[博客翻译]你应该使用的现代Git命令和功能


原文地址:https://martinheinz.dev/blog/109


Martin,2024年3月4日,git

我们这些软件工程师每天都在使用 git,然而大多数人只是使用最基本的命令,比如 add、commit、push 或 pull,好像还停留在 2005 年。但是,Git 自那时起引入了许多特性,使用它们可以让你的生活变得更加轻松,所以让我们来探索一些你应该知道的近期添加的现代 Git 命令。

3.png

切换分支

自 2019 年起,或者更准确地说,在 Git 2.23 版本中引入了 git switch 命令,我们可以使用它来切换分支:

git switch other-branch 

git switch -  # 切换回之前的分支,类似于 "cd -" 

git switch remote-branch  # 直接切换到远程分支并开始跟踪

这很酷,但我们使用 git checkout 命令在 Git 中切换分支已经很久了,为什么需要一个单独的命令呢?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,仅匹配仓库根部的文件。因此,运行 checkout 后,我们只有 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/  # Clean worktree, where you can make your changes and push them

此命令允许我们同时签出同一存储库的多个分支。在上面的例子中,我们有两个分支dev和master。假设我们正在开发分支中的功能,但我们被告知要进行紧急的bug修复。我们在中创建了一个新的工作树,而不是隐藏更改并重置分支/master分支的hotfix子目录。然后我们可以移动到那个目录,进行更改,推送它们并返回到原始工作树。

平分

最后但同样重要的是,git平分,这并不是什么新鲜事(git 1.7.14,2012年5月13日发布),但大多数人只使用2005年左右的git功能,所以我认为无论如何都值得展示。
正如文档页面所描述的:git平分-使用二进制搜索来查找引入错误的提交:

git bisect start
git bisect bad HEAD  # Provide the broken commit
git bisect good 479420e  # Provide a commit, that you know works
# Bisecting: 2 revisions left to test after this (roughly 1 step)
# [3258487215718444a6148439fa8476e8e7bd49c8] Refactoring.

# Test the current commit...
git bisect bad  # If the commit doesn't work
git bisect good # If the commit works

# Git bisects left or right half of range based on the last command
# Continue testing until you find the culprit

git bisect reset  # Reset to original commit

首先,我们使用git平分start显式启动平分会话,然后我们提供不起作用的提交(很可能是HEAD)和最后一个已知的正在工作的提交或标记。有了这些信息,git将在“坏”和“好”提交之间检查出一个提交。在这一点上,我们需要测试该版本是否存在错误,然后使用git平分good来告诉git它有效,或者使用git等分bad来告诉它无效。我们不断重复这个过程,直到没有提交为止,git会告诉我们哪个提交是导致问题的提交。
我建议查看docs页面,该页面显示了git平分的更多选项,包括可视化、回放或跳过提交。

结论

若你们搜索一些和git有关的问题,你们很可能会在StackOverflow问题上得到几千张赞成票。虽然这个答案很可能仍然有效,但它很可能已经过时了,因为它是10年前写的。因此,可能有一种更好、更简单、更容易的方法来做到这一点。因此,当遇到一些git问题时,我建议查看git文档中的最新命令,所有这些命令都有很多很好的例子,或者浏览手册页中的许多标志和选项,这些标志和选项是多年来添加到好的旧命令中的。