Git子目录下git checkout old_branch *的工作原理解析
Git分支操作原理解析与流程优化建议
涉及的原始操作片段如下:
# 当前工作目录为 /home/ab/ git checkout -f $RELEASE_BRANCH git branch $NEW_REPAIR_BRANCH git checkout $NEW_REPAIR_BRANCH cd /home/ab/cd/ef/ rm -r * git checkout $OLD_REPAIR_BRANCH *
核心问题底层逻辑
为什么执行
git branch new_branch会复制当前release_branch的内容?
Git的分支本质就是个存了40位提交SHA值的指针,根本没有全量拷贝文件的过程。不带任何额外参数执行git branch <新分支名>时,Git默认会让新分支的指针直接指向当前HEAD锚定的提交,也就是你当前所在release_branch的最新提交。新分支和当前分支指向同一个提交快照,初始工作区状态自然和当前分支完全一致,看起来就像复制了当前分支的内容。切换到新创建的分支后,为什么进入指定子目录,通过检出旧分支就能引入旧版本脚本?
git checkout本身有两种完全独立的工作模式:只传分支名的时候是分支切换模式,会改HEAD指向、更新整个工作区到对应分支状态;只要命令里带了路径参数,就会切到文件检出模式,完全不碰分支指向,只从你指定的分支/提交里把对应路径的文件提出来,覆盖当前工作区的同名文件。你cd到目标子目录后,命令里的*会被Shell先展开成当前子目录下的所有文件路径传给Git,Git自然就会去旧分支里把对应路径的旧版本脚本拉到当前目录。为什么最后一行checkout旧分支的命令只恢复当前子目录文件,既不拉全量脚本,也不切换到旧分支?
就是因为这行命令带了路径参数,触发的是上面说的文件检出模式:- 这个模式下Git不会修改HEAD指针,所以绝对不会切换到
$OLD_REPAIR_BRANCH - 你传的路径范围只有当前子目录下的文件,Git只会处理仓库里和这些路径匹配的内容,其他目录的文件碰都不会碰,自然不会拉取全量脚本
顺便说,这里先执行rm -r *清空目录完全是多余的,文件检出模式本身就会把目标路径的内容替换成指定分支里的版本,包括删掉那些在旧分支对应路径下不存在的文件。
- 这个模式下Git不会修改HEAD指针,所以绝对不会切换到
流程优化建议
原流程有不少冗余步骤,还存在误删文件的风险,可以做如下简化:
- 合并分支创建和切换步骤:不需要先切到release分支、建分支、再切新分支三步走,直接用
git checkout -b $NEW_REPAIR_BRANCH $RELEASE_BRANCH就能一步完成,作用是基于$RELEASE_BRANCH的最新提交创建新分支,并且直接切换过去。 - 去掉冗余的切目录、删文件操作:不需要cd到子目录,也不需要手动rm清空内容,直接在checkout里写明确的目标路径就行,记得加
--分隔分支名和路径,避免出现路径和分支重名时Git解析出错,对应步骤直接写git checkout $OLD_REPAIR_BRANCH -- cd/ef/就够了,路径写仓库根目录下的相对路径即可,不用写系统绝对路径。 - 非必要不要加
-f强制参数:git checkout -f会直接丢弃工作区所有未提交的改动,没有任何确认提示,很容易误删本地没保存的修改,如果不需要强制清空本地改动,直接去掉-f参数。
优化后的完整流程精简后只有两行:
# 在仓库根目录执行即可 git checkout -b $NEW_REPAIR_BRANCH $RELEASE_BRANCH git checkout $OLD_REPAIR_BRANCH -- cd/ef/
内容的提问来源于stack exchange,提问作者GuoLY96
相关产品推荐
相关产品推荐

