pete > courses > CS 315 Fall 26 > lab 02: git merging


Lab 02: git merging

Goals


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

Last modified: