合并与重设基的主要缺点是合并会导致树混乱。如果主服务器经常被更新,那么每次有重大更新时合并主服务器将创建一个不必要的提交的整个主机。现在,大多数情况下,实际上并不需要这样做。将存储库考虑如下:
Master A\--B--C\--D\---------E
Branch l--m---n---o--p--q
这里n是一个合并,在这里我们必须解决大量的冲突,我们希望避免再次解决。我们希望在不创建新合并提交的情况下合并e
所以我们回到o,合并e和cherry pick p和q在上面:
Master A\--B--C\--D\--------E\
Branch l--m---n\--o--p--q \
Tmp -------------o'-p-q
如果这样做没有错误,我们可以删除旧的分支。
如果我是第一个想到这种工作流程的人,我会很惊讶。有什么git扩展可以自动完成这项工作吗?
我已经开始编写一个脚本来执行此操作,但主要问题是选择o.“:/^merge”-在大多数情况下将选择o,但如果没有更好的方法来避免依赖不是以单词merge开头的提交消息,则会感到惊讶。
最佳答案
编辑:To retroactively enable rerere, see here.。这个答案中的脚本不会启用reere,并且在E
的历史(见下文)中,当存在进一步的变化时,其行为将不同于reere。n...D
执行o
合并并应用任何仍然有效的rerere
分辨率,而此脚本执行标准n...E
合并(但将父n...D
替换为o...E
)
复制图形以供参考:
before desired after
Master A\--B--C\--D\....E \ Master A\--B--C\-D...E\
Branch l--m---n---o--p--q / Branch l--m---n------o'--p'--q'
因此,reere将绕过
o
-revertedo
冲突,而脚本将把reversion视为进一步的更改。两个脚本都会生成上面的“期望后”图,但它们通过不同的路径到达那里。一个小时的尝试并没有产生比简单地看图表和推断更容易理解的文本描述的差异。
我不清楚是重播还是剧本的表现总是更好。
当我这样做的时候
回到o,合并e
具有
git checkout o
git merge E
我明白了
Master A\--B--C\--D\---------E
Branch l--m---n---o\-p--q \
HEAD `--------o'
与
E
为n...D
的父级。您确实需要o
内容(以保留已在o'
中应用的任何冲突解决方案),但您希望它具有o'
和o
作为父级,而不是n
和E
。这其实相当容易。所以完整的程序是,
#!/bin/sh
# 1. identify the most recent merge on $1
# 2. verify that it's from $2
# 3. update the merge to $2's current state,
# 4. preserving any conflict resolutions that were already done
# 5. and cherry-pick everything since.
# most recent merge in $1
update=`git rev-list -1 --min-parents=2 $1`
# verify most recent merge is from correct merge base
test "`git merge-base $1 $2`" = "`git rev-parse $update^2`" \
|| { echo "most recent merge isn't of $1 from $2"; exit 1; }
set -e # exit immediately on error
git checkout $update
git merge $2
git checkout $(
# this makes a new commit with HEAD's commit message and tree
# but with $update^ and $2 as parents
git cat-file -p HEAD \
| sed 1,/^$/d \
| git commit-tree -p $update^ -p $2 HEAD^{tree}
)
test $update = `git rev-parse $1` || git cherry-pick $update..$1
git checkout -B $1
如果您愿意丢失在
o
中完成的任何冲突解决方案,您可以这样做(从E
中)set -e
git checkout $update^
git merge $2
test $update = `git rev-parse $1` || git cherry-pick $update..$1
git checkout -B $1
如果在一个子shell中工作,退出它并不是一件麻烦事,那么你就可以做得更不那么脆弱了。
git merge $2 \
|| { echo "Resolve conflicts and \`exit\`, or \`exit 1\` to not continue"; $SHELL; }
edit:update,当没有可选择的内容时处理更新合并。