Configuration and revisions
Almost every Git command reads configuration and takes a commit from you, and many then walk history from it. This page covers those shared pieces, which later pages build on.
Layered configuration
Section titled “Layered configuration”Git reads configuration from several files in order, and a later value for the same key wins over an earlier one:
- System:
/etc/gitconfig, for every user on the machine. - Global:
~/.gitconfigor~/.config/git/config, for you. - Repository:
.git/config, for this repository. - Worktree:
.git/config.worktree, for one linked worktree whenextensions.worktreeConfigis on. - The command line:
git -c key=value, for one command.
git config --list --show-origin prints every value with the file it came from. Files can pull in
other files: include.path always does, and includeIf.gitdir:~/work/.path does only for
repositories under ~/work/, which is how people use a different email for work repositories.
Some keys hold several values rather than overriding each other. A remote’s fetch lines are
refspecs, and a remote can have many. Tools that
edit configuration must also preserve comments, blank lines and the order of entries, because people
edit these files by hand.
girtSupportedEdits preserve formatting but don’t follow includes.API docs
Revision syntax
Section titled “Revision syntax”Any command that takes a commit from a user accepts Git’s revision syntax (git help revisions):
main~2: two commits back frommain, following first parents.main^2: the second parent of the merge commit atmain.v1^{tree}: the tree of the commit thatv1points at.HEAD:src/lib.rs: the blob forsrc/lib.rsin the current commit.@{u}: the current branch’s upstream, such asorigin/main.main@{1}andHEAD@{yesterday}: previous values from the reflog.A..B: commits reachable fromBbut not fromA.A...B: commits reachable from either but not both.
Each form except the ranges resolves to one object ID, so commands only need to understand IDs once
the syntax is parsed. The ranges A..B and A...B name sets of commits instead; commands pass them
to a history walk.
girtPartialMissing dated reflogs, previous checkouts, index paths, message searches, range shorthands, pseudorefs and describe output. Cross-worktree aliases are tracked in #550.issue #364
History walks
Section titled “History walks”A history walk visits the ancestors of some commits, optionally excluding everything reachable
from others: git log A..B visits commits reachable from B and stops at those reachable from A.
git rev-list prints the same walk as bare IDs. Log, blame, push (to work out what the server
lacks) and ahead/behind counts all depend on it.
Walks have an order. Date order follows commit timestamps, newest first. Topological order
(--topo-order) guarantees no parent is shown before all of its children, which git log --graph
needs to draw lines correctly. Timestamps can be wrong, so a walk can’t stop just because it has
reached old dates; it has to know the excluded side’s boundary. Without help from a
commit-graph, working out that boundary may
mean visiting much of the excluded side’s history.
girtPartialGit comparisons confirm that the library walk has no date or topological order and isn’t lazy; ranges walk the excluded side’s whole history.issue #416
Merge bases
Section titled “Merge bases”The merge base of two commits is their best common ancestor: the last commit both lines of work
share, where they split. “Best” means no other common ancestor is a descendant of it. After
criss-cross merges, where two branches have each merged the other, there can be several best common
ancestors. git merge-base --all A B lists them.
Merging uses the merge base as the starting point
both sides changed from. A...B means commits on either side of it, and ahead/behind counts are
measured from it.
girtSupportedReturns every best common ancestor.API docs
Ancestry checks
Section titled “Ancestry checks”“Is X an ancestor of Y?” (git merge-base --is-ancestor X Y) answers whether moving a ref from X to
Y is a fast-forward: the new commit builds on the old one, so the move discards nothing. Push
refuses non-fast-forward updates unless forced, and git merge can simply move the branch when the
merge is a fast-forward.
girtSupportedAPI docs