The move makes the transition from one branch to another

I have a tree:

/--b1---b2 <-- topic b / a1---a2 <-- topic a 

where 'b' depends on 'a'. Then I understand that I need to make some changes related to topic "a" in order to continue "b", but I would like to make them to "b" as a normal development course for "b":

  /--b1---b2---a3---a4---b3---b4---a5---b5 <-- topic b / a1---a2 <-- topic a 

Then, when the thing that I want to do on 'b' is done, I want my tree to look like this:

  /--b1---b2--------m---b3'---b4'---b5' <-- topic b / / a1---a2---a3'---a4'---a5' <-- topic a 

as if I actually made all the changes to "a" and then merged them to "b" and then continued to "b".

I know I can do it manually:

1- rebase / cherry-pick 'a' is fixed from branch 'b' to 'a'
2- create a temporary branch "b-tmp" to "b".
3- reset branch of 'b' to 'b2'.
4- merge 'a' into 'b'.
5- rebase / cherry-pick 'b' is taken from 'b-tmp' to 'b'.
6 - delete the branch 'b-tmp'.

I can create some script to do this, I just would like to know if there are better ways / ideas for this other than these 6 steps.

+8
git
source share
1 answer

Let me start by saying that I would rather integrate topic branches often (integration early, collection often ... bell rings?). So, in fact, when there are changes that should eventually happen, I would come back, make changes to a and rebase b on top.

If you need to be stable for any other purpose, I would make a-for-b branch to temporarily save work, and reformat b on top of it.

If you really need to work with theme-a changes within branch b, here is what I will do.

Note. built-in screencasts


How to get to the starting point

This is a simple working tree with a layout from the question:

 mkdir /tmp/q cd /tmp/q git init . touch f git add f git commit -am initial git checkout -ba; for a in a{1,2}; do echo $a>$a; git add $a; git commit -am $a; git tag $a; done git checkout -bb; 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 

See screencast here


Reorganization captures its topic threads

 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 -ia # 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 

Again, see the screencast


Checking Results

Now we can do the comparison before / after the tree:

 sehe@natty:/tmp/q$ git show-branch ab ! [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 

Make it permanent:

 for name in ab; do git branch -m $name ${name}_old && git branch -m ${name}_new $name done git branch -D a_old b_old # when sure 

Notes

I deliberately decided to make conflict-free changes to demonstrate. Of course, in real life you will encounter merge conflicts. Use git mergetool and git rebase --continue .

If your changes are hygienic and truly belong to their respective topics, then the likelihood that conflicts should be small and easily resolved. Otherwise, it's time to review the branching scheme (see Martin Fowler ea)

Discussion

In response to

You also say that ā€œwhen there are changes that should go toā€œ a, ā€in the end I’ll go back, make changes toā€œ a ā€and rebaseā€œ b ā€on top ofā€œ a. ā€I’m not sure that I understand. Not could you explain?

I mean, in any case, I would try to make revisions a3, a4, a5 on branch a and reinstall b on it, therefore

  • the person performing the merge is the same person who commits.
  • you commit and merge sequentially (this means that you will not mess up due to loss in short memory) <-- this is the Merge Early/Soon/Frequently mantra
  • You avoid unnecessary merge conflicts.
  • you don’t need to ā€œcome back on timeā€ later and rewrite the original commits: a3, a4, a5 will simply be merged, not copied (see Git Cherry -pick vs Merge Workflow )

Here is ā€œHow to Get Started,ā€ but adapted to my idealized workflow. Please note that the end result of this alternative result is exactly what you will finish after all the juggling shown in the section ā€œReorganization is fixed on its branchesā€ above!

 mkdir /tmp/q cd /tmp/q git init . touch f git add f git commit -am initial git checkout -ba; # no change echo a1>a1; git add a1; git commit -am a1 echo a2>a2; git add a2; git commit -am a2 git checkout -bb; # 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 

Note that in practice it’s easy to go back to the branch to fix your a3 / a4 / a5:

  • If you just realized that you have affected things that belong to this branch, you can simply switch to a branch with pending local changes 2
  • then you selectively (!!) put the parts that you want to branch to ( git add -i or similar in git guis or, for example, vim fugitive )
  • lock on
  • go back to branch b ( git checkout b )
  • pass the remaining bits
  • rebase b for latest version in

2 if they do not conflict with other changes from a..b; in this case you git stash first and git stash apply if on a branch

+8
source share

All Articles