Tuesday, July 26, 2016

Git Tutorial 6—pull request



Continue our theme, dev1 is still the lucky hero, in this tutorial, dev2 is allowed to merge his code directly into master, he has to create pull request to ask dev1 to pull his code into master.  Let us see what kind of troubles he will run into.

Day 1 end

dev1 pushes his code into remote

dev1 is happy with his changes and push to the remote master:

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

dev2 creates a pull request

dev2 wants to ask dev1 to pull his code into master, to do so, he does these things:
1)      merge master into his branch, and as we know by now, he runs into a conflict and solves it
git checkout master
git pull origin master

git checkout t2
#runs into a conflict
git merge master

#solves the conflict
git add testf
git commit

2)      push his local branch to remote, in doing so, creates a remote branch with the same name
git push -v --tags --set-upstream origin t2

At this point, dev2’s workspace looks like this:


3)      creates a pull request
hub pull-request -m "p1"

Note, hub is an extension of github commands, and can be downloaded from https://github.com/github/hub, to install it in windows, just add the bin directory to the PATH variable.

Now you can see in Github, an open pull request, which, since dev2 has taken care to solve conflict first, can be auto merged:

What will happen if dev2 doesn’t merge first? In other words, dev2 doesn’t do the first step, instead he just does the second and third step:

git push -v --tags --set-upstream origin t2
hub pull-request -m "p1"
Github shows the result pull request has conflicts, and has to be solved manually:

dev1 merges the pull request

Since there is no conflict on the pull request, dev1 can merge the request on Github by clicking on the merge button.  

In our plot, dev1 doesn’t trust dev2 very much, perhaps because dev2 is an open source contributor who is unknown to dev1, so dev1 decides to merge dev2’s code locally to check out. He can merge the remote t2 into his local master and then push his local master to remote:

git checkout master
git pull origin master

#note, need to fetch origin first, otherwise git will complain origin/t2 is unknown
git fetch origin
git merge --no-ff origin/t2

git push -v --tags --set-upstream origin master:master

Or he can check out the remote t2 into a local branch, and merge the local branch to his local master, then push his local master to remote:

git checkout master
git pull origin master

git fetch origin
git branch t2 origin/t2
git merge --no-ff t2

git push -v --tags --set-upstream origin master:master

Either way, dev1 ends with:


Going to Github, you will see the pull request has been merged:

Day 2

dev1 pushes his code into remote

dev1 works on a local branch t3, and pushes his changes to remote:
git checkout master
git pull origin master
git checkout 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'

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

git branch --delete t3

dev2 creates a pull request

git checkout master
git pull origin master

git checkout -b t4
echo 't4-c1' >>  testf; git add testf; git commit -m 't4-c1'

git push -v --tags --set-upstream origin t4

hub pull-request -m "p2"

At this point, the pull request contains no conflict, and can be auto merged. Unfortunately, dev1 feels too tired, and he returns home without noticing the pull request.

Day 3

 

dev1 pushes his code into remote

dev1 doesn’t pay attention to dev2’s pull request, he chooses to work on his stuff first:

git checkout master
git pull origin master
git checkout -b t5
echo 't5-c1'>> testf; git add testf; git commit -m 't5-c1'

Note, at this point, the pull request created in day 2 now contains conflicts!

dev2 creates a pull request

dev2 continues to work on his local branch t4, then tries to merge t4 with remote master, upon which he runs into a conflict which he solves manually:

git checkout t4
echo 't4-c2' >>  testf; git add testf; git commit -m 't4-c2'

git checkout master
git pull origin master

git checkout t4
git merge master

#solve the conflict
git add testf
git commit

Then he pushes his local t4 to remote:
git push -v --tags --set-upstream origin t4

Now, notice the pull request created in day 2 has no conflict again, because the conflict has been solved by dev2!

dev2 tries to create a new pull request:
hub pull-request -m "p3"

This is not necessary and will actually fail with the message:
Error creating pull request: Unprocessable Entity (HTTP 422)
A pull request already exists for t4.

 

dev1 merges the pull request

Finally, dev1 has some free time and is able to merge the pull request:
git checkout master
git pull origin master

git fetch origin
git merge --no-ff origin/t4

git push -v --tags --set-upstream origin master:master

dev1’s workspace now looks like this:


Lessons learned:

  • To make sure a team functions smoothly, pull requests should be merged quickly.
  • Solving conflicts is a chore, and it should be avoided as much as possible. In any day,  well-designed code (loosely-coupling code) is the king.