Skip to content

Git lab ​

Build a small repository from nothing, then take it through everything in the track: a single-hunk commit, a feature branch, an interactive rebase, a real merge conflict, and a mistake you undo with the reflog.

Time: 45 to 60 minutes · Before this: the six lessons

What you need ​

  • A terminal with Git 2.28 or newer (git --version).
  • BranchPilot on Linux. Every step also gives the terminal command, so you can follow along without it.
  • Optional: Delta View, to resolve the conflict in a three-way merge tool.
  • A text editor.

On Windows, BranchPilot is not available. Do the terminal commands in Git Bash or in DhivaLabs Shell's Local terminal, and use DeltaView for the conflict.

Everything happens in a new folder, ~/git-lab, that you delete at the end. Your hashes will differ from the ones shown, because a hash includes your name and the time.

Part 1: a repository and a single-hunk commit ​

  1. Check your identity.

    bash
    git config user.name
    git config user.email

    Both should print a value. If either prints nothing, set it as in Commits. Use the email you are happy to see in a commit.

  2. Create the repository.

    bash
    mkdir -p ~/git-lab && cd ~/git-lab
    git init -b main trip-planner
    cd trip-planner
    text
    Initialized empty Git repository in /home/you/git-lab/trip-planner/.git/
  3. Add two files and make the first commit. Create README.md:

    text
    # Trip planner
    
    Packing list and day plan for a weekend away.

    and packing.txt, one item per line:

    text
    Passport
    Tickets
    Phone charger
    Toothbrush
    Rain jacket
    Walking shoes
    Socks
    T-shirts
    Water bottle
    Snacks
    Book
    Headphones

    Then:

    bash
    git add README.md packing.txt
    git commit -m "Start trip planner"
    text
    [main (root-commit) 421cf2d] Start trip planner
     2 files changed, 15 insertions(+)
     create mode 100644 README.md
     create mode 100644 packing.txt
  4. Open it in BranchPilot. Start BranchPilot, select Open repository… and choose ~/git-lab/trip-planner.

    Expected: the commit graph shows one commit, Start trip planner, with the main label. The changes panel says Working tree clean.

  5. Make two unrelated edits. In packing.txt, change Tickets to Train tickets, and add Sunglasses as a new last line. Save. (Or in the terminal: sed -i 's/^Tickets$/Train tickets/' packing.txt and echo "Sunglasses" >> packing.txt.)

    Expected: packing.txt appears under Unstaged with an M badge. BranchPilot notices by itself.

  6. Stage only the first hunk. Select packing.txt under Unstaged. The diff shows two hunks: @@ -1,5 +1,5 @@ with the tickets change, and one at line 10 with +Sunglasses. Select Stage hunk on the first one only.

    In the terminal: git add -p, answer y to the first hunk and n to the second.

    Expected: packing.txt is now under both Staged and Unstaged. In the terminal:

    bash
    git status --short
    text
    MM packing.txt

    Select the file under Staged (or run git diff --staged) and check that only the tickets line is there.

  7. Commit it, then commit the rest. Type Say which tickets to pack in Commit subject and select Commit (1). Then stage the remaining hunk (Stage file) and commit it as Pack sunglasses.

    bash
    git commit -m "Say which tickets to pack"
    git add packing.txt
    git commit -m "Pack sunglasses"
    git log --oneline
    text
    eb4dd84 Pack sunglasses
    9527823 Say which tickets to pack
    421cf2d Start trip planner

Part 2: a feature branch, tidied with interactive rebase ​

  1. Create a branch. In BranchPilot, select the plus button on the Branches heading (Create branch), type weekend in Branch name, leave Check out ticked and select Create.

    bash
    git switch -c weekend
    text
    Switched to a new branch 'weekend'

    Expected: the header shows weekend as the current branch.

  2. Make three commits on it. Create days.md with a deliberate typo, waterfal:

    text
    # Day plan
    
    Saturday: Walk to the waterfal
    Sunday: Train home after lunch

    Commit it as Add day plan. Then fix the typo (waterfall) and commit as Fix typo in day plan. Then in packing.txt change Snacks to Trail mix and fruit and commit as Pack hiking snacks.

    bash
    git add days.md && git commit -m "Add day plan"
    sed -i 's/waterfal$/waterfall/' days.md
    git commit -am "Fix typo in day plan"
    sed -i 's/^Snacks$/Trail mix and fruit/' packing.txt
    git commit -am "Pack hiking snacks"
    git log --oneline --graph --all
    text
    * c4d4033 Pack hiking snacks
    * 706fbcf Fix typo in day plan
    * 91bb216 Add day plan
    * eb4dd84 Pack sunglasses
    * 9527823 Say which tickets to pack
    * 421cf2d Start trip planner

    (commit -a stages every change to tracked files before committing. It skips new files, which is why days.md needed git add.)

  3. Fold the typo fix into its commit. Nobody else has these commits yet, so it is safe to rewrite them. In BranchPilot, right-click Pack sunglasses (the last commit to keep untouched) and choose Interactive rebase onto this commit…. The rows are newest on top:

    text
    pick  Pack hiking snacks
    pick  Fix typo in day plan
    pick  Add day plan

    Set Fix typo in day plan to fixup. It folds into the row below it, Add day plan. Select Start rebase.

    In the terminal, run git rebase -i main. The list there is oldest on top. Change the second line from pick to fixup, then save and close:

    text
    pick 91bb216 # Add day plan
    fixup 706fbcf # Fix typo in day plan
    pick c4d4033 # Pack hiking snacks

    Expected: BranchPilot shows Rebase complete; the terminal prints Successfully rebased and updated refs/heads/weekend.

    bash
    git log --oneline --graph --all
    text
    * c77da86 Pack hiking snacks
    * a105eae Add day plan
    * eb4dd84 Pack sunglasses
    * 9527823 Say which tickets to pack
    * 421cf2d Start trip planner

    Two commits instead of three, with new hashes. days.md says waterfall.

Part 3: a real merge conflict ​

  1. Change the same line on main. Switch to main (double-click it in Branches, or git switch main). days.md disappears from the folder, because it only exists on weekend. Change Snacks to Snacks for the train and commit as Pack snacks for the train.

    bash
    git switch main
    sed -i 's/^Snacks$/Snacks for the train/' packing.txt
    git commit -am "Pack snacks for the train"
    git log --oneline --graph --all
    text
    * 0959eac Pack snacks for the train
    | * c77da86 Pack hiking snacks
    | * a105eae Add day plan
    |/
    * eb4dd84 Pack sunglasses
    …

    The branches have diverged, and both changed the Snacks line.

  2. Merge weekend into main. In BranchPilot, right-click weekend and choose Merge into current…, then Merge.

    bash
    git merge weekend
    text
    Auto-merging packing.txt
    CONFLICT (content): Merge conflict in packing.txt
    Automatic merge failed; fix conflicts and then commit the result.

    Expected: BranchPilot reports Merge has conflicts — resolve them in the right panel, shows a Merge in progress banner, and lists packing.txt under Conflicted with a U badge. Open packing.txt in your editor:

    text
    Water bottle
    <<<<<<< HEAD
    Snacks for the train
    =======
    Trail mix and fruit
    >>>>>>> weekend
    Book
  3. Resolve it, keeping both lines. Choose one way.

    In your editor and BranchPilot: delete the three marker lines so both items stay, save, then select Mark resolved on packing.txt. In the terminal, git add packing.txt does the same.

    In DeltaView: set it up as Git's merge tool for this repository only (no --global, so deleting the folder removes the setting):

    bash
    git config merge.tool deltaview
    git config mergetool.deltaview.cmd \
      'delta-view --merge "$LOCAL" "$BASE" "$REMOTE" --output "$MERGED"'
    git config mergetool.deltaview.trustExitCode false
    git config mergetool.keepBackup false
    git mergetool

    DeltaView opens with Snacks for the train in LEFT and Trail mix and fruit in RIGHT. Press Alt + ↓ to go to the conflict, choose Both, then Take both, left first. When the toolbar says All conflicts resolved, press Ctrl + S and close the window.

    Expected: either way, the file reads:

    text
    Water bottle
    Snacks for the train
    Trail mix and fruit
    Book

    and git diff --staged --check prints nothing (no leftover markers).

  4. Finish the merge. In BranchPilot the Conflicted list is empty, so Continue is enabled: select it. In the terminal, run git commit, and save and close the editor to accept Merge branch 'weekend'.

    bash
    git log --oneline --graph --all
    text
    *   37dcd6b Merge branch 'weekend'
    |\
    | * c77da86 Pack hiking snacks
    | * a105eae Add day plan
    * | 0959eac Pack snacks for the train
    |/
    * eb4dd84 Pack sunglasses
    * 9527823 Say which tickets to pack
    * 421cf2d Start trip planner

    Expected: BranchPilot's graph shows the merge commit as a hollow ring where the two lanes join. days.md is back in the folder.

Part 4: make a mistake, then undo it ​

  1. Delete the merged branch. Right-click weekend, choose Delete… and confirm, or:

    bash
    git branch -d weekend
    text
    Deleted branch weekend (was c77da86).

    It is merged, so Git deletes it without complaint.

  2. Make the mistake. You meant to undo a small edit, but you throw away the merge instead:

    bash
    git reset --hard HEAD~1
    text
    HEAD is now at 0959eac Pack snacks for the train

    Expected: the merge commit is gone from BranchPilot's graph, and days.md is gone from the folder. The weekend branch is deleted too, so no label points at that work any more.

  3. Find it in the reflog.

    bash
    git reflog
    text
    0959eac HEAD@{0}: reset: moving to HEAD~1
    37dcd6b HEAD@{1}: commit (merge): Merge branch 'weekend'
    0959eac HEAD@{2}: commit: Pack snacks for the train
    eb4dd84 HEAD@{3}: checkout: moving from weekend to main
    …

    The merge is one move ago, HEAD@{1}.

  4. Put it back.

    bash
    git reset --hard "HEAD@{1}"
    text
    HEAD is now at 37dcd6b Merge branch 'weekend'

    Expected: the merge commit, both weekend commits and days.md are back. BranchPilot updates by itself.

Break it, try it ​

Try these on the same repository. Each one teaches something the steps above did not.

  • Back out of a conflict. Create a branch books, change Book to Two books there and commit. On main, change Book to Kindle and commit. Merge books, and when it conflicts select Abort in the banner (or git merge --abort). git status is clean again and main is unchanged.
  • Lose a branch on purpose. Delete books with Delete… and then Force delete (or git branch -D books). Git prints Deleted branch books (was …). Bring it back with git branch books followed by that hash, or find the hash with git reflog.
  • Get blocked, then stash. Add a line to packing.txt without committing and try to switch to books. Git refuses: Your local changes to the following files would be overwritten by checkout. Stash the change (Stash changes in BranchPilot, or git stash push -m "packing ideas"), switch, switch back, and Pop it (or git stash pop).
  • Undo the safe way. Right-click Pack sunglasses and choose Revert this commit (or git revert eb4dd84, with your own hash). A new commit removes Sunglasses; nothing in the history was rewritten.
  • Keep a secret out. Create a file .env with the line API_KEY=example-not-real. It appears under Untracked. Add a .gitignore containing .env and watch it disappear from the list. Commit .gitignore, never .env.
  • Compare two commits in DeltaView. Set DeltaView up as git difftool for this repository (the same commands as in Use DeltaView with Git, without --global) and run git difftool HEAD~2.

Clean up ​

  1. In BranchPilot, close the repository's tab. On the welcome screen, select Remove from recent on its row.

  2. Delete the lab folder. This removes the repository, its history and the DeltaView settings you added without --global:

    bash
    rm -rf ~/git-lab
  3. Keep your global user.name and user.email: you will need them for real projects.

Check yourself ​

QuizGit lab

Question 1 of 6

After you select Stage hunk on only the first hunk, git status --short shows MM packing.txt. What does that mean?

Score: 0

What you learned ​

  • Hunk staging turns one round of mixed edits into separate, focused commits.
  • An interactive rebase tidies a branch before anyone else sees it; the commits get new hashes.
  • A conflict is Git asking you to decide; resolve, mark resolved, and continue, or abort.
  • DeltaView can be Git's merge tool for one repository or for all of them.
  • git reset --hard can hide a commit, but the reflog still knows where it is.

Next steps ​