如何使两个 git 分支(具有共同的历史)在重新设置其中一个分支后彼此一致?
How to make two git branches (with common history) coherent with each other after rebasing one of them?
我觉得我的标题不够清晰,所以我描述一下问题:
在我的 git 项目中,我有 3 个分支:master
、b1
和 b2
。这是历史树:
A---B---C master
\
D---E---F b1
\
G---H---I b2
假设我想变基 b1
分支并编辑 E
提交。变基后,提交 E
和 F
将被具有不同提交 SHA 的新提交 E'
和 F'
替换。因此,b1
中的历史将不同于 b2
中的历史:
A---B---C master
\
D---E'---F' b1
A---B---C---D---E---F---G---H---I b2
所以我的问题是:在变基 b1
之后如何确保 b2
遵循 b1
(自动获得与 b1
相同的新提交)以便他们的各自的历史保持连贯。
第一次变基后,不是这样的:
A---B---C master
\
D---E'---F' b1
A---B---C---D---E---F---G---H---I b2
而是这个:
A---B---C master
\
D---Ea---F' b1
\
E---F---G---H---I b2
这里,Ea
表示修改后的E
提交。
你想要这个,如果我没理解错的话:
A---B---C master
\
D---Ea---F' b1
\
G'---H'---I' b2
您可以使用交互式变基实现此目的:
git checkout b2
git rebase -i b1
在变基编辑中,您注释掉提交 E:
的行
# pick df8efe6 E
pick a7fcbed G
pick 936b51a H
pick c77ca69 I
# ...
# Commands:
# p, pick = use commit
# ...
# If you remove a line here THAT COMMIT WILL BE LOST.
回复您的评论,如果您想从起始位置 (ABCDEFGHI) 一路走到所需的结束位置:
git checkout b2
git rebase -i master
在编辑器中:
pick 1234567 D
edit a7fcbed E
pick 936b51a F
pick c77ca69 G
pick 1e8d614 H
pick 8daafa7 I
# ...
# p, pick = use commit
# e, edit = use commit, but stop for amending
# ...
完成后,更正 b1
分支:
git checkout b1
git reset --hard 936b51a
您还可以查看其他答案以获取灵感。我不确定你为什么要在一个命令中实现所有这些;您仍然必须在此过程中的某处修改提交 E。这样做可以为您节省一个交互式变基。
如果您只有两个分支,具有如图所示的线性历史:
我会变基 b2
而不是 b1
:
A---B---C master
\
D---E'---F'
\
G'---H'---I' b2
然后更新 b1
:
git branch -f b1 F'
@Han-KwangNienhuys 的回答完全有效,如果b2
已经重写
需要更新b2
时可以应用它。
So my question is: how to make sure that b2 follows b1 (automatically gets the same new commits as b1).
您也需要重写 b2 的历史记录,您正在重新设置所有 master..b2
提交的基址并重新挂起 b1
和 b2
标签。
Interactive rebase 允许您在每个步骤后执行任意命令,特别是包括 git branch
。也一样
git rebase -i master b2
并在当前 b1 提交后的选择列表中说 exec git branch -f b1
。
您可以将其自动化,将选择列表缓冲区通过
输送
while read command commit rest; do case $command in
*) printf %s\n "$command${commit:+ $commit${rest:+ $rest}}" ;;&
pick) git for-each-ref refs/heads --points-at $commit \
--format='exec git branch -f %(refname:short)' ;;
esac; done
并且它会在每次选择分支提示后添加 exec git branch -f
。我刚刚构建并尝试了这个。当然要调味。
如果你要深入到一个分支历史中,最好只构建你想要的精确选择和分支序列; rebase 是一个方便的命令,旨在简化一项常见任务。像所有好的工具一样,它可以比您预期的更进一步,但它也有其局限性。
我觉得我的标题不够清晰,所以我描述一下问题:
在我的 git 项目中,我有 3 个分支:master
、b1
和 b2
。这是历史树:
A---B---C master
\
D---E---F b1
\
G---H---I b2
假设我想变基 b1
分支并编辑 E
提交。变基后,提交 E
和 F
将被具有不同提交 SHA 的新提交 E'
和 F'
替换。因此,b1
中的历史将不同于 b2
中的历史:
A---B---C master
\
D---E'---F' b1
A---B---C---D---E---F---G---H---I b2
所以我的问题是:在变基 b1
之后如何确保 b2
遵循 b1
(自动获得与 b1
相同的新提交)以便他们的各自的历史保持连贯。
第一次变基后,不是这样的:
A---B---C master
\
D---E'---F' b1
A---B---C---D---E---F---G---H---I b2
而是这个:
A---B---C master
\
D---Ea---F' b1
\
E---F---G---H---I b2
这里,Ea
表示修改后的E
提交。
你想要这个,如果我没理解错的话:
A---B---C master
\
D---Ea---F' b1
\
G'---H'---I' b2
您可以使用交互式变基实现此目的:
git checkout b2
git rebase -i b1
在变基编辑中,您注释掉提交 E:
的行# pick df8efe6 E
pick a7fcbed G
pick 936b51a H
pick c77ca69 I
# ...
# Commands:
# p, pick = use commit
# ...
# If you remove a line here THAT COMMIT WILL BE LOST.
回复您的评论,如果您想从起始位置 (ABCDEFGHI) 一路走到所需的结束位置:
git checkout b2
git rebase -i master
在编辑器中:
pick 1234567 D
edit a7fcbed E
pick 936b51a F
pick c77ca69 G
pick 1e8d614 H
pick 8daafa7 I
# ...
# p, pick = use commit
# e, edit = use commit, but stop for amending
# ...
完成后,更正 b1
分支:
git checkout b1
git reset --hard 936b51a
您还可以查看其他答案以获取灵感。我不确定你为什么要在一个命令中实现所有这些;您仍然必须在此过程中的某处修改提交 E。这样做可以为您节省一个交互式变基。
如果您只有两个分支,具有如图所示的线性历史:
我会变基 b2
而不是 b1
:
A---B---C master
\
D---E'---F'
\
G'---H'---I' b2
然后更新 b1
:
git branch -f b1 F'
@Han-KwangNienhuys 的回答完全有效,如果b2
已经重写
b2
时可以应用它。
So my question is: how to make sure that b2 follows b1 (automatically gets the same new commits as b1).
您也需要重写 b2 的历史记录,您正在重新设置所有 master..b2
提交的基址并重新挂起 b1
和 b2
标签。
Interactive rebase 允许您在每个步骤后执行任意命令,特别是包括 git branch
。也一样
git rebase -i master b2
并在当前 b1 提交后的选择列表中说 exec git branch -f b1
。
您可以将其自动化,将选择列表缓冲区通过
输送while read command commit rest; do case $command in
*) printf %s\n "$command${commit:+ $commit${rest:+ $rest}}" ;;&
pick) git for-each-ref refs/heads --points-at $commit \
--format='exec git branch -f %(refname:short)' ;;
esac; done
并且它会在每次选择分支提示后添加 exec git branch -f
。我刚刚构建并尝试了这个。当然要调味。
如果你要深入到一个分支历史中,最好只构建你想要的精确选择和分支序列; rebase 是一个方便的命令,旨在简化一项常见任务。像所有好的工具一样,它可以比您预期的更进一步,但它也有其局限性。