正如其他人所说,不接触工作目录就不可能重新设置分支(即使是建议的替代方案,例如创建新的克隆或工作树也无法改变这一事实;这些替代方案确实不会触及您当前的工作目录,但只能通过创建一个新的工作树)。
对于要更新的分支基于当前工作树(或其父级)的特殊情况,可以“重新设置”另一个分支而无需不必要地接触文件。
如果您有一个 git 工作流程,其中您正在处理所有从主“主”分支(定期更新到远程主分支)分支的许多分支,这种特殊情况通常会发生。
为了说明,假设 Git 存储库具有以下结构:
repo
- commitA
- commitB
- commitC <-- master <-- OtherBranch based on master
- commitD <-- First commit in otherBranch
- commitE <-- Second commit in OtherBranch
- commitD <-- Unrelated commit in current working tree
为了示例,假设“OtherBranch”从“master”分支出来,并且您当前的工作树也基于“master”。
您的工作流程通常从使用远程版本更新本地主分支开始...
# Fetch commits from remote "origin" and update the master branch:
# If your current branch is identical to master
git pull origin master
# If your current branch has extra commits on top of master
git pull --rebase origin master
# If you don't want to touch your current branch
git fetch origin master:master
... 然后你摆弄当前分支并进行一些耗时的编译。最终,您决定要在 OtherBranch 上工作。这个OtherBranch 应该基于master(最好使用最少的文件系统操作)。以下部分将展示如何。
重新定位其他分支(参考示例 - 不要这样做)
下面的解决方案是git的做法:
git checkout OtherBranch
git rebase master # or git rebase origin/master
这样做的缺点是第一个命令会更改当前工作树的日期,即使文件将由第二个命令恢复。
以最小的更改重新定位其他分支
为了尽量减少接触文件的数量,您需要签出新的基础分支,然后使用 git cherry-pick 在基础分支之上应用 OtherBranch 中的所有额外提交。
在做任何事情之前,您需要识别OtherBranch 中的提交。
-
git log OtherBranch 显示在 OtherBranch 上的提交(主要在您尚未更改 OtherBranch 时有用)
-
git reflog 显示对本地存储库中分支的更改(如果您已经更新了分支并犯了错误,这很有用)。
在当前示例中,您会发现OtherBranch 上的最后一次提交是commitE。您可以使用git log commitE(或者如果您想要更短的列表,git log --oneline commitE)查看之前的提交列表。如果查看列表,您将看到基本提交是 commitC。
现在您知道基础提交是commitC,最后一次提交是commitE,您可以将OtherBranch(从其以前的“master”到新的“master”)rebase 如下:
# Replace the old OtherBranch with "master" and switch to it.
git checkout -B OtherBranch master
# Cherry-pick commits starting from commitC and ending at commitE.
cherry-pick commitC^..commitE
或者(如果你想在替换OtherBranch之前成功完成“rebase”):
# Create new branch NewOtherBranch based off "master" and switch to it.
git checkout -b NewOtherBranch master
# Cherry-pick commits starting from commitC and ending at commitE.
cherry-pick commitC^..commitE
# Replace the old branch with the current branch (-M = --move --force)
git branch -M OtherBranch
为什么会这样?
在 git 中变基分支需要将当前分支切换到要更新的分支 (OtherBranch)。
使用git rebase 工作流,会发生以下情况:
- 切换到
OtherBranch(可能从一个非常古老的基础分支分支出来)。
- 变基(内部步骤 1):保存不在上游分支中的提交。
- 变基(内部步骤 2):将当前分支重置为(新)基分支。
- 变基(内部步骤 3):从步骤 2 恢复提交。
第 1 步和第 3 步涉及很多文件,但最终很多涉及的文件实际上并没有改变。
我的方法将第 1 步和第 3 步合并到第 3 步中,因此触摸文件的数量最少。唯一被触及的文件是:
- 在当前工作树中的基础分支和当前提交之间更改的文件。
-
OtherBranch 中的提交更改的文件。