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