1200px-Git-logo.svg.png

令我惊讶的是,最近发现高级命令列表中新增了2个高级命令:git restore 和 git switch

当我看到一个 push 标志时,我首先会使用 pull 来消除冲突 – 神秘的匿名者

对于那些工作使用过 Git 一段时间的人,并不能经常发现它的新东西,如果你排除了管道命令行,这可能是我们大多数人不记得的最好做法。给我惊喜的是,我最近发现在高级命令列表中新增了两个新命令。

  • git restore
  • git switch

不理解它们为什么存在,先让我们拜访下我们的老朋友 git checkout

git-checkout.jpeg

Checkout 命令

Git checkout 让新手感到困惑的众多原因之一,是因为他的作用取决于上下文环境。大多数人用它是在本地仓库切换活跃的分支。更确切的说,是切换 HEAD 指向的分支。例如,如果你在 main 分支,你能切换到 develop 分支。

1
git checkout develop

你也可以让 HEAD 头指向到一个特定的提交ID,而不是一个分支(达到所谓的分离 HEAD 状态):

1
git checkout f8c540805b7e16753c65619ca3d7514178353f39

事情变的棘手的是,如果你提供一个文件作为参数而不是一个分支或提交ID,它将丢弃你对该文件的本地更改,并还原到修改前状态。例如,如果你切换到 develop 分支并对 test.txt 文件做了一些修改,然后你可以恢复这个文件到未修改前,也就是到这个分支的最后一次提交。

git checkout -- test.txt,以下这个命令操作演示(熟悉的童鞋可跳过):

1.develop 分支 test.txt 文件状态和内容

1
2
3
4
5
➜ git:(develop) git status
On branch develop
nothing to commit, working tree clean
➜ git:(develop) cat test.txt
test.txt file on develop

2.修改 test.txt 文件内容,并查看当前文件状态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
➜ git:(develop) ✗ git status
On branch develop
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   test.txt

no changes added to commit (use "git add" and/or "git commit -a")
➜ git:(develop) ✗ cat test.txt
test.txt file on develop
test.txt file on develop
➜ git:(develop)

3.执行恢复命令,并查看恢复后文件状态

1
2
3
4
5
6
7
➜ git:(develop) ✗ git checkout -- test.txt
➜ git:(develop) git status
On branch develop
nothing to commit, working tree clean
➜ git:(develop) cat test.txt
test.txt file on develop
➜ git:(develop)

一种疯狂的做法

如果你第一次知道这个命令有这两种行为,可能认为那是说不通的,为什么一个命令会做两个不同的操作?其实事情要更微妙一些。如果我们看 Git 官方文档,我们会发现这个命令有一个额外的参数,这个参数通常被省略。

1
git checkout <tree-ish> -- <pathspec>

<tree-ish> 是什么?它能理解为许多不同的事情,但是通常的它的意思是一个提交的哈希值(CommitID)或者分支名称。把当前分支看作默认值,但是它可以是任何分支或提交的哈希值。例如,如果你在 develop 分支,想要将 test.txt 文件更改为来自main分支的版本,你可以这么做:

1
git checkout main -- text.txt

命令操作演示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
➜ git:(main) git status
On branch main
nothing to commit, working tree clean
➜ git:(main) cat test.txt
test.txt file on main
test.txt file on main
➜ git:(main) git checkout develop
Switched to branch 'develop'
➜ git:(develop) cat test.txt
test.txt file on develop
➜ git:(develop) git checkout main -- test.txt
➜ git:(develop) ✗ cat test.txt
test.txt file on main
test.txt file on main

考虑到这一点,也许事情开始变的有意义。当你仅仅提供一个分支名或者CommitID作为 git checkout 参数时,然后它会把你所有的文件修改成相应版本的状态,但是如果你明确指定一个文件名,它仅仅更改这一个文件。

git-switch-restore.jpeg

新来的小孩

所以再阅读了前面段落的后,事情开始变的有意义,我们必须承认对于新手它仍然是令人困惑的,那是因为在 git 2.23 版本,两个新命令的引进替换掉了老的 git checkout(它仍然是可以用的,但是新版本 git 的人,最好开始使用新命令)。如你所料,他们基本上都实现了前面描述的两种行为,将 git Checkout 分成两部分。

Switch

当只一个分支名作为git checkout参数运行时,swtich 实现了 git checkout 的这个行为。所以你可以使用它在分支或提交之间切换。

1
git switch develop

当你使用 git checkout 时,你可以切换到一个提交ID并进入到分离 HEAD 状态,默认情况下 git switch 不允许那样做,你需要通过使用 -d 参数:

1
git switch -d f8c540805b7e16753c65619ca3d7514178353f39

git checkout 另一个不同之处在于,你可以使用 -b 参数在一个命令中创建并切换到新的分支:

git checkout -b new_branch

在新的命令 switch 中同样的做法是使用 -c 参数:

1
git switch -c new_branch

Restore

当一个文件作为 git checkout 参数运行时,你可以使用 restore,顾名思义,修订一个文件到指定版本(默认为当前分支)

1
git restore -- test.txt

结尾

这些方法仍处于试验阶段,他们既然存在,但无论如何,我都鼓励大家开始使用,因为他们在你的脑海中可能变的更有意义,而且它可能会让 git 新用户少一些困惑。

关于这两个命令的更多详情,可以在 git 的官方文档中找到:

译自原文:https://www.banterly.net/2021/07/31/new-in-git-switch-and-restore/