summaryrefslogtreecommitdiff
path: root/Documentation/git-diff-hunks.adoc
blob: 25cab2ea7db8d8b82ddc2c02dd9d897923508c8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
git-diff-hunks(1)
=================

NAME
----
git-diff-hunks - Inspect and manage the diff-hunks store

SYNOPSIS
--------
[synopsis]
git diff-hunks verify
git diff-hunks clear

DESCRIPTION
-----------

The diff-hunks store is a cache of diff hunk coordinates, the line
ranges that changed between two blobs, so that commands
which need them, such as linkgit:git-blame[1] and `git log` and `git diff`
with the `--stat`, `--numstat`, and `--shortstat` formats, can skip
running the diff algorithm, and blame can skip loading the blob
content. (The summary formats still test each pair for binariness,
which can load the blobs.)

The store is a single file, `$GIT_DIR/objects/info/diff-hunks`. Reading is
enabled by default; writing is off by default. A `git diff`, `git log`,
`git show`, or `git diff-tree` that produces one of the stat formats
fills the store as a side effect, but only when writing is enabled for
that run (see "WARMING THE STORE" below), so ordinary reads never
modify the repository. When the store does not have the pair, holds a
different object hash, the file is unreadable, or an object replacement
redirects one of the blobs, the consumer falls back to computing the
diff. A store only speeds up these commands; it never changes their
output.

`git diff-hunks` itself only inspects and manages the file. See
linkgit:gitformat-diff-hunks[5] for the file format.

WARMING THE STORE
-----------------

The store is filled by running ordinary commands with writing enabled.
Turn writing on for a single invocation with the `GIT_DIFF_HUNKS_WRITE`
environment variable, or persistently with the `diffHunks.write`
configuration; the environment variable takes precedence. A repository
owner warms the store by running the diff-producing commands they care
about with writing on, for example:

	GIT_DIFF_HUNKS_WRITE=1 git log --all --stat >/dev/null

A `--stat` walk records one entry per blob pair;
linkgit:git-blame[1] replays the coordinates and the summary formats
sum the counts, so a single warming walk serves both.
A warming run seeds from the existing store and rewrites the file
with the newly computed pairs merged in, so a later run adds to what
earlier runs recorded rather than discarding it.

A walk records only the pairs it diffs. `git log --all --stat` diffs
each commit against its first parent, so a blame that follows a
merge's second parent computes those pairs itself: blame coverage is
partial on history with merges. Warming with a walk that also diffs
the other parents, for example `git log --all -m --stat`, raises
blame coverage at the cost of a larger store and a longer warming
run.

COMMANDS
--------

`verify`::
	Check the integrity of the store: the trailing hash checksum, the
	chunk table of contents, the sort order of the index, and the
	bounds of every entry. Exits with non-zero status if the store is
	corrupt. An absent store is valid.

`clear`::
	Remove the store file.

CORRECTNESS
-----------

A stored result is interchangeable with a freshly computed one because an
entry is keyed by the inputs that determine the diff:

* the object IDs of the old and new blob, so a result is used only for
  the exact contents it was computed from; and
* the diff algorithm and ignore flags (`xdl_opts`) the hunks were
  computed under. A lookup whose `xdl_opts` differ from a stored entry
  misses. This is why, for example, `blame -w` and
  `--diff-algorithm=<algorithm>` (including a per-path
  `diff.<driver>.algorithm`) do not reuse entries recorded under the
  default settings: they change `xdl_opts`.

The context length is not part of the key because only trim-stable
pairs are recorded: pairs whose zero-context trimmed diff and untrimmed
diff are identical, so one entry answers blame (zero context) and the
summary formats (any context) alike. The rare pair where
the zero-context trimming optimization picks a different but
equally valid set of hunks is
never recorded and is always computed.

Some options shape the hunks in ways the key does not express, so a
diff that uses them is excluded from the store in both directions:
break detection (`-B`), `--ignore-matching-lines` (`-I`), and
`--anchored`. `--ignore-blank-lines` is different: it is an ignore
flag and therefore part of the key, but the summary formats exclude
it anyway, because it coalesces hunks differently between the code
path that emits text and the one that replays coordinates, so a
served answer would not match a store-less run.
linkgit:git-blame[1] additionally does not
consult the store for reverse blame, ignored revisions, or paths with a
textconv driver.

The store carries a trailing hash checksum, but readers do not
re-checksum it on every load. As with the commit-graph and
multi-pack-index, the writer fsyncs the file (honoring `core.fsync`) and
commits it atomically, so a committed store is intact; every offset and
count is still bounds-checked as it is read. The checksum is verified by
`git diff-hunks verify`, not on the read path, so structural corruption
that fails a bounds check is read as an absent entry, while a record
that stays within bounds but whose bytes were altered is served until
`verify` detects the mismatch.

CONFIGURATION
-------------

`core.diffHunks`::
	Whether commands read the store. Defaults to true. See
	linkgit:git-config[1].

`diffHunks.write`::
	Whether diff-producing commands write to the store. Defaults to
	false. The `GIT_DIFF_HUNKS_WRITE` environment variable overrides it
	for a single invocation. See linkgit:git-config[1].

Writing the store honors the `core.fsync` configuration through the
`diff-hunks` component; see linkgit:git-config[1].

SEE ALSO
--------
linkgit:git-blame[1],
linkgit:git-log[1],
linkgit:gitformat-diff-hunks[5]

GIT
---
Part of the linkgit:git[1] suite