将提交从一个分支移动到另一个分支,然后将它们合并回来

chi*_*ila 8 git

我有一棵树:

       /--b1---b2 <-- topic b
      /    
a1---a2 <-- topic a
Run Code Online (Sandbox Code Playgroud)

其中'b'取决于'a'.然后我意识到我需要做一些与主题'a'相关的更改以继续'b',但我想在'b'上做它们作为'b'的正常开发过程:

       /--b1---b2---a3---a4---b3---b4---a5---b5 <-- topic b
      /    
a1---a2 <-- topic a
Run Code Online (Sandbox Code Playgroud)

然后,当我想在'b'上完成的事情完成时,我希望我的树看起来像这样:

       /--b1---b2--------m---b3'---b4'---b5' <-- topic b
      /                 /
a1---a2---a3'---a4'---a5' <-- topic a
Run Code Online (Sandbox Code Playgroud)

好像我实际上对'a'进行了所有更改,然后将它们合并在'b'上,然后继续'b'.

我知道我可以手动执行此操作:

1- rebase/cherry-pick'a'从分支'b'提交到'a'2-在'b'上
创建一个时间分支'b-tmp'.
3-将分支'b'重置为'b2'.
4-将'a'合并到'b'上.
5- rebase/cherry-pick'b'从'b-tmp'提交到'b'.
6-删除分支'b-tmp'.

我可以创建一些脚本来执行此操作,我只想知道是否有更好的方法/想法来执行此操作,除了这6个步骤.

seh*_*ehe 8

让我首先说我宁愿经常整合主题分支(早期整合,经常构建......敲响钟声?).所以,事实上,当有应该去到最终的变化,我会回去,做了改变一个,和变基b之上一个.

如果一个需要一些其他的目的是稳定的,我会成为一个一个换-B分支包含的工作暂时和重订b在此之上.

如果你真的必须使用分支' b ' 内的'topic- a '变化,那就是我要做的.

注意:包括截屏视频


到达起点

这是一个简单的工作树,其中包含以下问题的布局:

mkdir /tmp/q
cd /tmp/q
git init .
touch f
git add f
git commit -am initial
git checkout -b a; for a in a{1,2}; do echo $a>$a; git add $a; git commit -am $a; git tag $a; done
git checkout -b b; for a in b{1,2} a{3,4} b{3,4} a5 b5; do echo $a>$a; git add $a; git commit -am $a; git tag $a; done
git show-branch 
Run Code Online (Sandbox Code Playgroud)

在这里截屏


将提交重新组织到其主题分支上

git checkout -b a_new a     # for safety, work on a clone of branch a
git reset --hard b          # start by moving it to the end of the b branch
git status                  # (just show where we are)
git log --oneline

git rebase -i a             # rebase it on top of the original branch a

    # not shown: delete every line with non-branch-a commits (b1-b5)
    # see screencast

git log --oneline           # (just show where we are again)

git checkout -b b_new b     # for safety, work on a clone of branch b
git log --oneline           # (just show where we are again: the end of branch b)
git rebase -i a_new         # this time, rebase it on top of the new branch a_new
git log --oneline           # (check results)
git show-branch b_new a_new
Run Code Online (Sandbox Code Playgroud)

再次,请参阅截屏视频


检查结果

我们现在可以进行前/后树比较:

sehe@natty:/tmp/q$ git show-branch a b
! [a] a2
 ! [b] b5
--
 + [b] b5
 + [b^] a5
 + [b~2] b4
 + [b~3] b3
 + [b~4] a4
 + [b~5] a3
 + [b~6] b2
 + [b~7] b1
++ [a] a2

sehe@natty:/tmp/q$ git show-branch a_new  b_new 
! [a_new] a5
 * [b_new] b5
--
 * [b_new] b5
 * [b_new^] b4
 * [b_new~2] b3
 * [b_new~3] b2
 * [b_new~4] b1
+* [a_new] a5
Run Code Online (Sandbox Code Playgroud)

永久化:

for name in a b; 
do 
     git branch -m $name ${name}_old && 
     git branch -m ${name}_new $name
done
git branch -D a_old b_old # when sure
Run Code Online (Sandbox Code Playgroud)

笔记

我故意选择对演示进行非冲突的更改.当然,在现实生活中,你会遇到合并冲突.使用git mergetoolgit rebase --continue.

如果您的更改是卫生的并且确实属于各自的主题分支,那么冲突可能很少并且很容易解决.否则,是时候修改你的分支方案了(参见Martin Fowler ea)

讨论

回应

你还说"当最终会有'a'的变化时,我会回去,对'a'进行更改,然后在'a'之上'b''.我也不确定我是否理解这一点.你能解释一下吗?

我的意思是,我会尽量让A3,A4,A5上的修订一个分支,无论如何,和变基b到这一点,所以

  • 进行合并的人是进行提交的同一个人
  • 你连续进行提交和合并(这意味着你不会因为短期内存丢失而搞乱) <-- this is theMerge Early/Soon/Frequently mantra
  • 你避免不必要的合并冲突
  • 你不必在以后"回到过去"并重写原始提交:a3,a4,a5将被合并,而不是被复制(参见Git Cherry-pick vs Merge Workflow)

这是"走向起点",但适应了我理想化的工作流程.请注意,这个替代结果的最终结果已经完全是您在上面的"重组提交到他们的主题分支"下显示的所有杂耍之后结束的!

mkdir /tmp/q
cd /tmp/q
git init .
touch f
git add f
git commit -am initial
git checkout -b a;                        # no change
echo a1>a1; git add a1; git commit -am a1
echo a2>a2; git add a2; git commit -am a2

git checkout -b b;                        # start off the a branch
echo b1>b1; git add b1; git commit -am b1
echo b2>b2; git add b2; git commit -am b2

git checkout a                            # go back to the a branch for a3 and a4
echo a3>a3; git add a3; git commit -am a3
echo a4>a4; git add a4; git commit -am a4

git checkout b
git rebase a                              # here is the magic: rebase early
echo b3>b3; git add b3; git commit -am b3
echo b4>b4; git add b4; git commit -am b4

git checkout a                            # go back to the a branch for a5
echo a5>a5; git add a5; git commit -am a5

git checkout b
git rebase a                              # again: rebase early
echo b5>b5; git add b5; git commit -am b5

git show-branch
Run Code Online (Sandbox Code Playgroud)

请注意,实际上回到a分支提交a3/a4/a5提交并不困难:

  • 如果您只是意识到触摸了属于该分支的内容,您可以切换具有待定本地更改分支2
  • 你然后选择性(!!)阶段即需要去到零件一个分支(git add -i或在GIT中的GUI或例如类似于vim fugitive)
  • 提交上
  • 切换回b分支(git checkout b)
  • 提交其余的位
  • 变基b到的最新版本

2只要它们不与a..b的其他变化发生冲突; 在这种情况下你最好git stash先和git stash apply在当一个分支