Thursday, July 14, 2016

Git Tutorial 5-- rebase and delete local branches



This tutorial is similar to the previous, except instead of merging to master, dev1 and dev2 use rebase.

Day 1 end

This is the end of day 1, dev1 is ready to call a day, he is happy with this changes, and ready to push his changes to the remote (we will assume dev1 is almost the lucky one, and simplify his actions, in reality, everyone should take similar actions as dev2) . dev1 first rebases t1 onto master, than merge t1 into master and push to the remote master:

git checkout t1
git rebase master

git checkout master
git merge t1
git push -v --tags --set-upstream origin master:master

 
dev1 then deletes branch t1.
git branch --delete t1



dev2 wants to do the same thing, he first syncs up his local master with the remote master:
git checkout master
git pull origin master
 
Bad luck, dev2 finds out his branch t2 has deviated from master. He needs to get his changes into master, so he rebases t2 onto master, and when he does this, he runs into the dreaded conflict:
git checkout t2
git rebase master



Git shows this error is caused by reapplying t2-c1.

Git tries to be smart, and performs an auto-merge, but it fails. Note, upon automerging failure, Git has changed your file in the working directory, here is the content of testf:

dev2 will need to manually resolve this conflict (and delete those markers <<<<<<< HEAD, =======, >>>>>>> t2), he can signal to Git that the conflict has been resolved, and continues rebasing again: 
git add testf
git rebase –continue


Git continues to reapply t2-c2, and again runs into a conflict:

dev2 needs to solve this conflict, and notifies Git to continue:
git add testf
git rebase --continue

Finally, dev2 is able to merge t2 into master and push to remote:
git checkout master
git merge t2
git push -v --tags --set-upstream origin master:master




dev2 then deletes branch t2.

Day 2

dev1 syncs his local branch with the remote master and creates a new branch t3:
git checkout master
git pull origin master
git checkout –b t3

And then he commits 2 changes to t3,
echo 't3-c1' >> testf; git add testf; git commit -m 't3-c1'
echo 't3-c2' >> testf1; git add testf1; git commit -m 't3-c2'

And merges t3 into local master and pushes his changes to the remote master:
git checkout master
git pull origin master
git merge t3
git push -v --tags --set-upstream origin master:master

And then delete t3:
git branch --delete t3

In our script, dev2 is always the unlucky one. He doesn’t realize his local master is behind, and he checks out t4 from the old master:
git checkout master
git checkout -b t4
echo 't4-c1' >>  testf; git add testf; git commit -m 't4-c1'



Now he realizes his local master is behind, so he syncs up his local master with the remote, and then anxious to make sure his changes are based on the latest code, he rebases t4 onto his local master and runs into a conflict:

git checkout master
git pull --rebase origin master
git checkout t4
git rebase master


Running git status shows you:



So again dev2 needs to carefully resolve the conflict (be sure to check out each marked lines). He then continues rebasing again:
git add testf
git rebase –continue


dev2 thinks his work is not finished and is not ready to push to remote master, so he keeps working on t4:
echo 't4-c2' >>  testf; git add testf; git commit -m 't4-c2'

Day 3

The sun always smiles on dev1, and he checks out t5, works on t5, and pushes to the remote master:
git checkout master
git pull origin master
git checkout -b t5
echo 't5-c1'>> testf; git add testf; git commit -m 't5-c1'

git checkout master
git pull origin master
git merge t5
git push -v --tags --set-upstream origin master:master

git branch --delete t5

Back to our unlucky dev2, he is ready to push his changes. First, he syncs his local master to remote, and then rebases t4 onto local master and runs into a conflict:
git checkout master
git pull --rebase origin master

git checkout t4
git rebase master



Poor dev2, he is losing his mind! He has solved the conflict t4-c1 yesterday, and today he has to solve it again. He curses but he still gets the job done and notify Git to continue:
git add testf
git rebase –continue

Just as dev2 thinks his ordeal is over, he is hit again with conflict on t4-c2:

dev2 resolves the conflict and continues:

git add testf
git rebase –continue


Well, you should really admire dev2, after all this torture, he is still calm. Because he has spent so much time on resolving the conflict, before he pushes his local master to remote, he syncs up his local master with the remote just to be sure there are no changes made that overlap his changes (good luck for him this time, no more changes on the remote master, otherwise our poor dev2 may lose his mind):
git checkout master
git pull --rebase origin master
git merge t4
git push -v --tags --set-upstream origin master:master

Resulting diagram looks like this which is exactly the same as in the previous tutorial:



Lessons learned:
  •  Rebase results in a beautiful line, but at a great cost on every day developers! 

  •  It is quite common for a developer to hold on his work until he is sure that his work is at least not going to affect others, just like dev2 in the script in day 2. dev2 works on his branch, keeps an eye on the code in the remote repository, making sure that his code is built on top of the latest. Using rebase, dev2 in day 2 has to resolve the conflict on the same commit twice!  This seems to suggest that after using rebase, you should push your changes, otherwise you will have to go through the same conflict again. 

  • Personally, I do not like to reapply my commits one at a time, that is probably not what I would view my commits. I make 2 commits into my local branch, if these 2 commits are not related, then it is not confusing to recommit them again. However, the 2nd commit might add some new functions and might also refactor the code in the 1st commit. In my mind, 2nd commit is entangled with the 1st commit. If I had to write the 1st, 2nd commit from the scratch, I probably would have written them differently. Using rebasing forces me to go through the history again, which is confusing.   

No comments:

Post a Comment