baixiaoji/blog

高阶 GIT 101 - 分支管理

Opened this issue · 0 comments

文档目的: 1. 让读者了解并存分支切换方式 2. 优化分支排列方式

日常小剧场:RD 开发 A 需求,产品和Server找过来说需要协助排查线上异常,排查不一会发现就是涉及 A 需求代码逻辑异常,需要紧急修复然后验证无误上线。这时候你该怎么处理目前工作现场(workspace)?

Stash

git stash 可以将本次修改内容(涉及跟踪数据)存储到 stash 中,stash 是一个存储临时修改的堆栈。
上述场景,工作流会变成:

  1. 直接使用 git stash 命令完成工作区暂存
  2. 然后切分支 => 改问题 => 发环境 => 验无误之后开始正常上线。

这时候回到开发 A 需求分支,通过 git stash list 查看 stash 堆栈信息,如果有良好工作习惯(每次使用 stash 完清空本次),就会发现堆栈中有一条记录,否则往期历史记录都还在堆栈中对你说好久不见。

这种场景你会迷糊应该用那条记录,因为所有直接提交复用是就近 commit message,如果记性好可以快速识别出来,那记性不好呢?
这时候你会说那不应该是第一条吗?因为 stash 是堆栈结构,第一条就是上次推入。

这个理解没啥问题,主要是观点无法验真。因为做需求过程中,修改好这个紧急问题,可能会有下一个而且还有可能你会忘记回去做A需求,会有B C D 需求,一旦小剧场现象串成了环,stash 中位置就不可靠了,甚至会出现两个记录 commit message 一致的情况。所以回到流程 1 中,这时候存储需要添加一些方便你回忆的标记位,像提交commit 那样。

git stash -m "<your message>"

继续回到修复完成场景,这时候查看堆栈信息就比较容易了,通过 git stash list 查看上次提交所属堆栈的位置,然后使用

# ❌
git stash apply --index <index>
# ✅
git stash pop --index <index>

Commit

git stash 需要培养良好维护习惯,但这个也太烦了,需要有好习惯好记性才行,还有没有简单方式呀,还记得上文最后说到存 stash 类似 commit 就行,那为什么不直接存 commit 呢?
Of course, yes!
既然 git stash 操作存在较多的记忆、习惯等限制,那就直接将修改提交成一条临时commit呗~

git commit -nm 'temp message'

等问题结束,然后提交从暂存区转移到工作区,后续正常工作就好了。

git reset HEAD~

空间换时间

这时候你还是会有疑问,还是太麻烦了。有没有可以保留当前工作现场,又可以切换到新分支的情况。
当然有了,重新开一个目录重新拉取仓库,这时候clone命令并不需要全量历史记录,浅克隆减少等待时长

git clone --depth 1 <repository>

# 极端浅克隆,默认 branch 通常 master / main
git clone --single-branch --depth 1 <repository>

后续排查到问题原因,想排查问题引入时机,需要将浅克隆升级为深克隆,使用git fetch --unshallow 即可。
当前方式拿大量空间换取排查和养成习惯时间,受限于磁盘空闲上限。或许会觉得空间不值钱,小小空间轻松拿下。意识到这点时候,或许还没见过 monorepo 可怕。
即便是极致浅克隆场景原本 1.6G 远程仓库还是 400MB,后续添加安装依赖和转化深克隆,轻轻松松膨胀到 10+G 不在话下。
或许会说这玩意每次删掉就好,更方便!
是滴,没有一点毛病。如果幸运的话~
所以这样空间换时间方式你还能接收吗?

Worktree

[[高阶 Git 101 - 概念篇]] 中了解到所有记录都存储在 .git/objects 当中,也是克隆耗时最长阶段(复制远程仓库数据)。既然已有所有对象,有没有什么手段新建一个目录让其共享同一个 .git 信息做到快速克隆出一个仓库呢?
有的!真是个小机灵鬼~
git worktree 是一个在 Git 2.5 版本中引入的功能,它允许在一个仓库中同时进行多份工作树的检出,使得能同时在多个分支进行工作成为可能。
使用场景:

  1. 并行工作 on 多个分支:当你在一个分支上工作,但突然需要切换到其他分支进行一些工作(如 bug 修复)时,你可能不想立即提交你当前的工作进度。此时,你可以使用 git worktree 创建一个新的工作树来处理新的任务,而无需离开你的当前工作标头。
  2. 同时进行长时间运行的操作:有时,一个长期运行的操作(如测试或编译)需要在一个分支上进行,而你想要在不同的分支并行进行其他的工作。在这种情况下,git worktree 可以帮助你创建一个新的工作环境。
    使用场景完美契合了我们的诉求,创建出来 worktree 不占用任何空间,共享 .git 所有历史记录,并做到工作区完美隔离。但依旧存在缺点,依赖包无法共享,用户需要单独安装依赖,若仓库安装依赖过重,会有体验不好情况;若都是用 pnpm 进行管理,对应缓存+软硬链安装依赖方式,体验良好,占空间只有部分依赖体积(预计 400 MB)。
    明细命令:
git worktree add <target_dir_worktree_path>

列出所有工作树:

git worktree list

删除一个工作树:

git worktree remove <target_dir_worktree_path>

检查出一个新的分支到工作树:

git worktree add -b new-branch <target_dir_worktree_path> origin/base-branch

在这些命令中,<target_dir_worktree_path> 是新的工作树的路径,new-branch 是新工作树的分支名称,origin/base-branch 是新分支要基于的远程分支。
完成创建之后,cd <target_dir_worktree_path> 即可在新分支进行排查和开发,更多 worktree 使用小技巧请结合 man 命令查看。

参考资料

git stash - 《阮一峰 Git 教程》 - 书栈网 · BookStack
git神器-git stash使用详解 - 个人文章 - SegmentFault 思否
如何恢复丢弃的 git stash 数据 - 知乎
Git - git-stash Documentation
https://git-scm.com/docs/git-worktree
Mastering Git Worktree: A Comprehensive Guide