Chapter 15Lesson 02~145 minutes

Advanced Revision Selection, Log Search, Path History, and Ancestry Analysis: Guided Hands-On Workflow and Core Operations

Construct a disposable branched and merged repository, resolve revision expressions, answer branch-unique/deployment/ancestry questions, trace a renamed file, and verify results with rev-list, log, show, and merge-base.

Hands-on graphrev-listfirst-parentRename history

Learning objectives

  • Build a deterministic graph with merged and unmerged topic branches.
  • Use rev-parse and parent selectors to prove exact branch/tag/merge identities.
  • Answer unique-to-branch and symmetric-divergence questions with revision set algebra.
  • Trace deployment first-parent and ancestry-path history.
  • Use --follow plus exact commit:path inspection to analyze a renamed file.

1. Create a disposable history with divergence, merge, and rename

This lab has a deliberate trunk integration line, a merged feature/settings branch, and an unmerged experiment/cache branch. Every later query refers to named commits captured during setup.

Git Bash, Bash, or zsh

mkdir git-history-query-lab
cd git-history-query-lab
git init -b trunk repo
cd repo
git config user.name "History Query Lab"
git config user.email "history-query@example.invalid"

mkdir -p services/api docs deploy
printf "port=8080\nmode=stable\n" > services/api/config.txt
printf "# Runbook\n" > docs/runbook.md
printf "environment=dev\n" > deploy/state.txt
git add .
git commit -m "A: establish service baseline"
A=$(git rev-parse HEAD)

printf "health=/ready\n" >> services/api/config.txt
git add services/api/config.txt
git commit -m "B: add health endpoint"
B=$(git rev-parse HEAD)

git branch feature/settings
git branch experiment/cache

printf "environment=staging\n" > deploy/state.txt
git add deploy/state.txt
git commit -m "T1: advance deployment line"
T1=$(git rev-parse HEAD)

printf "rotation=weekly\n" >> docs/runbook.md
git add docs/runbook.md
git commit -m "T2: document rotation"
T2=$(git rev-parse HEAD)

PowerShell setup alternative

New-Item -ItemType Directory git-history-query-lab | Out-Null
Set-Location git-history-query-lab
git init -b trunk repo
Set-Location repo
git config user.name "History Query Lab"
git config user.email "history-query@example.invalid"

New-Item -ItemType Directory -Force services/api,docs,deploy | Out-Null
@('port=8080','mode=stable') | Set-Content services/api/config.txt
Set-Content docs/runbook.md '# Runbook'
Set-Content deploy/state.txt 'environment=dev'
git add .
git commit -m "A: establish service baseline"
$A = git rev-parse HEAD

Add-Content services/api/config.txt 'health=/ready'
git add services/api/config.txt
git commit -m "B: add health endpoint"
$B = git rev-parse HEAD

git branch feature/settings
git branch experiment/cache

Set-Content deploy/state.txt 'environment=staging'
git add deploy/state.txt
git commit -m "T1: advance deployment line"
$T1 = git rev-parse HEAD

Add-Content docs/runbook.md 'rotation=weekly'
git add docs/runbook.md
git commit -m "T2: document rotation"
$T2 = git rev-parse HEAD

2. Build the feature branch and rename the configuration file

git switch feature/settings
git mv services/api/config.txt services/api/settings.txt
git commit -m "F1: rename API configuration"
F1=$(git rev-parse HEAD)

printf "timeout=30\n" >> services/api/settings.txt
git add services/api/settings.txt
git commit -m "F2: add API timeout"
F2=$(git rev-parse HEAD)

git log --graph --decorate --oneline --all

The rename and subsequent modification are linear on feature/settings, which makes the limits of --follow easier to see before the branch is merged.

3. Create a second branch that will remain unmerged

git switch experiment/cache
mkdir -p services/cache
printf "cache=enabled\n" > services/cache/cache.txt
git add services/cache/cache.txt
git commit -m "E1: prototype cache service"
E1=$(git rev-parse HEAD)

printf "ttl=120\n" >> services/cache/cache.txt
git add services/cache/cache.txt
git commit -m "E2: tune cache TTL"
E2=$(git rev-parse HEAD)

4. Merge the feature into trunk and create deployment tags

git switch trunk
git tag -a deploy-before-feature -m "Deployment before feature merge" "$T2"

git merge --no-ff feature/settings -m "M: merge settings feature"
M=$(git rev-parse HEAD)

printf "environment=production\n" > deploy/state.txt
git add deploy/state.txt
git commit -m "R: promote merged service to production"
R=$(git rev-parse HEAD)
git tag -a deploy-production -m "Production deployment" "$R"

git log --graph --decorate --oneline --all

The graph now contains one merged side branch and one unmerged experiment. That distinction drives the set queries below.

5. Resolve symbolic names and parent selectors to exact IDs

git rev-parse trunk
git rev-parse feature/settings
git rev-parse experiment/cache
git rev-parse deploy-production^{commit}
git rev-parse "$M^1"
git rev-parse "$M^2"
git show --no-patch --format='%H%nparents=%P%nsubject=%s' "$M"

M^1 should equal T2; M^2 should equal F2. The merge object's parent ordering gives meaning to first-parent analysis.

6. Question 1 — what commits are unique to the unmerged experiment?

git log --oneline trunk..experiment/cache
git rev-list --count trunk..experiment/cache
git rev-list --left-right --count trunk...experiment/cache

The two-dot query should show E1 and E2. The left/right symmetric-difference count also reports unique commits on trunk's side because trunk advanced independently after B.

7. Question 2 — how exactly have trunk and experiment diverged?

git log --left-right --graph --oneline trunk...experiment/cache
git merge-base trunk experiment/cache

Every displayed commit belongs exclusively to one side of the symmetric difference. The merge base should resolve to B, their last shared ancestor.

8. Question 3 — what reached production through the integration line?

git log --first-parent --oneline deploy-before-feature..deploy-production
git rev-list --first-parent deploy-before-feature..deploy-production

This view includes the merge event and the production promotion on trunk without expanding all feature commits. If your deployment policy treats merge commits as integration events, first-parent history is often the right human-facing timeline.

9. Compare first-parent with all commits reachable in the deployment range

git log --oneline deploy-before-feature..deploy-production
git log --first-parent --oneline deploy-before-feature..deploy-production

The ordinary range includes feature commits because the production tag can reach them through the merge. The first-parent query deliberately suppresses that side history. Neither is “more correct” without a defined reporting question.

10. Question 4 — which commits lie on paths from the rename to production?

git log --ancestry-path --oneline "$F1..$R"
git rev-list --ancestry-path "$F1..$R"

Expected descendants include F2, the merge M, and production commit R. Unrelated trunk commits that are not descendants of F1 are excluded even if they are reachable from R.

11. Question 5 — what is the file's history across its rename?

git log --oneline feature/settings -- services/api/settings.txt
git log --follow --oneline feature/settings -- services/api/settings.txt
git log --follow --name-status feature/settings -- services/api/settings.txt

Without --follow, history normally stops at the rename boundary for the new pathname. With --follow, Git can continue to earlier commits under config.txt. This example uses one file on a linear feature history, matching the option's intended shape.

12. Use git show to inspect a specific object rather than walking a set

git show --stat "$F1"
git show "$B:services/api/config.txt"
git show "$F2:services/api/settings.txt"

git show commit:path resolves a blob from a specific tree snapshot. It is especially useful when path names changed and you need exact content, not lineage heuristics.

13. Construct the same set with explicit ^ exclusions

git rev-list experiment/cache ^trunk
git rev-list trunk ^experiment/cache
git rev-list trunk experiment/cache --not "$B"

Explicit inclusion/exclusion syntax scales to multiple starting points. For automation, it can be clearer than mentally combining several shorthand ranges.

14. Compare path history simplification modes

git log --graph --oneline --all -- services/api/settings.txt
git log --full-history --graph --oneline --all -- services/api/settings.txt
git log --full-history --simplify-merges --graph --oneline --all -- services/api/settings.txt

The selected path determines TREESAME-style simplification. The outputs can differ around merges. Preserve the exact query in an audit so reviewers know whether topology was simplified.

15. Resolve checkout-history selectors safely

git switch experiment/cache
git switch trunk
git rev-parse '@{-1}'
git reflog --date=iso --max-count=8
git rev-parse 'trunk@{1}'

@{-1} should resolve to the previously checked out branch/commit. trunk@{1} names trunk's previous reflog value, but its meaning depends on your exact local operations.

16. Challenge — choose the query, not a memorized flag sequence

  1. You need commits on experiment/cache that trunk cannot reach. Write the smallest revision range.
  2. You need unique commits from both trunk and experiment, labeled by side. Which range and display option?
  3. You need the production integration timeline without expanding feature commits. Which traversal?
  4. You need exact content of the old path at commit B. Should you use --follow or git show B:path?
  5. You need descendants of F1 that also lead to R. Which range option?

17. Cleanup

All state is disposable, but save any reports you want before deleting the lab.

Git Bash / Bash / zsh

cd ../..
pwd
rm -rf git-history-query-lab

PowerShell

Set-Location ../..
Get-Location
Remove-Item -Recurse -Force git-history-query-lab

18. Knowledge check

Question 1. Why does trunk..experiment/cache show only E1/E2?

Question 2. Why does the ordinary deployment range include F1/F2 while first-parent does not?

Question 3. What should M^2 identify in this lab?

Question 4. Why is git show B:services/api/config.txt stronger evidence than guessing rename history?

Question 5. What does --ancestry-path F1..R exclude?

19. Summary

You created a real graph and answered five operational questions with distinct queries: branch-unique commits, symmetric divergence, first-parent deployment history, ancestry-path descendants, and one-file rename history. The commands are reusable because each begins with a set definition rather than a display preference.

Next

Make history reports stable across humans, scripts, shells, and platforms

Lesson 3 separates display configuration from query semantics and develops machine-readable output and pathspec policy.

Authoritative references

 gitrevisions
 git-rev-list
 git-log
 git-show

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.