Hermetic Networks Hermetic Networks

Technicians - Git and GitHub - Session 05

Merging, Pulling, and Conflicts

A branch is only useful if its work can come back. This session merges session 04's practice branch into main, the easy way and then the way that produces a conflict on purpose, so the first real one you hit on the job is not the first one you have ever seen.

1Bringing a branch back

Session 04 left a commit sitting on try-a-branch that main never received. A merge is the command that changes that: it takes everything committed on one branch and brings it onto another. Run git switch main to get back onto main, then git merge try-a-branch, and whatever try-a-branch had that main did not now exists on main too.

What actually happens behind that one command depends on whether main moved at all while the branch was out doing its own work.

2The easy case: fast-forward

If main has not changed at all since the branch split off, bringing the branch back needs no real combining. Git simply moves main's pointer forward to the branch's latest commit, the same way session 04 described a branch moving forward with each new commit. Git calls this a fast-forward, because nothing had to be merged; main just caught up. This is the most common outcome on a quiet repository.

3The other case: a merge commit

If main gained its own commits while the branch was out doing its own work, a fast-forward is not possible; the two lines of history have genuinely diverged, exactly as session 03 used that word for push. Git creates a new kind of commit, a merge commit, whose job is to join both histories together. A merge commit has two parents instead of one, which is simply git's way of recording "this snapshot combines what main had and what the branch had."

Most of the time git works out how to combine the two automatically, because the two sets of changes touched different lines or different files entirely. The lab in section 6 deliberately creates the one case where it cannot.

4Where a pull request fits

Session 02 named a pull request as a GitHub page proposing that one branch be merged into another. Everything in sections 1 through 3 can happen with no pull request at all, directly from the terminal. A pull request adds a place for that same merge to be discussed first: a view of every change the branch would bring, a space for comments, and a single button that performs the merge once everyone agrees. On a repository with more than one contributor, routing a merge through a pull request, rather than merging silently from a terminal, is what gives a second person an actual chance to catch a problem before it reaches main.

5Why a conflict happens

Git can combine two branches automatically only when it can tell, line by line, which change goes where. That breaks down in exactly one situation: both branches changed the same line of the same file, to two different things. Git has no basis for guessing which version you want, so it stops and asks you, which is what a merge conflict is. It is not an error and it is not rare. It is git being honest that a decision belongs to a person, not to software.

A conflict marks the disputed section of the file directly, using a format every version of git produces the same way:

<<<<<<< HEADThis file was created for session 03's lab.=======This file exists for the git course.>>>>>>> try-a-branchThis file exists for the git course, created in session 03.
Everything between <<<<<<< HEAD and ======= is what main has. Everything between ======= and the branch name is what the branch has. You delete all three marker lines and leave whichever text, or combination, is correct, as in the bottom box.

HEAD in the first marker refers to whichever commit you currently have checked out, main in this case. Nothing about these markers is specific to one file type; the same three lines appear in HTML, CSS, or any text file git tracks.

6Resolving one, step by step

  1. Run git status. Git lists the file or files with conflicts, so you know exactly where to look rather than searching the whole project.
  2. Open the conflicted file. Read both versions between the markers and decide what the file should actually say: one side, the other, or something that combines them, which is often the right call.
  3. Delete all three marker lines by hand, <<<<<<< HEAD, =======, and >>>>>>> branch-name, leaving only the text you decided on.
  4. Save the file, then git add it, the same as staging any other change. Staging a file after a conflict tells git you have resolved that file specifically.
  5. Once every conflicted file is staged, run git commit. Git has already prepared a merge commit message naming what was merged; you can keep it or edit it.
It is not an emergency

A conflict only means two people had an idea about the same line at the same time. Nothing is lost: both versions are sitting right there in the file, in full, until you choose. Taking a few minutes to read both sides carefully costs far less than guessing.

7Try it: cause a conflict, then fix it

Continuing in your practice folder, starting on try-a-branch from session 04.

  1. On try-a-branch, edit the first line of notes.txt to something new, for example "This file exists for the git course." Stage and commit it.
  2. Run git switch main. Confirm the first line is back to whatever it said originally; the branch's edit is not here, exactly as session 04 demonstrated.
  3. On main, edit that same first line to something different, for example "This file was created for session 03's lab." Stage and commit it. Main and the branch have now each changed the identical line, to different text.
  4. Run git merge try-a-branch. Git reports a conflict in notes.txt rather than guessing.
  5. Open the file, find the three markers from section 5, and resolve it by hand following the five steps above. Then run git log --oneline --graph and look for the merge commit, the one with two lines feeding into it.

8Check for understanding

  1. Main has had no new commits since a branch was created. What happens when that branch is merged?
    Answer

    With main unchanged since the branch split off, there is nothing to combine. Git fast-forwards, moving main's pointer up to the branch's latest commit directly, with no merge commit created.

  2. Exactly what situation causes a merge conflict?
    Answer

    Git merges automatically whenever it can tell which change belongs where, which covers different files and even different lines of the same file. A conflict only arises when both sides changed the exact same line to different text, since git then has no basis for choosing one over the other.

  3. In a conflict marker, what does the text between <<<<<<< HEAD and ======= represent?
    Answer

    HEAD refers to whatever commit you currently have checked out, which in a typical merge is main. The section before ======= is that branch's version of the line; the section after, up to the closing marker naming the other branch, is the incoming branch's version.

  4. After resolving a conflict by hand, what is the next required step before committing?
    Answer

    After editing the file to remove the conflict markers and keep the correct text, stage it with git add, exactly as you would stage any other change. That marks the conflict as resolved. Once every conflicted file is staged, git commit completes the merge.

  5. What does routing a merge through a pull request add, on a repository with more than one contributor, that merging directly from a terminal does not?
    Answer

    The merge itself works the same way either way. What a pull request adds is a review step: a page where someone other than the author can see every change the branch would bring and comment before that same merge is performed, which is the chance a direct terminal merge skips.

9Before session 06

  • Keep the merged practice repo; nothing further is needed from it until session 08.
  • Think about one change to the real HN - Training site you would want to see before it goes live. Session 06 uses that instinct directly.

10Glossary

Merge
Bringing one branch's commits onto another.
Fast-forward
A merge where the target branch had no new commits of its own, so git simply advances its pointer with no merge commit.
Merge commit
A commit with two parent commits, created when git combines two branches that each gained independent commits.
Merge conflict
The state where two branches changed the identical line differently and git needs a person to choose.
Conflict markers
The <<<<<<<, =======, and >>>>>>> lines git inserts around a disputed section of a file.
HEAD
The commit currently checked out in your working tree.

11Sources