复杂合并的临时提交
temporary commit on complex merge
我有两个分支,master
是主分支,feature_branch_1
是很老的分支,很多提交落后于 master。我需要将 feature_branch_1
合并到 master 中,所以我做了:
git pull --rebase origin master
正如预期的那样,有很多冲突,不久之后需要在新 feature_branch_2
上开发另一个功能,这与 master 的 HEAD
背道而驰,绝对需要继续努力feature_branch_1
之前。或多或少处于复杂合并的中间,我如何在 feature_branch_1
上进行临时提交,以便稍后再回来处理。我知道我可以做一个:
git add <things-that-are-done>
git commit -m 'intermediary commit between merges'
... come back to it later
git checkout 'that-temp-commit-hash'
... after finishing
git add .
git commit -m 'done with feature_branch_1'
git rebase --interactive HEAD~1
进行临时提交然后变基以在之后压缩它。
这是处理此问题的最佳方法吗?
Git 不会让您使用包含未合并条目的索引进行提交。
使用 git add
将解决未合并的条目,以便您可以提交,但由于多种原因,这种方法可能不能令人满意。无需赘述:
- 未解析的路径通过使用索引槽 1-3 而不是槽 0 来表示。它们包含文件的 merge-base 版本,"sides"(
--ours
和--theirs
,虽然在合并过程中角色有点交换)。
git add
从 work-tree 复制到 slot 0,破坏 slot 1-3,因此文件现在已解析(即使 work-tree 文件仍然充满冲突标记)。
- 一个 "undo" (
REUC
) 条目也在此时记录在索引中,这样你就可以 git checkout -m
到 re-create 冲突的路径 (擦除插槽 0 条目并恢复 1-3 条目)。
- 实际上提交合并结果永久失去撤消状态。
这意味着如果你做提交部分合并,然后想返回并想完成它,一些信息——特别是未合并的状态,即使它被移动到一个撤消条目——丢失了。稍后,您最接近找出仍需要正确合并哪些文件的方法是搜索冲突标记。 (如果你觉得没问题的话,这个方法可能还是比较满意的。)
除此之外,rebase 会复制 多个提交 ,并且您没有提到在最后一次提交时是否发生了这种特定的合并冲突。在继续其他操作之前,您需要完成或中止变基。 (技术上可以在变基过程中做一些事情,但这很棘手。)
关于这部分:
... come back to it later
git checkout 'that-temp-commit-hash'
... after finishing
git add .
git commit -m 'done with feature_branch_1'
git rebase --interactive HEAD~1
因为这个特定的 unmerged-state(您故意快速解决 "wrong" 以便做其他事情并稍后回来)是变基而不是合并的结果,该序列可以工作。不过,将最后两个步骤替换为 git commit --amend
会更简单,也更普遍适用。 --amend
选项告诉 git commit
使用当前提交的 parent(s) 而不是当前提交本身来进行新提交。这适用于正常(single-parent、non-merge)提交和实际合并(两个或更多 parents)。
备选方案
你最好的选择可能是不理会这个 work-tree 并制作另一个你处理其他问题的地方。
最简单的方法,始终适用于 Git 的每个版本,就是制作另一个克隆。
您可以通过克隆 in-progress 变基来制作额外的克隆。在具有硬链接的合理系统上,如果您使用本地路径(例如 git clone work/repo work/new-clone-for-fast-fix
,从您工作的地方向上一级)将您的存储库克隆到同一文件系统上的另一个存储库,Git 将使用底层包的硬链接和 objects,因此您只需要 work-tree space.
如果您的 Git 相对较新(我推荐至少 Git 2.6,尽管该功能在 2.5 中就有),您可以使用 git worktree add
创建一个新的 "linked work-tree".链接的 work-tree 会记住其原始存储库(反之亦然),但也有一个私有索引 / staging-area。你可以把它放在你想要的任何分支上,在那里做任何你喜欢的事情,包括创建其他分支或做其他变基,所有这些都不会影响你的 "main" work-tree 和 "main" 索引。
我有两个分支,master
是主分支,feature_branch_1
是很老的分支,很多提交落后于 master。我需要将 feature_branch_1
合并到 master 中,所以我做了:
git pull --rebase origin master
正如预期的那样,有很多冲突,不久之后需要在新 feature_branch_2
上开发另一个功能,这与 master 的 HEAD
背道而驰,绝对需要继续努力feature_branch_1
之前。或多或少处于复杂合并的中间,我如何在 feature_branch_1
上进行临时提交,以便稍后再回来处理。我知道我可以做一个:
git add <things-that-are-done>
git commit -m 'intermediary commit between merges'
... come back to it later
git checkout 'that-temp-commit-hash'
... after finishing
git add .
git commit -m 'done with feature_branch_1'
git rebase --interactive HEAD~1
进行临时提交然后变基以在之后压缩它。
这是处理此问题的最佳方法吗?
Git 不会让您使用包含未合并条目的索引进行提交。
使用 git add
将解决未合并的条目,以便您可以提交,但由于多种原因,这种方法可能不能令人满意。无需赘述:
- 未解析的路径通过使用索引槽 1-3 而不是槽 0 来表示。它们包含文件的 merge-base 版本,"sides"(
--ours
和--theirs
,虽然在合并过程中角色有点交换)。 git add
从 work-tree 复制到 slot 0,破坏 slot 1-3,因此文件现在已解析(即使 work-tree 文件仍然充满冲突标记)。- 一个 "undo" (
REUC
) 条目也在此时记录在索引中,这样你就可以git checkout -m
到 re-create 冲突的路径 (擦除插槽 0 条目并恢复 1-3 条目)。 - 实际上提交合并结果永久失去撤消状态。
这意味着如果你做提交部分合并,然后想返回并想完成它,一些信息——特别是未合并的状态,即使它被移动到一个撤消条目——丢失了。稍后,您最接近找出仍需要正确合并哪些文件的方法是搜索冲突标记。 (如果你觉得没问题的话,这个方法可能还是比较满意的。)
除此之外,rebase 会复制 多个提交 ,并且您没有提到在最后一次提交时是否发生了这种特定的合并冲突。在继续其他操作之前,您需要完成或中止变基。 (技术上可以在变基过程中做一些事情,但这很棘手。)
关于这部分:
... come back to it later git checkout 'that-temp-commit-hash' ... after finishing git add . git commit -m 'done with feature_branch_1' git rebase --interactive HEAD~1
因为这个特定的 unmerged-state(您故意快速解决 "wrong" 以便做其他事情并稍后回来)是变基而不是合并的结果,该序列可以工作。不过,将最后两个步骤替换为 git commit --amend
会更简单,也更普遍适用。 --amend
选项告诉 git commit
使用当前提交的 parent(s) 而不是当前提交本身来进行新提交。这适用于正常(single-parent、non-merge)提交和实际合并(两个或更多 parents)。
备选方案
你最好的选择可能是不理会这个 work-tree 并制作另一个你处理其他问题的地方。
最简单的方法,始终适用于 Git 的每个版本,就是制作另一个克隆。
您可以通过克隆 in-progress 变基来制作额外的克隆。在具有硬链接的合理系统上,如果您使用本地路径(例如 git clone work/repo work/new-clone-for-fast-fix
,从您工作的地方向上一级)将您的存储库克隆到同一文件系统上的另一个存储库,Git 将使用底层包的硬链接和 objects,因此您只需要 work-tree space.
如果您的 Git 相对较新(我推荐至少 Git 2.6,尽管该功能在 2.5 中就有),您可以使用 git worktree add
创建一个新的 "linked work-tree".链接的 work-tree 会记住其原始存储库(反之亦然),但也有一个私有索引 / staging-area。你可以把它放在你想要的任何分支上,在那里做任何你喜欢的事情,包括创建其他分支或做其他变基,所有这些都不会影响你的 "main" work-tree 和 "main" 索引。