你应该了解和使用的现代 Git 命令和功能
现在已经不是 2005 年了, git
提供的不仅仅是add
, commit
, push
和pull
. 让我们来探讨一下你应该知道的所有新的, 现代化的 git
命令吧.
我们所有的软件工程师每天都在使用git
, 但大多数人只接触过add
, commit
, push
或pull
等最基本的命令, 就像还在2005年一样.
然而, Git 从那时起引入了许多功能, 使用这些功能可以让你的生活变得更轻松, 所以让我们来探索一些最近添加的现代 git
命令, 你应该了解它们.
switch
从 2019 年开始, 或者更准确地说, 从 Git 2.23 版本开始, 我们可以使用 git switch
来切换分支:
php
git switch other-branch
git switch - # Switch back to previous branch, similar to "cd -"
git switch remote-branch # Directly switch to remote branch and start tracking it
这很酷, 但我们从一开始就用 git checkout
在 Git 中切换分支了, 为什么还需要一个单独的命令呢? git checkout
是一个非常通用的命令--它可以(除其他外)检出或恢复特定文件, 甚至特定提交, 而新的 git switch
只 切换分支. 此外, switch
还会执行一些checkout
不执行的额外的合理性检查, 例如, 如果switch会导致本地改动丢失, 那么它就会中止操作.
restore
Git 2.23 版新增的另一个子命令/功能是 git restore
, 我们可以用它把文件恢复到上次提交的版本:
css
# Unstage changes made to a file, same as "git reset some-file.py"
git restore --staged some-file.py
# Unstage and discard changes made to a file, same as "git checkout some-file.py"
git restore --staged --worktree some-file.py
# Revert a file to some previous commit, same as "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
的比较, 请参阅 本文档部分.
sparse-checkout
Next one is git sparse-checkout
, a little more obscure feature that was added in Git 2.25, which was released on January 13, 2020.
下一个是 git sparse-checkout
, 这是 2020 年 1 月 13 日发布的 Git 2.25 中新增的一个不起眼的功能.
比方说, 你有一个大型的单仓库(monorepo), 其中的微服务被分隔到各个目录中, 由于版本库太大, checkout
或status
之类的命令执行起来非常慢, 但也许你真的只需要处理单个子树/目录. 那么, git sparse-checkout
来拯救你了:
shell
$ git clone --no-checkout https://github.com/derrickstolee/sparse-checkout-example
$ cd sparse-checkout-example
$ git sparse-checkout init --cone # Configure git to only match files in root directory
$ git checkout main # Checkout only files in root directory
$ 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 中, 当你只想构建/部署 monorepo 的一部分, 而不需要检出所有文件时, 这对提高流水线性能同样有用.
有关sparse-checkout
的详细介绍, 请参阅这里.
worktree
一个人可能需要同时在单个应用(仓库)中处理多个功能, 或者当你正在处理某个功能请求时出现了一个重要的 bug, 这种情况并不少见.
在这种情况下, 要么你必须克隆多个版本/分支的版本库, 要么你需要隐藏/丢弃你当时正在处理的内容. 2018 年 9 月 24 日发布的 git worktree
就是解决这些情况的办法:
bash
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
该命令允许我们同时签出同一版本库的多个分支. 在上面的例子中, 我们有 2 个分支dev
和master
. 假设我们正在dev
分支中开发功能, 但有人告诉我们要进行紧急 bug 修复. 与其将更改存储起来并重置分支, 不如在 master
分支的 ./hotfix
子目录下创建一个新的Worktree. 然后, 我们就可以移动到该目录, 进行修改, 推送并返回原始Worktree.
更详细的介绍请参阅本文.
bisect
最后但并非最不重要的是git bisect
, 它并不新鲜(Git 1.7.14, 2012 年 5 月 13 日发布), 但大多数人只使用 2005 年左右的git
功能, 所以我觉得还是值得展示一下.
正如文档页所描述的那样: git-bisect
- 使用二进制搜索查找引入错误的提交:
ini
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 bisect start
明确启动分段会话, 然后提供不生效的提交(很可能是HEAD
)和最后一次已知的工作提交或标记. 有了这些信息, git
就会检查出介于 "bad" 和 "good" 提交之间的一个提交. 这时, 我们需要测试该版本是否有 bug, 然后使用git bisect good
来告诉git
该版本有效, 或使用git bisect bad
来告诉 git
该版本无效. 我们不断重复这个过程, 直到没有提交了, git
就会告诉我们哪个提交引入了问题.
我推荐你去看看文档那里还有更多关于git bisect
的选项, 包括可视化, 重放或跳过提交.
总结一下
如果你搜索一些与 git
相关的问题, 你很可能会在 StackOverflow 上找到有几千个向上投票的答案的问题. 虽然这个答案很可能仍然有效, 但很可能已经过时, 因为它是 10 年前写的. 因此, 可能还有更好, 更简单, 更容易的方法. 所以, 当遇到一些git
问题时, 我建议查看git文档, 了解更多最新的命令, 这些命令都有很多很好的示例, 或者浏览man
页面, 了解多年来添加到老命令中的很多标志和选项.