前
A1-----A2 (master, contains a:apple, b:banana, c:carrot)
\
\----B1 (second, contains a:apple, b:beets, d:dandelion)
变体 1:没有引用 master(非常丑陋)
git read-tree -m -u master
git commit -m 'B2: copy of A2'
git diff master
后:
A1-----A2 (master, contains a:apple, b:banana, c:carrot)
\
\----B1---B2 (second, contains a:apple, b:banana, c:carrot)
- 当前分支:第二个(ff)
git status
: 干净的
diff
状态为master
:干净
确认回退工作:
git reset --hard HEAD^
git clean -f
git branch -avv
再次显示之前的状态。
这个变体有什么作用?
git read-tree
将给定的其他提交(此处master
)读入 INDEX
- 作为选项
-u
,它会相应地更新工作树
- 然后像往常一样将其提交到 B1
- 但是,它不会添加对“合并”树的引用。
变体 2:显示对 master 的合并引用(首选!)
对不起,我没有找到正确的方法。这是一种解决方法:
第一:做一个虚拟合并
git merge -s ours -m 'B2 dummy' master
第二:修复合并到正确的数据
git read-tree -m -u master
git commit --amend -m 'B2: copy of A2'
第三:检查它是否真的匹配master
:
git diff master
后:
A1-------A2 (master, contains a:apple, b:banana, c:carrot)
\ \
\----B1---B2 (second, contains a:apple, b:banana, c:carrot)
- 当前分支:第二个(ff,合并,第一个父级:B1)
git status
: 干净的
diff
状态为master
:干净
确认回退工作:
git reset --hard HEAD^
git clean -f
git branch -avv
再次显示之前的状态,因为它应该。
这是如何运作的:
git read-tree -m -u master
重置合并信息,所以我们不能开始合并,读取树然后提交这个合并,很遗憾。
- 但是我们想使用 option
-u
,因为这对于更新工作树至关重要。但是-u
需要-m
或类似的东西会让我们退出合并模式。
- 所以我们之前做了一个虚拟合并(并使用策略
ours
来防止合并冲突,这正是我们想要发生的错误事情)。
git read-tree
然后我们根据需要从 master 读取状态
- 现在我们
amend
与现在终于正确的索引内容合并。
- 这将保留原始合并信息。
- 请注意,这是
ff
根据上游。
这有什么问题?
git commit
意味着是原子的。要么你有一个正确的状态,要么没有。
- 然而,这引入了一种非原子情况,在这种情况下,竞争条件(停电)可能会使您的本地 git repo 处于某种不需要的状态
- 如果在自动设置中使用此策略,这是不好的,例如,在发布 (B1) 之后,当前上游(主)将用于重新启动以创建下一个版本(B2 和更高版本)。
- 因此,变体 2 不能被视为对此的最终定论。是的,它以某种方式有效,但它既不漂亮、干净也不完美。
其他解决方案似乎太复杂了。但也许我监督了一点?
要么使用完全难以理解的 git-plumbing 命令来自己创建正确的提交对象——不适合易于理解和使用的解决方案。
或者做一些非常复杂的子分支,然后快进到子分支,然后删除它 - 双重禁止,因为这甚至会引入更复杂的事情,比如如果出现问题需要进行复杂的清理。
或者找出需要哪些命令来将工作树更新为 a 之后的索引(就像-u
已经可以做到的那样重新发明轮子)git read-tree master
,因为这应该发生在(!)提交之前(像往常一样)。
去做
这尚未通过子模块进行彻底测试。如果它们被添加、删除、替换等,.gitmodules
并且.git/modules/
已经更新或阻止了一些东西。Loooooong 的故事。