你应该使用的现代Git命令和特性

Medium 2024年08月12日 编辑

1-tifivznjzarj7ws1cgippw-66b9d1ef3c5bc.webp

我们每天都在用git,但大多数人只用到最基础的操作,比如addcommitpushpull,仿佛我们还停留在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 resetgit checkout的用例,这两个命令已经是功能繁多的命令。关于revertrestorereset的对比,还可以查看这个文档部分

稀疏检出

接下来是git sparse-checkout,这是Git在2.25版本中添加的一个较为隐晦的特性,该版本于2020年1月13日发布。

想象一下,如果你有一个大型单体仓库,微服务被分散到不同的目录中,由于仓库体积庞大,checkoutstatus这样的命令执行得非常缓慢,但或许你只需要处理单个子目录。这时,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/  # 清爽的工作树,你可以在这里进行更改并推送它们

这个命令允许我们同时检出同一仓库的多个分支。在上面的例子中,我们有两个分支devmaster。假设我们正在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的几个更多选项,包括可视化、重放或跳过提交。

猜你喜欢