5. Commit Graph

Fix the Bug: Merge-Base (Lowest Common Ancestor) Finding

midversion-control-internalscommit-graphdebugging

git merge-base A B finds the best common ancestor commit of two branch tips -- what git merge uses as the three-way merge base, and what git log A..B uses to figure out which commits are actually new on B. The commit graph is a DAG, not a tree: a merge commit has MORE THAN ONE parent, so "the" parent chain from a commit isn't a single path -- every parent has to be followed to find every ancestor.

Right now, get_merge_base silently returns the WRONG (too-old) common ancestor whenever the correct answer is only reachable by walking through a merge commit's second (or later) parent -- because _collect_ancestors only ever follows commit_parents[0].

Your task: find the bug in _collect_ancestors and fix it. The overall structure of get_merge_base -- collect both commits' ancestor sets via _collect_ancestors, intersect them, and keep only the most recent common ancestor -- is already correct; don't change it.

Example that currently fails

parents = {
    "A": [], "B": ["A"], "C": ["A"], "D": ["B"], "E": ["C"],
    "M": ["D", "E"],   # a merge commit -- TWO parents
    "X": ["M"], "Y": ["E"],
}

get_merge_base(parents, "X", "Y")
# should be "E" (X reaches E through M's SECOND parent; Y reaches E
# directly)
# currently: "A" (only M's first parent, D, gets walked -- E and C are
# never visited from X's side at all, so the intersection collapses
# all the way back to the root)

Real-world grounding

  • Git's merge-base computation (get_merge_bases and the ancestor walk it's built on, including how it handles a commit with multiple parents): commit-reach.c

Real Git's version additionally handles the case where there's more than one equally good merge base (a criss-cross merge), using commit generation numbers and a priority queue to stay efficient on huge histories instead of this exercise's plain BFS-and-intersect -- but "every parent of a merge commit is part of its ancestry, not just the first one" is the exact mechanism this bug breaks.

hints
merge_base.pysign in to run
Loading...
test result

This is a preview. Sign in to run this exercise against the real tests.