Level 4 — Collaboration and a real conflict
Intermediate Git CLI GitLab UI GitHub UI
Objective
Everything so far had one person. This lab adds a second, which is where Git earns its keep. You will play both: two clones of the same project in two folders, each with its own identity, working on the same sentence at the same time. The conflict that follows is genuine, not simulated, and you will resolve it the way you would at work.
Starting state
- Your own private project with the playground pushed, from Lab 2.
mainclean and up to date in your existing clone.-
The better conflict markers turned on, which makes this lab much easier:
Terminal $ git config --global merge.conflictstyle zdiff3 -
About an hour. Two issues to pretend about: #15 "FAQ: clarify the licence answer" (Ben's) and #16 "FAQ: shorten the licence answer" (yours).
Instructions
Part 1: create the second person
-
Clone the project a second time, into a folder named after your colleague:
Terminal $ cd ~/git-practice $ git clone <your-project-url> ben $ cd ben -
Give that clone Ben's identity, so the history shows two people:
Terminal $ git config user.name "Ben" $ git config user.email "ben@northwind-trails.example"Without
--global, this applies to that clone only (lesson 3.4). You now have two working copies of one project:~/git-practice/trailguide(you) and~/git-practice/ben(Ben).
Part 2: Ben changes the FAQ and merges first
-
In the
benfolder, branch and rewrite the first FAQ answer. Find the line that readsYes. It is a practice project for the Git Course and can be used, changed and shared freely.and replace it withYes. Trailguide is free for everyone, including commercial use.Terminal $ git switch -c fix/15-faq-wording $ git commit -am "docs: clarify the licence answer (#15)" $ git push -u origin fix/15-faq-wording -
Merge Ben's work into
main. In real life this is his merge request being approved; here, do it directly:Terminal $ git switch main $ git merge fix/15-faq-wording $ git push $ git log --oneline -270bbe76 docs: clarify the licence answer (#15) 0755cde docs: link the installation guide from the FAQ (#33)mainon the server now has Ben's wording. Your own clone knows nothing about it.
Part 3: you change the same line, from the old main
-
Back in your own clone, and deliberately without pulling, branch and change the same line to something different:
Yes. It is a practice project and costs nothing.Terminal $ cd ~/git-practice/trailguide $ git switch -c docs/16-faq-shorten $ git commit -am "docs: shorten the licence answer (#16)" $ git log --oneline -11a144e0 docs: shorten the licence answer (#16)Two people have now edited the same sentence, from the same starting point, without knowing about each other. This is exactly how conflicts happen in real life.
-
Bring
mainup to date and update your branch from it, which is the moment the collision surfaces:Terminal $ git switch main $ git pull $ git switch docs/16-faq-shorten $ git merge mainAuto-merging docs/faq.md CONFLICT (content): Merge conflict in docs/faq.md Automatic merge failed; fix conflicts and then commit the result.Checkpoint: that is the conflict. Nothing is broken.
Part 4: resolve it
-
See where you stand.
Terminal $ git statusOn branch docs/16-faq-shorten You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: docs/faq.md no changes added to commit (use "git add" and/or "git commit -a") -
Open
docs/faq.mdand read all three versions:Markdown <<<<<<< HEAD Yes. It is a practice project and costs nothing. ||||||| 0755cde Yes. It is a practice project for the Git Course and can be used, changed and shared freely. ======= Yes. Trailguide is free for everyone, including commercial use. >>>>>>> mainYours is above, the original in the middle, Ben's below. Each of you kept part of the original and added something.
-
Write a resolution that keeps both intentions, and delete every marker line:
Markdown Yes. Trailguide is free for everyone, including commercial use, and costs nothing. -
Mark it resolved and finish the merge.
Terminal $ git add docs/faq.md $ git statusOn branch docs/16-faq-shorten All conflicts fixed but you are still merging. (use "git commit" to conclude merge) Changes to be committed: modified: docs/faq.mdTerminal $ git commit --no-edit[docs/16-faq-shorten 9d9ffd2] Merge branch 'main' into docs/16-faq-shorten -
Push and look at the shape of what you made.
Terminal $ git push -u origin docs/16-faq-shorten $ git log --oneline --graph -5* 9d9ffd2 Merge branch 'main' into docs/16-faq-shorten |\ | * 70bbe76 docs: clarify the licence answer (#15) * | 1a144e0 docs: shorten the licence answer (#16) |/ * 0755cde docs: link the installation guide from the FAQ (#33) * 683cb88 docs: add Windows question to FAQ (#33)The fork is the two of you working in parallel; the join is your resolution.
-
Finish through a merge request. On the website, open one from
docs/16-faq-shortenintomain, withCloses #16in the description. Because you already mergedmaininto the branch and resolved, the platform reports no conflicts and the merge button is available. Merge it, tick "delete source branch", then in your own clone:Terminal $ git switch main && git pull $ git branch -d docs/16-faq-shorten $ git fetch --prune
Expected result
maincontains one sentence with both ideas: "Yes. Trailguide is free for everyone, including commercial use, and costs nothing."git log --oneline --graphshows the fork and the join.- Both branches are deleted locally and on the server.
- You have resolved a real conflict, which was the point.
Common mistakes
- Pulling in step 5. That avoids the conflict and defeats the lab. The whole scenario depends on branching from the old
main. git merge mainfrom the wrong folder. The two clones look identical; checkgit config user.nameor the folder in your prompt.- Committing with markers still in the file. Search for
<<<beforegit add; the resolution in step 9 must have no marker lines left. - Trying to
git pullwhile the conflict is unresolved. Git refuses until the merge is finished or aborted. - Wanting to start over.
git merge --abortat any point in Part 4 returns you to step 6, as many times as you like. - Both clones sharing your identity. If Ben's commits show your name, step 2 was skipped or run with
--global.
Show solution
Parts 2 to 4 as commands, with the edits described in words:
# Ben's clone
$ cd ~/git-practice/ben
$ git switch -c fix/15-faq-wording
# replace the licence answer with the commercial-use wording
$ git commit -am "docs: clarify the licence answer (#15)"
$ git push -u origin fix/15-faq-wording
$ git switch main && git merge fix/15-faq-wording && git push
# your clone, without pulling first
$ cd ~/git-practice/trailguide
$ git switch -c docs/16-faq-shorten
# replace the same line with the short wording
$ git commit -am "docs: shorten the licence answer (#16)"
$ git switch main && git pull
$ git switch docs/16-faq-shorten
$ git merge main # conflict
# edit docs/faq.md to one sentence containing both ideas, delete the markers
$ git add docs/faq.md
$ git commit --no-edit
$ git push -u origin docs/16-faq-shortenKeep the ben folder: Level 6 uses two clones again.
What happened and why
Both of you started from the same commit and changed the same line, so when the two lines of work met, Git had two candidates and no way to choose (lesson 11.1). It wrote both into the file with the ancestor between them and stopped. Nothing was lost at any point: both versions were in the file, both commits were in history, and git merge --abort would have undone everything.
Your resolution became the merge commit's content. Everything else in the merge — every other line of every other file — Git combined silently, which is what it does with the overwhelming majority of any merge.
The habit this lab is really teaching is step 6: updating your branch from main before asking for review. Doing it early means resolving one small conflict on your own time. Doing it late means the merge request itself is blocked, in front of a reviewer who is waiting.
Next: Level 5 moves to the recovery commands — rebase, cherry-pick, reset and the reflog.