在我的日常 git 工作流程中,我有很多主题分支,如下所示:
o--o--o (t2) / o--o (t1) / 哦——哦——哦(大师) \ 哦--哦--o (t3)
当我从上游拉动时,
o--o--o (t2) / o--o (t1) / o--o--o--n--n--n(主) \ 哦--哦--o (t3)
我想rebase我所有的主题分支都在新的master之上:
o'--o'--o' (t2) / o'--o' (t1) / o--o--o--n--n--n(主) \ 哦——哦——哦(t3)
目前我使用
git rebase --onto
手动完成此操作。在这种情况下,整个更新过程将是:
$ git checkout master
$ git pull
$ git rebase master t1
$ git rebase --onto t1 t2~3 t2
$ git rebase master t3
在各个主题分支之间跳转并添加提交时,这会变得更加棘手。
在我的例子中,主题分支之间的依赖关系纯粹是树状的:没有分支依赖于多个其他分支。 (我最终必须以某种特定的顺序上游依赖补丁,所以我先验地选择该顺序。)
有什么工具可以帮助我管理这个工作流程吗?我见过 TopGit,但它似乎与
tg patch
基于电子邮件的工作流程密切相关,这与我无关。
git 邮件列表上也提出了几乎相同的问题: 同时变基多个分支... 链接的响应附加了一个 perl 脚本,可生成您需要的命令。
如果您希望此脚本快速运行并避免让它踩到您的脚趾,还可以考虑使用
git-new-workdir
来设置仅用于自动变基的工作副本。
如果您发现自己一遍又一遍地解决相同的冲突,请考虑启用 git rerere。
话虽如此,这里有一个替代食谱:
# Construct a placeholder commit that has all topics as parent.
HEADS="$(git for-each-ref refs/heads/\*)" &&
MAGIC_COMMIT=$(echo "Magic Octopus"$'\n\n'"$HEADS" |
git commit-tree \
$(git merge-base $(echo "$HEADS" | sed 's/ .*//' ))^{tree} \
$(echo "$HEADS" | sed 's/ .*//;s/^/-p /')) &&
git update-ref refs/hidden/all $MAGIC_COMMIT
# Rebase the whole lot at once.
git rebase --preserve-merges master refs/hidden/all
# Resolve conflicts and all that jazz.
# Update topic refs from the rebased placeholder.
PARENT=
echo "$HEADS" |
while read HASH TYPE REF
do
let ++PARENT
git update-ref -m 'Mass rebase' "$REF" refs/hidden/all^$PARENT "$HASH"
done
自 git v2.44 起,有一个新的实验性命令 git replay 允许使用该命令相对轻松地完成此操作(基于您的示例):
git replay --onto master old_master..t1 old_master..t2 old_master..t3 | git update-ref --stdin
甚至还有一种更简单的语法,其中提交范围的表达方式不同:
git replay --onto master ^old_master t1 t2 t3 | git update-ref --stdin
备注:
replay
命令不会更新引用,而只是创建 git 对象并在控制台中输出引用更新,需要以适合 git update-ref --stdin
的格式完成,从而有效地进行引用更新。