pete > courses > CS 315 Fall 26 > lab 02: git merging
Lab 02: git merging
Goals
- git: explain the circumstances that cause a merge conflict and resolve them
back to git
specifically, a problem that can arise when multiple developers are working on the same codebase called a merge conflict
I’m going to simulate two users: "me" and "my partner"
in the following elucidation, commands run by me are preceded by "me\(" and comands run by my partner are preceded by "my-partner\)"
first we set things up using the normal commands we’ve already covered:
me my partner create remote repo create remote repo clone to local clone to local setup remote to partner setup remote to me
we’ve now got four empty repos, but remotes are set up so that the desired pushes and pulls can happen
we can verify this:
me$ git remote -v origin ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-public-work (fetch) origin ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-public-work (push) partner ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-partner-public-work (fetch) partner ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-partner-public-work (push)
my-partner$ git remote -v me ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-public-work (fetch) me ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-public-work (push) origin ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-partner-public-work (fetch) origin ssh://pjohnson@basin.cs.middlebury.edu/home/pjohnson/my-partner-public-work (push)
recall that "origin", "partner", and "me" are just shorthand names for the big long "ssh://…" identifiers on the right
"origin" does have a special implication, though, as it signifies where the code was cloned from originally, and therefore where pushes go by default (this can be configured, of course)
we’ll add some files:
edit foo.c
add/commit
push
pull
push
edit Makefile
add/commit
push
pull
push
now all four repos are in the same state
so let’s introduce a problem:
edit foo.c edit Makefile add/commit add/commit push push
"my" pair of repos and "my partner’s" pair of repos now differ in history
mine goes v0 -> v1 -> v2a and my partner’s goes v0 -> v1 -> v2b
but the histories are compatible in that the differences don’t conflict
so no matter which order the changes described by v2a and v2b are applied in, the end result is always the same
to resolve this, exactly one person needs to pull from the other and merge
for instance, I (on the left) could run git pull my-partners-repo master and immediately get thrown into a text editor with the following text:
Merge branch 'master' of ../my-partners-remote-repo # Please enter a commit message to explain why this merge is necessary, # especially if it merges an updated upstream into a topic branch. # # Lines starting with '#' will be ignored, and an empty message aborts # the commit.
this indicates a) that git has detected that the two histories differ, b) that git recognizes the differences don’t contradict each other, and c) git is asking us to add a new commit that represents the unification of the histories
having done so, if we look at "my" log, we see five revisions of the code now:
$ git log
v0 -> v1 -> v2a -> v2b -> v3, where v3 is the unified conclusion of the separate paths
now "I" can push, my partner can pull, and we’re back in an agreeable state:
pull
commit merge
push
pull
push
note that running "git log" in my partner’s repo produces the same output
(I’m pretty sure git just uses the timestamp of the conflicting commites to determine which goes first in the log)
that was the easy version
now the hard version: both I and my partner introduce conflicting changes
for instance, I’ll add this line to foo.c:
printf("I love Harry Potter!\n");
and my partner will add this line:
printf("I love Lord of the Rings!\n");
both add, commit, and push, like so:
edit foo.c edit foo.c add/commit add/commit push push
now the revision histories are such that the first five entries match, but the sixth in each very clearly contradict each other: git won’t be able to figure out which is correct
and indeed git tells us precisely this when "I" pull from my partner’s repo:
Auto-merging foo.c CONFLICT (content): Merge conflict in foo.c Automatic merge failed; fix conflicts and then commit the result.
and if we open up foo.c, we see something interesting:
<<<<<<< HEAD
printf("I love Harry Potter!\n");
=======
printf("I love Lord of the Rings!\n");
>>>>>>> 1d9647201ebec26408d9d24f6e46266ed970a7b5
git has denoted for us where the conflict lies
everything between the "<<<<<<< HEAD" and "=======" lines is in "my" (local) version
and everything between the "=======" and ">>>>>>> 1d9647201ebec26408d9d24f6e46266ed970a7b5" lines is my partner’s (incoming) version
it’s entirely up to me to fix it
so I replace all five of those lines with the obvious:
printf("I love Star Wars!\n");
add, commit, push, pull, push, and finally all four repos both match and are sane
pull
resolve
add files resolved
commit merge
push
pull
push