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
Check your identity.
bashgit config user.name git config user.emailBoth should print a value. If either prints nothing, set it as in Commits. Use the email you are happy to see in a commit.
Create the repository.
bashmkdir -p ~/git-lab && cd ~/git-lab git init -b main trip-planner cd trip-plannertextInitialized empty Git repository in /home/you/git-lab/trip-planner/.git/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:textPassport Tickets Phone charger Toothbrush Rain jacket Walking shoes Socks T-shirts Water bottle Snacks Book HeadphonesThen:
bashgit 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.txtOpen 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
mainlabel. The changes panel says Working tree clean.Make two unrelated edits. In
packing.txt, changeTicketstoTrain tickets, and addSunglassesas a new last line. Save. (Or in the terminal:sed -i 's/^Tickets$/Train tickets/' packing.txtandecho "Sunglasses" >> packing.txt.)Expected:
packing.txtappears under Unstaged with anMbadge. BranchPilot notices by itself.Stage only the first hunk. Select
packing.txtunder 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, answeryto the first hunk andnto the second.Expected:
packing.txtis now under both Staged and Unstaged. In the terminal:bashgit status --shorttextMM packing.txtSelect the file under Staged (or run
git diff --staged) and check that only the tickets line is there.Commit it, then commit the rest. Type
Say which tickets to packin Commit subject and select Commit (1). Then stage the remaining hunk (Stage file) and commit it asPack sunglasses.bashgit commit -m "Say which tickets to pack" git add packing.txt git commit -m "Pack sunglasses" git log --onelinetexteb4dd84 Pack sunglasses 9527823 Say which tickets to pack 421cf2d Start trip planner
Part 2: a feature branch, tidied with interactive rebase
Create a branch. In BranchPilot, select the plus button on the Branches heading (Create branch), type
weekendin Branch name, leave Check out ticked and select Create.bashgit switch -c weekendtextSwitched to a new branch 'weekend'Expected: the header shows
weekendas the current branch.Make three commits on it. Create
days.mdwith a deliberate typo,waterfal:text# Day plan Saturday: Walk to the waterfal Sunday: Train home after lunchCommit it as
Add day plan. Then fix the typo (waterfall) and commit asFix typo in day plan. Then inpacking.txtchangeSnackstoTrail mix and fruitand commit asPack hiking snacks.bashgit 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 --alltext* 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 -astages every change to tracked files before committing. It skips new files, which is whydays.mdneededgit add.)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:
textpick Pack hiking snacks pick Fix typo in day plan pick Add day planSet 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 frompicktofixup, then save and close:textpick 91bb216 # Add day plan fixup 706fbcf # Fix typo in day plan pick c4d4033 # Pack hiking snacksExpected: BranchPilot shows Rebase complete; the terminal prints
Successfully rebased and updated refs/heads/weekend.bashgit log --oneline --graph --alltext* c77da86 Pack hiking snacks * a105eae Add day plan * eb4dd84 Pack sunglasses * 9527823 Say which tickets to pack * 421cf2d Start trip plannerTwo commits instead of three, with new hashes.
days.mdsayswaterfall.
Part 3: a real merge conflict
Change the same line on main. Switch to
main(double-click it in Branches, orgit switch main).days.mddisappears from the folder, because it only exists onweekend. ChangeSnackstoSnacks for the trainand commit asPack snacks for the train.bashgit switch main sed -i 's/^Snacks$/Snacks for the train/' packing.txt git commit -am "Pack snacks for the train" git log --oneline --graph --alltext* 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
Snacksline.Merge weekend into main. In BranchPilot, right-click
weekendand choose Merge into current…, then Merge.bashgit merge weekendtextAuto-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.txtunder Conflicted with aUbadge. Openpacking.txtin your editor:textWater bottle <<<<<<< HEAD Snacks for the train ======= Trail mix and fruit >>>>>>> weekend BookResolve 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.txtdoes 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):bashgit 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 mergetoolDeltaView opens with
Snacks for the trainin LEFT andTrail mix and fruitin 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:
textWater bottle Snacks for the train Trail mix and fruit Bookand
git diff --staged --checkprints nothing (no leftover markers).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 acceptMerge branch 'weekend'.bashgit log --oneline --graph --alltext* 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 plannerExpected: BranchPilot's graph shows the merge commit as a hollow ring where the two lanes join.
days.mdis back in the folder.
Part 4: make a mistake, then undo it
Delete the merged branch. Right-click
weekend, choose Delete… and confirm, or:bashgit branch -d weekendtextDeleted branch weekend (was c77da86).It is merged, so Git deletes it without complaint.
Make the mistake. You meant to undo a small edit, but you throw away the merge instead:
bashgit reset --hard HEAD~1textHEAD is now at 0959eac Pack snacks for the trainExpected: the merge commit is gone from BranchPilot's graph, and
days.mdis gone from the folder. Theweekendbranch is deleted too, so no label points at that work any more.Find it in the reflog.
bashgit reflogtext0959eac 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}.Put it back.
bashgit reset --hard "HEAD@{1}"textHEAD is now at 37dcd6b Merge branch 'weekend'Expected: the merge commit, both
weekendcommits anddays.mdare 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, changeBooktoTwo booksthere and commit. Onmain, changeBooktoKindleand commit. Mergebooks, and when it conflicts select Abort in the banner (orgit merge --abort).git statusis clean again andmainis unchanged. - Lose a branch on purpose. Delete
bookswith Delete… and then Force delete (orgit branch -D books). Git printsDeleted branch books (was …). Bring it back withgit branch booksfollowed by that hash, or find the hash withgit reflog. - Get blocked, then stash. Add a line to
packing.txtwithout committing and try to switch tobooks. Git refuses:Your local changes to the following files would be overwritten by checkout. Stash the change (Stash changes in BranchPilot, orgit stash push -m "packing ideas"), switch, switch back, and Pop it (orgit 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 removesSunglasses; nothing in the history was rewritten. - Keep a secret out. Create a file
.envwith the lineAPI_KEY=example-not-real. It appears under Untracked. Add a.gitignorecontaining.envand watch it disappear from the list. Commit.gitignore, never.env. - Compare two commits in DeltaView. Set DeltaView up as
git difftoolfor this repository (the same commands as in Use DeltaView with Git, without--global) and rungit difftool HEAD~2.
Clean up
In BranchPilot, close the repository's tab. On the welcome screen, select Remove from recent on its row.
Delete the lab folder. This removes the repository, its history and the DeltaView settings you added without
--global:bashrm -rf ~/git-labKeep your global
user.nameanduser.email: you will need them for real projects.
Check yourself
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?
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 --hardcan hide a commit, but the reflog still knows where it is.
Next steps
- BranchPilot reference: every menu and the Git command behind it
- Merge three versions of a file in DeltaView
- Git identities in DhivaLabs Shell, if you work with more than one account
- Back to all learning tracks