Skip to content

Commit be733e1

Browse files
committed
Merge branch 'en/merge-tree'
"git merge-tree" learned a new mode where it takes two commits and computes a tree that would result in the merge commit, if the histories leading to these two commits were to be merged. * en/merge-tree: git-merge-tree.txt: add a section on potentional usage mistakes merge-tree: add a --allow-unrelated-histories flag merge-tree: allow `ls-files -u` style info to be NUL terminated merge-ort: optionally produce machine-readable output merge-ort: store more specific conflict information merge-ort: make `path_messages` a strmap to a string_list merge-ort: store messages in a list, not in a single strbuf merge-tree: provide easy access to `ls-files -u` style info merge-tree: provide a list of which files have conflicts merge-ort: remove command-line-centric submodule message from merge-ort merge-ort: provide a merge_get_conflicted_files() helper function merge-tree: support including merge messages in output merge-ort: split out a separate display_update_messages() function merge-tree: implement real merges merge-tree: add option parsing and initial shell for real merge function merge-tree: move logic for existing merge into new function merge-tree: rename merge_trees() to trivial_merge_trees()
2 parents dc6315e + 7260e87 commit be733e1

File tree

8 files changed

+1032
-167
lines changed

8 files changed

+1032
-167
lines changed

Documentation/git-merge-tree.txt

Lines changed: 223 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,237 @@ git-merge-tree(1)
33

44
NAME
55
----
6-
git-merge-tree - Show three-way merge without touching index
6+
git-merge-tree - Perform merge without touching index or working tree
77

88

99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git merge-tree' <base-tree> <branch1> <branch2>
12+
'git merge-tree' [--write-tree] [<options>] <branch1> <branch2>
13+
'git merge-tree' [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)
1314

15+
[[NEWMERGE]]
1416
DESCRIPTION
1517
-----------
16-
Reads three tree-ish, and output trivial merge results and
17-
conflicting stages to the standard output. This is similar to
18-
what three-way 'git read-tree -m' does, but instead of storing the
19-
results in the index, the command outputs the entries to the
20-
standard output.
21-
22-
This is meant to be used by higher level scripts to compute
23-
merge results outside of the index, and stuff the results back into the
24-
index. For this reason, the output from the command omits
25-
entries that match the <branch1> tree.
18+
19+
This command has a modern `--write-tree` mode and a deprecated
20+
`--trivial-merge` mode. With the exception of the
21+
<<DEPMERGE,DEPRECATED DESCRIPTION>> section at the end, the rest of
22+
this documentation describes modern `--write-tree` mode.
23+
24+
Performs a merge, but does not make any new commits and does not read
25+
from or write to either the working tree or index.
26+
27+
The performed merge will use the same feature as the "real"
28+
linkgit:git-merge[1], including:
29+
30+
* three way content merges of individual files
31+
* rename detection
32+
* proper directory/file conflict handling
33+
* recursive ancestor consolidation (i.e. when there is more than one
34+
merge base, creating a virtual merge base by merging the merge bases)
35+
* etc.
36+
37+
After the merge completes, a new toplevel tree object is created. See
38+
`OUTPUT` below for details.
39+
40+
OPTIONS
41+
-------
42+
43+
-z::
44+
Do not quote filenames in the <Conflicted file info> section,
45+
and end each filename with a NUL character rather than
46+
newline. Also begin the messages section with a NUL character
47+
instead of a newline. See <<OUTPUT>> below for more information.
48+
49+
--name-only::
50+
In the Conflicted file info section, instead of writing a list
51+
of (mode, oid, stage, path) tuples to output for conflicted
52+
files, just provide a list of filenames with conflicts (and
53+
do not list filenames multiple times if they have multiple
54+
conflicting stages).
55+
56+
--[no-]messages::
57+
Write any informational messages such as "Auto-merging <path>"
58+
or CONFLICT notices to the end of stdout. If unspecified, the
59+
default is to include these messages if there are merge
60+
conflicts, and to omit them otherwise.
61+
62+
--allow-unrelated-histories::
63+
merge-tree will by default error out if the two branches specified
64+
share no common history. This flag can be given to override that
65+
check and make the merge proceed anyway.
66+
67+
[[OUTPUT]]
68+
OUTPUT
69+
------
70+
71+
For a successful merge, the output from git-merge-tree is simply one
72+
line:
73+
74+
<OID of toplevel tree>
75+
76+
Whereas for a conflicted merge, the output is by default of the form:
77+
78+
<OID of toplevel tree>
79+
<Conflicted file info>
80+
<Informational messages>
81+
82+
These are discussed individually below.
83+
84+
[[OIDTLT]]
85+
OID of toplevel tree
86+
~~~~~~~~~~~~~~~~~~~~
87+
88+
This is a tree object that represents what would be checked out in the
89+
working tree at the end of `git merge`. If there were conflicts, then
90+
files within this tree may have embedded conflict markers. This section
91+
is always followed by a newline (or NUL if `-z` is passed).
92+
93+
[[CFI]]
94+
Conflicted file info
95+
~~~~~~~~~~~~~~~~~~~~
96+
97+
This is a sequence of lines with the format
98+
99+
<mode> <object> <stage> <filename>
100+
101+
The filename will be quoted as explained for the configuration
102+
variable `core.quotePath` (see linkgit:git-config[1]). However, if
103+
the `--name-only` option is passed, the mode, object, and stage will
104+
be omitted. If `-z` is passed, the "lines" are terminated by a NUL
105+
character instead of a newline character.
106+
107+
[[IM]]
108+
Informational messages
109+
~~~~~~~~~~~~~~~~~~~~~~
110+
111+
This always starts with a blank line (or NUL if `-z` is passed) to
112+
separate it from the previous sections, and then has free-form
113+
messages about the merge, such as:
114+
115+
* "Auto-merging <file>"
116+
* "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
117+
* "Failed to merge submodule <submodule> (<reason>)"
118+
* "Warning: cannot merge binary files: <filename>"
119+
120+
Note that these free-form messages will never have a NUL character
121+
in or between them, even if -z is passed. It is simply a large block
122+
of text taking up the remainder of the output.
123+
124+
EXIT STATUS
125+
-----------
126+
127+
For a successful, non-conflicted merge, the exit status is 0. When the
128+
merge has conflicts, the exit status is 1. If the merge is not able to
129+
complete (or start) due to some kind of error, the exit status is
130+
something other than 0 or 1 (and the output is unspecified).
131+
132+
USAGE NOTES
133+
-----------
134+
135+
This command is intended as low-level plumbing, similar to
136+
linkgit:git-hash-object[1], linkgit:git-mktree[1],
137+
linkgit:git-commit-tree[1], linkgit:git-write-tree[1],
138+
linkgit:git-update-ref[1], and linkgit:git-mktag[1]. Thus, it can be
139+
used as a part of a series of steps such as:
140+
141+
NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2)
142+
test $? -eq 0 || die "There were conflicts..."
143+
NEWCOMMIT=$(git commit-tree $NEWTREE -p $BRANCH1 -p $BRANCH2)
144+
git update-ref $BRANCH1 $NEWCOMMIT
145+
146+
Note that when the exit status is non-zero, `NEWTREE` in this sequence
147+
will contain a lot more output than just a tree.
148+
149+
For conflicts, the output includes the same information that you'd get
150+
with linkgit:git-merge[1]:
151+
152+
* what would be written to the working tree (the
153+
<<OIDTLT,OID of toplevel tree>>)
154+
* the higher order stages that would be written to the index (the
155+
<<CFI,Conflicted file info>>)
156+
* any messages that would have been printed to stdout (the
157+
<<IM,Informational messages>>)
158+
159+
MISTAKES TO AVOID
160+
-----------------
161+
162+
Do NOT look through the resulting toplevel tree to try to find which
163+
files conflict; parse the <<CFI,Conflicted file info>> section instead.
164+
Not only would parsing an entire tree be horrendously slow in large
165+
repositories, there are numerous types of conflicts not representable by
166+
conflict markers (modify/delete, mode conflict, binary file changed on
167+
both sides, file/directory conflicts, various rename conflict
168+
permutations, etc.)
169+
170+
Do NOT interpret an empty <<CFI,Conflicted file info>> list as a clean
171+
merge; check the exit status. A merge can have conflicts without having
172+
individual files conflict (there are a few types of directory rename
173+
conflicts that fall into this category, and others might also be added
174+
in the future).
175+
176+
Do NOT attempt to guess or make the user guess the conflict types from
177+
the <<CFI,Conflicted file info>> list. The information there is
178+
insufficient to do so. For example: Rename/rename(1to2) conflicts (both
179+
sides renamed the same file differently) will result in three different
180+
file having higher order stages (but each only has one higher order
181+
stage), with no way (short of the <<IM,Informational messages>> section)
182+
to determine which three files are related. File/directory conflicts
183+
also result in a file with exactly one higher order stage.
184+
Possibly-involved-in-directory-rename conflicts (when
185+
"merge.directoryRenames" is unset or set to "conflicts") also result in
186+
a file with exactly one higher order stage. In all cases, the
187+
<<IM,Informational messages>> section has the necessary info, though it
188+
is not designed to be machine parseable.
189+
190+
Do NOT assume that each paths from <<CFI,Conflicted file info>>, and
191+
the logical conflicts in the <<IM,Informational messages>> have a
192+
one-to-one mapping, nor that there is a one-to-many mapping, nor a
193+
many-to-one mapping. Many-to-many mappings exist, meaning that each
194+
path can have many logical conflict types in a single merge, and each
195+
logical conflict type can affect many paths.
196+
197+
Do NOT assume all filenames listed in the <<IM,Informational messages>>
198+
section had conflicts. Messages can be included for files that have no
199+
conflicts, such as "Auto-merging <file>".
200+
201+
AVOID taking the OIDS from the <<CFI,Conflicted file info>> and
202+
re-merging them to present the conflicts to the user. This will lose
203+
information. Instead, look up the version of the file found within the
204+
<<OIDTLT,OID of toplevel tree>> and show that instead. In particular,
205+
the latter will have conflict markers annotated with the original
206+
branch/commit being merged and, if renames were involved, the original
207+
filename. While you could include the original branch/commit in the
208+
conflict marker annotations when re-merging, the original filename is
209+
not available from the <<CFI,Conflicted file info>> and thus you would
210+
be losing information that might help the user resolve the conflict.
211+
212+
[[DEPMERGE]]
213+
DEPRECATED DESCRIPTION
214+
----------------------
215+
216+
Per the <<NEWMERGE,DESCRIPTION>> and unlike the rest of this
217+
documentation, this section describes the deprecated `--trivial-merge`
218+
mode.
219+
220+
Other than the optional `--trivial-merge`, this mode accepts no
221+
options.
222+
223+
This mode reads three tree-ish, and outputs trivial merge results and
224+
conflicting stages to the standard output in a semi-diff format.
225+
Since this was designed for higher level scripts to consume and merge
226+
the results back into the index, it omits entries that match
227+
<branch1>. The result of this second form is similar to what
228+
three-way 'git read-tree -m' does, but instead of storing the results
229+
in the index, the command outputs the entries to the standard output.
230+
231+
This form not only has limited applicability (a trivial merge cannot
232+
handle content merges of individual files, rename detection, proper
233+
directory/file conflict handling, etc.), the output format is also
234+
difficult to work with, and it will generally be less performant than
235+
the first form even on successful merges (especially if working in
236+
large repositories).
26237

27238
GIT
28239
---

0 commit comments

Comments
 (0)