How version control works: commits, history, and merge bases
A version control system records the history of a project as snapshots called commits. In Git, each commit stores its content, a message, and pointers to its parent commits. Because a commit points to its parents, history forms a directed acyclic graph (DAG): a commit with one parent is ordinary, and a merge commit has two or more.
Python
import hashlib
import json
commits = {}
def commit(message, parents):
body = json.dumps({"message": message, "parents": parents}, sort_keys=True)
commit_id = hashlib.sha256(body.encode()).hexdigest()[:8]
commits[commit_id] = {"message": message, "parents": parents}
return commit_id
def ancestors(commit_id):
seen = {commit_id}
stack = [commit_id]
while stack:
for parent in commits[stack.pop()]["parents"]:
if parent not in seen:
seen.add(parent)
stack.append(parent)
return seen
def depth(commit_id):
parents = commits[commit_id]["parents"]
return 0 if not parents else 1 + max(depth(parent) for parent in parents)
root = commit("init", [])
parser = commit("add parser", [root])
main = commit("add tests", [parser])
feature = commit("add lexer", [parser])
merged = commit("merge feature", [main, feature])
common = ancestors(main) & ancestors(feature)
base = max(common, key=depth)
print(commits[base]["message"])
print(sorted(commits[c]["message"] for c in ancestors(merged)))
print(commit("init", []) == root)