我们每天都在用git
,但大多数人只用到最基础的操作,比如add
、commit
、push
或pull
,仿佛我们还停留在2005年。
然而,Git自那时起已经引入了许多新特性,使用这些特性能让你的工作更加轻松。让我们来看看一些最近新增的现代git
命令,你应当了解一下。
Switch
从2019年开始,确切地说,是在Git 2.23版本中引入了git switch
,我们可以用它来切换分支:
复制
git switch other-branch
git switch - # 切换回上一个分支,类似于 "cd -"
git switch remote-branch # 直接切换到远程分支并开始跟踪它
这确实很酷,但自从Git出现以来,我们一直在用git checkout
来切换分支,为什么还需要一个新的命令呢?git checkout
是一个非常强大的命令——它不仅可以检出或恢复特定的文件,甚至可以检出到特定的提交,而新的git switch
仅仅用于切换分支。另外,switch
还进行了一些checkout
不做的额外检查,比如,如果切换会导致本地更改丢失,switch
会终止操作。
恢复
Git在2.23版本中新增了另一个子命令/特性:git restore
,我们可以用它将文件恢复到上次提交的版本:
复制
# 取消对文件的更改的暂存,与 "git reset some-file.py" 相同
git restore --staged some-file.py
# 取消暂存并丢弃对文件的更改,与 "git checkout some-file.py" 相同
git restore --staged --worktree some-file.py
# 将文件恢复到之前的某个提交,与 "git reset commit -- some-file.py" 相同
git restore --source HEAD~2 some-file.py
上述代码片段中的注释说明了各种git restore
命令的工作方式。总的来说,git restore
替换并简化了一些git reset
和git checkout
的用例,这两个命令已经是功能繁多的命令。关于revert
、restore
和reset
的对比,还可以查看这个文档部分。
稀疏检出
接下来是git sparse-checkout
,这是Git在2.25版本中添加的一个较为隐晦的特性,该版本于2020年1月13日发布。
想象一下,如果你有一个大型单体仓库,微服务被分散到不同的目录中,由于仓库体积庞大,checkout
或status
这样的命令执行得非常缓慢,但或许你只需要处理单个子目录。这时,git sparse-checkout
就能发挥作用了:
复制
$git clone --no-checkout https://github.com/derrickstolee/sparse-checkout-example$ cd sparse-checkout-example
$git sparse-checkout init --cone # 配置git只匹配根目录中的文件$ git checkout main # 只检出根目录中的文件
$ ls
bootstrap.sh LICENSE.md README.md
$ git sparse-checkout set service/common
$ ls
bootstrap.sh LICENSE.md README.md service
$ tree .
.
├── bootstrap.sh
├── LICENSE.md
├── README.md
└── service
├── common
│ ├── app.js
│ ├── Dockerfile
... ...
在上面的例子中,我们首先克隆了仓库,但实际上并没有检出所有文件。然后我们使用git sparse-checkout init --cone
来配置git
只匹配仓库根目录中的文件。所以,在运行检出之后,我们只有3个文件,而不是整个树。然后,为了下载/检出特定的目录,我们使用git sparse-checkout set ...
。
如前所述,这在本地处理大型仓库时非常有用,但在CI/CD中同样有用,可以提高管道的性能,当你只想构建/部署单体仓库的一部分,而且没有必要检出所有内容。
关于sparse-checkout
的详细说明,请参阅这篇文章。
工作树
在单个应用程序(仓库)中同时处理多个功能,或者在处理某个功能请求时突然出现一个紧急错误,这种情况很常见。
在这种情况下,你需要要么克隆仓库的多个版本/分支,要么暂存/丢弃你当时正在处理的内容。针对这种情况,git worktree
是一个解决方案,它于2018年9月24日发布:
复制
git branch
# * dev
# master
git worktree list
# /.../some-repo ews5ger [dev]
git worktree add -b hotfix ./hotfix master
# Preparing worktree (new branch 'hotfix')
# HEAD is now at 5ea9faa Signed commit.
git worktree list
# /.../test-repo ews5ger [dev]
# /.../test-repo/hotfix 5ea9faa [hotfix]
cd hotfix/ # 清爽的工作树,你可以在这里进行更改并推送它们
这个命令允许我们同时检出同一仓库的多个分支。在上面的例子中,我们有两个分支dev
和master
。假设我们正在dev
分支上处理一个功能,但我们被告知需要紧急修复一个错误。我们不是暂存更改并重置分支,而是在./hotfix
子目录中从master
分支创建一个新的工作树。然后我们可以切换到那个目录,进行更改,推送它们,然后返回到原始的工作树。
更详细的说明请参阅这篇文章。
二分查找
最后要介绍的是git bisect
,这个功能虽然不是最新的(Git 1.7.14,发布于2012年5月13日),但由于大多数人只使用2005年左右的git
功能,所以我认为它仍然值得推荐。
根据文档页面的描述:<i>git-bisect</i>
- 使用二分查找法找到引入错误的提交:
复制
git bisect start
git bisect bad HEAD # 提供一个出错的提交
git bisect good 479420e # 提供一个你知道可以正常工作的提交
# Bisecting: 2 revisions left to test after this (roughly 1 step)
# [3258487215718444a6148439fa8476e8e7bd49c8] Refactoring.
# 测试当前的提交...
git bisect bad # 如果提交有问题
git bisect good # 如果提交没有问题
# Git根据最后一个命令在范围的左半部分或右半部分进行二分查找
# 继续测试直到找到罪魁祸首
git bisect reset # 重置到原始提交
我们首先使用git bisect start
明确开始二分查找会话,然后提供不能正常工作的提交(很可能是HEAD
)和最后一个已知可以正常工作的提交或标签。有了这些信息后,git
将检出位于“坏" 和 "好”提交之间的一个提交。此时我们需要测试该版本是否有错误,然后使用git bisect good
告诉git
它没有问题,或者使用git bisect bad
告诉git
它有问题。我们不断重复这个过程,直到没有提交剩下,git
会告诉我们哪个提交引入了问题。
我建议查看文档页面,它展示了git bisect
的几个更多选项,包括可视化、重放或跳过提交。