mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
Merge branch 'en/zdiff3'
"Zealous diff3" style of merge conflict presentation has been added. * en/zdiff3: update documentation for new zdiff3 conflictStyle xdiff: implement a zealous diff3, or "zdiff3"
This commit is contained in:
commit
4ce498baa3
|
@ -4,7 +4,14 @@ merge.conflictStyle::
|
|||
shows a `<<<<<<<` conflict marker, changes made by one side,
|
||||
a `=======` marker, changes made by the other side, and then
|
||||
a `>>>>>>>` marker. An alternate style, "diff3", adds a `|||||||`
|
||||
marker and the original text before the `=======` marker.
|
||||
marker and the original text before the `=======` marker. The
|
||||
"merge" style tends to produce smaller conflict regions than diff3,
|
||||
both because of the exclusion of the original text, and because
|
||||
when a subset of lines match on the two sides they are just pulled
|
||||
out of the conflict region. Another alternate style, "zdiff3", is
|
||||
similar to diff3 but removes matching lines on the two sides from
|
||||
the conflict region when those matching lines appear near either
|
||||
the beginning or end of a conflict region.
|
||||
|
||||
merge.defaultToUpstream::
|
||||
If merge is called without any commit argument, merge the upstream
|
||||
|
|
|
@ -266,8 +266,7 @@ When switching branches with `--merge`, staged changes may be lost.
|
|||
The same as `--merge` option above, but changes the way the
|
||||
conflicting hunks are presented, overriding the
|
||||
`merge.conflictStyle` configuration variable. Possible values are
|
||||
"merge" (default) and "diff3" (in addition to what is shown by
|
||||
"merge" style, shows the original contents).
|
||||
"merge" (default), "diff3", and "zdiff3".
|
||||
|
||||
-p::
|
||||
--patch::
|
||||
|
|
|
@ -70,6 +70,9 @@ OPTIONS
|
|||
--diff3::
|
||||
Show conflicts in "diff3" style.
|
||||
|
||||
--zdiff3::
|
||||
Show conflicts in "zdiff3" style.
|
||||
|
||||
--ours::
|
||||
--theirs::
|
||||
--union::
|
||||
|
|
|
@ -240,7 +240,8 @@ from the RCS suite to present such a conflicted hunk, like this:
|
|||
|
||||
------------
|
||||
Here are lines that are either unchanged from the common
|
||||
ancestor, or cleanly resolved because only one side changed.
|
||||
ancestor, or cleanly resolved because only one side changed,
|
||||
or cleanly resolved because both sides changed the same way.
|
||||
<<<<<<< yours:sample.txt
|
||||
Conflict resolution is hard;
|
||||
let's go shopping.
|
||||
|
@ -261,16 +262,37 @@ side wants to say it is hard and you'd prefer to go shopping, while the
|
|||
other side wants to claim it is easy.
|
||||
|
||||
An alternative style can be used by setting the "merge.conflictStyle"
|
||||
configuration variable to "diff3". In "diff3" style, the above conflict
|
||||
may look like this:
|
||||
configuration variable to either "diff3" or "zdiff3". In "diff3"
|
||||
style, the above conflict may look like this:
|
||||
|
||||
------------
|
||||
Here are lines that are either unchanged from the common
|
||||
ancestor, or cleanly resolved because only one side changed.
|
||||
ancestor, or cleanly resolved because only one side changed,
|
||||
<<<<<<< yours:sample.txt
|
||||
or cleanly resolved because both sides changed the same way.
|
||||
Conflict resolution is hard;
|
||||
let's go shopping.
|
||||
||||||| base:sample.txt
|
||||
or cleanly resolved because both sides changed identically.
|
||||
Conflict resolution is hard.
|
||||
=======
|
||||
or cleanly resolved because both sides changed the same way.
|
||||
Git makes conflict resolution easy.
|
||||
>>>>>>> theirs:sample.txt
|
||||
And here is another line that is cleanly resolved or unmodified.
|
||||
------------
|
||||
|
||||
while in "zdiff3" style, it may look like this:
|
||||
|
||||
------------
|
||||
Here are lines that are either unchanged from the common
|
||||
ancestor, or cleanly resolved because only one side changed,
|
||||
or cleanly resolved because both sides changed the same way.
|
||||
<<<<<<< yours:sample.txt
|
||||
Conflict resolution is hard;
|
||||
let's go shopping.
|
||||
|||||||
|
||||
||||||| base:sample.txt
|
||||
or cleanly resolved because both sides changed identically.
|
||||
Conflict resolution is hard.
|
||||
=======
|
||||
Git makes conflict resolution easy.
|
||||
|
|
|
@ -714,9 +714,9 @@ information about the rebased commits and their parents (and instead
|
|||
generates new fake commits based off limited information in the
|
||||
generated patches), those commits cannot be identified; instead it has
|
||||
to fall back to a commit summary. Also, when merge.conflictStyle is
|
||||
set to diff3, the apply backend will use "constructed merge base" to
|
||||
label the content from the merge base, and thus provide no information
|
||||
about the merge base commit whatsoever.
|
||||
set to diff3 or zdiff3, the apply backend will use "constructed merge
|
||||
base" to label the content from the merge base, and thus provide no
|
||||
information about the merge base commit whatsoever.
|
||||
|
||||
The merge backend works with the full commits on both sides of history
|
||||
and thus has no such limitations.
|
||||
|
|
|
@ -92,8 +92,7 @@ in linkgit:git-checkout[1] for details.
|
|||
The same as `--merge` option above, but changes the way the
|
||||
conflicting hunks are presented, overriding the
|
||||
`merge.conflictStyle` configuration variable. Possible values
|
||||
are "merge" (default) and "diff3" (in addition to what is
|
||||
shown by "merge" style, shows the original contents).
|
||||
are "merge" (default), "diff3", and "zdiff3".
|
||||
|
||||
--ignore-unmerged::
|
||||
When restoring files on the working tree from the index, do
|
||||
|
|
|
@ -137,8 +137,7 @@ should result in deletion of the path).
|
|||
The same as `--merge` option above, but changes the way the
|
||||
conflicting hunks are presented, overriding the
|
||||
`merge.conflictStyle` configuration variable. Possible values are
|
||||
"merge" (default) and "diff3" (in addition to what is shown by
|
||||
"merge" style, shows the original contents).
|
||||
"merge" (default), "diff3", and "zdiff3".
|
||||
|
||||
-q::
|
||||
--quiet::
|
||||
|
|
|
@ -14,9 +14,9 @@ conflicts before writing them to the rerere database.
|
|||
|
||||
Different conflict styles and branch names are normalized by stripping
|
||||
the labels from the conflict markers, and removing the common ancestor
|
||||
version from the `diff3` conflict style. Branches that are merged
|
||||
in different order are normalized by sorting the conflict hunks. More
|
||||
on each of those steps in the following sections.
|
||||
version from the `diff3` or `zdiff3` conflict styles. Branches that
|
||||
are merged in different order are normalized by sorting the conflict
|
||||
hunks. More on each of those steps in the following sections.
|
||||
|
||||
Once these two normalization operations are applied, a conflict ID is
|
||||
calculated based on the normalized conflict, which is later used by
|
||||
|
@ -42,8 +42,8 @@ get a conflict like the following:
|
|||
>>>>>>> AC
|
||||
|
||||
Doing the analogous with AC2 (forking a branch ABAC2 off of branch AB
|
||||
and then merging branch AC2 into it), using the diff3 conflict style,
|
||||
we get a conflict like the following:
|
||||
and then merging branch AC2 into it), using the diff3 or zdiff3
|
||||
conflict style, we get a conflict like the following:
|
||||
|
||||
<<<<<<< HEAD
|
||||
B
|
||||
|
|
|
@ -1536,7 +1536,7 @@ static struct option *add_common_options(struct checkout_opts *opts,
|
|||
OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
|
||||
OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
|
||||
OPT_STRING(0, "conflict", &opts->conflict_style, N_("style"),
|
||||
N_("conflict style (merge or diff3)")),
|
||||
N_("conflict style (merge, diff3, or zdiff3)")),
|
||||
OPT_END()
|
||||
};
|
||||
struct option *newopts = parse_options_concat(prevopts, options);
|
||||
|
|
|
@ -34,6 +34,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
|
|||
struct option options[] = {
|
||||
OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
|
||||
OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
|
||||
OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
|
||||
XDL_MERGE_ZEALOUS_DIFF3),
|
||||
OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
|
||||
XDL_MERGE_FAVOR_OURS),
|
||||
OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
|
||||
|
|
|
@ -1566,7 +1566,7 @@ _git_checkout ()
|
|||
|
||||
case "$cur" in
|
||||
--conflict=*)
|
||||
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
||||
__gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
|
||||
;;
|
||||
--*)
|
||||
__gitcomp_builtin checkout
|
||||
|
@ -2437,7 +2437,7 @@ _git_switch ()
|
|||
|
||||
case "$cur" in
|
||||
--conflict=*)
|
||||
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
||||
__gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
|
||||
;;
|
||||
--*)
|
||||
__gitcomp_builtin switch
|
||||
|
@ -2877,7 +2877,7 @@ _git_restore ()
|
|||
|
||||
case "$cur" in
|
||||
--conflict=*)
|
||||
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
||||
__gitcomp "diff3 merge zdiff3" "" "${cur##--conflict=}"
|
||||
;;
|
||||
--source=*)
|
||||
__git_complete_refs --cur="${cur##--source=}"
|
||||
|
|
|
@ -211,4 +211,94 @@ test_expect_success 'rebase --apply describes fake ancestor base' '
|
|||
)
|
||||
'
|
||||
|
||||
test_setup_zdiff3 () {
|
||||
test_create_repo zdiff3 &&
|
||||
(
|
||||
cd zdiff3 &&
|
||||
|
||||
test_write_lines 1 2 3 4 5 6 7 8 9 >basic &&
|
||||
test_write_lines 1 2 3 AA 4 5 BB 6 7 8 >middle-common &&
|
||||
test_write_lines 1 2 3 4 5 6 7 8 9 >interesting &&
|
||||
test_write_lines 1 2 3 4 5 6 7 8 9 >evil &&
|
||||
|
||||
git add basic middle-common interesting evil &&
|
||||
git commit -m base &&
|
||||
|
||||
git branch left &&
|
||||
git branch right &&
|
||||
|
||||
git checkout left &&
|
||||
test_write_lines 1 2 3 4 A B C D E 7 8 9 >basic &&
|
||||
test_write_lines 1 2 3 CC 4 5 DD 6 7 8 >middle-common &&
|
||||
test_write_lines 1 2 3 4 A B C D E F G H I J 7 8 9 >interesting &&
|
||||
test_write_lines 1 2 3 4 X A B C 7 8 9 >evil &&
|
||||
git add -u &&
|
||||
git commit -m letters &&
|
||||
|
||||
git checkout right &&
|
||||
test_write_lines 1 2 3 4 A X C Y E 7 8 9 >basic &&
|
||||
test_write_lines 1 2 3 EE 4 5 FF 6 7 8 >middle-common &&
|
||||
test_write_lines 1 2 3 4 A B C 5 6 G H I J 7 8 9 >interesting &&
|
||||
test_write_lines 1 2 3 4 Y A B C B C 7 8 9 >evil &&
|
||||
git add -u &&
|
||||
git commit -m permuted
|
||||
)
|
||||
}
|
||||
|
||||
test_expect_success 'check zdiff3 markers' '
|
||||
test_setup_zdiff3 &&
|
||||
(
|
||||
cd zdiff3 &&
|
||||
|
||||
git checkout left^0 &&
|
||||
|
||||
base=$(git rev-parse --short HEAD^1) &&
|
||||
test_must_fail git -c merge.conflictstyle=zdiff3 merge -s recursive right^0 &&
|
||||
|
||||
test_write_lines 1 2 3 4 A \
|
||||
"<<<<<<< HEAD" B C D \
|
||||
"||||||| $base" 5 6 \
|
||||
======= X C Y \
|
||||
">>>>>>> right^0" \
|
||||
E 7 8 9 \
|
||||
>expect &&
|
||||
test_cmp expect basic &&
|
||||
|
||||
test_write_lines 1 2 3 \
|
||||
"<<<<<<< HEAD" CC \
|
||||
"||||||| $base" AA \
|
||||
======= EE \
|
||||
">>>>>>> right^0" \
|
||||
4 5 \
|
||||
"<<<<<<< HEAD" DD \
|
||||
"||||||| $base" BB \
|
||||
======= FF \
|
||||
">>>>>>> right^0" \
|
||||
6 7 8 \
|
||||
>expect &&
|
||||
test_cmp expect middle-common &&
|
||||
|
||||
test_write_lines 1 2 3 4 A B C \
|
||||
"<<<<<<< HEAD" D E F \
|
||||
"||||||| $base" 5 6 \
|
||||
======= 5 6 \
|
||||
">>>>>>> right^0" \
|
||||
G H I J 7 8 9 \
|
||||
>expect &&
|
||||
test_cmp expect interesting &&
|
||||
|
||||
# Not passing this one yet; the common "B C" lines is still
|
||||
# being left in the conflict blocks on the left and right
|
||||
# sides.
|
||||
test_write_lines 1 2 3 4 \
|
||||
"<<<<<<< HEAD" X A \
|
||||
"||||||| $base" 5 6 \
|
||||
======= Y A B C \
|
||||
">>>>>>> right^0" \
|
||||
B C 7 8 9 \
|
||||
>expect &&
|
||||
test_cmp expect evil
|
||||
)
|
||||
'
|
||||
|
||||
test_done
|
||||
|
|
|
@ -313,6 +313,8 @@ int git_xmerge_config(const char *var, const char *value, void *cb)
|
|||
die("'%s' is not a boolean", var);
|
||||
if (!strcmp(value, "diff3"))
|
||||
git_xmerge_style = XDL_MERGE_DIFF3;
|
||||
else if (!strcmp(value, "zdiff3"))
|
||||
git_xmerge_style = XDL_MERGE_ZEALOUS_DIFF3;
|
||||
else if (!strcmp(value, "merge"))
|
||||
git_xmerge_style = 0;
|
||||
/*
|
||||
|
|
|
@ -66,6 +66,7 @@ extern "C" {
|
|||
|
||||
/* merge output styles */
|
||||
#define XDL_MERGE_DIFF3 1
|
||||
#define XDL_MERGE_ZEALOUS_DIFF3 2
|
||||
|
||||
typedef struct s_mmfile {
|
||||
char *ptr;
|
||||
|
|
|
@ -230,7 +230,7 @@ static int fill_conflict_hunk(xdfenv_t *xe1, const char *name1,
|
|||
size += xdl_recs_copy(xe1, m->i1, m->chg1, needs_cr, 1,
|
||||
dest ? dest + size : NULL);
|
||||
|
||||
if (style == XDL_MERGE_DIFF3) {
|
||||
if (style == XDL_MERGE_DIFF3 || style == XDL_MERGE_ZEALOUS_DIFF3) {
|
||||
/* Shared preimage */
|
||||
if (!dest) {
|
||||
size += marker_size + 1 + needs_cr + marker3_size;
|
||||
|
@ -322,6 +322,40 @@ static int xdl_fill_merge_buffer(xdfenv_t *xe1, const char *name1,
|
|||
return size;
|
||||
}
|
||||
|
||||
static int recmatch(xrecord_t *rec1, xrecord_t *rec2, unsigned long flags)
|
||||
{
|
||||
return xdl_recmatch(rec1->ptr, rec1->size,
|
||||
rec2->ptr, rec2->size, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove any common lines from the beginning and end of the conflicted region.
|
||||
*/
|
||||
static void xdl_refine_zdiff3_conflicts(xdfenv_t *xe1, xdfenv_t *xe2, xdmerge_t *m,
|
||||
xpparam_t const *xpp)
|
||||
{
|
||||
xrecord_t **rec1 = xe1->xdf2.recs, **rec2 = xe2->xdf2.recs;
|
||||
for (; m; m = m->next) {
|
||||
/* let's handle just the conflicts */
|
||||
if (m->mode)
|
||||
continue;
|
||||
|
||||
while(m->chg1 && m->chg2 &&
|
||||
recmatch(rec1[m->i1], rec2[m->i2], xpp->flags)) {
|
||||
m->chg1--;
|
||||
m->chg2--;
|
||||
m->i1++;
|
||||
m->i2++;
|
||||
}
|
||||
while (m->chg1 && m->chg2 &&
|
||||
recmatch(rec1[m->i1 + m->chg1 - 1],
|
||||
rec2[m->i2 + m->chg2 - 1], xpp->flags)) {
|
||||
m->chg1--;
|
||||
m->chg2--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Sometimes, changes are not quite identical, but differ in only a few
|
||||
* lines. Try hard to show only these few lines as conflicting.
|
||||
|
@ -482,7 +516,22 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
|
|||
int style = xmp->style;
|
||||
int favor = xmp->favor;
|
||||
|
||||
if (style == XDL_MERGE_DIFF3) {
|
||||
/*
|
||||
* XDL_MERGE_DIFF3 does not attempt to refine conflicts by looking
|
||||
* at common areas of sides 1 & 2, because the base (side 0) does
|
||||
* not match and is being shown. Similarly, simplification of
|
||||
* non-conflicts is also skipped due to the skipping of conflict
|
||||
* refinement.
|
||||
*
|
||||
* XDL_MERGE_ZEALOUS_DIFF3, on the other hand, will attempt to
|
||||
* refine conflicts looking for common areas of sides 1 & 2.
|
||||
* However, since the base is being shown and does not match,
|
||||
* it will only look for common areas at the beginning or end
|
||||
* of the conflict block. Since XDL_MERGE_ZEALOUS_DIFF3's
|
||||
* conflict refinement is much more limited in this fashion, the
|
||||
* conflict simplification will be skipped.
|
||||
*/
|
||||
if (style == XDL_MERGE_DIFF3 || style == XDL_MERGE_ZEALOUS_DIFF3) {
|
||||
/*
|
||||
* "diff3 -m" output does not make sense for anything
|
||||
* more aggressive than XDL_MERGE_EAGER.
|
||||
|
@ -603,10 +652,12 @@ static int xdl_do_merge(xdfenv_t *xe1, xdchange_t *xscr1,
|
|||
if (!changes)
|
||||
changes = c;
|
||||
/* refine conflicts */
|
||||
if (XDL_MERGE_ZEALOUS <= level &&
|
||||
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
|
||||
xdl_simplify_non_conflicts(xe1, changes,
|
||||
XDL_MERGE_ZEALOUS < level) < 0)) {
|
||||
if (style == XDL_MERGE_ZEALOUS_DIFF3) {
|
||||
xdl_refine_zdiff3_conflicts(xe1, xe2, changes, xpp);
|
||||
} else if (XDL_MERGE_ZEALOUS <= level &&
|
||||
(xdl_refine_conflicts(xe1, xe2, changes, xpp) < 0 ||
|
||||
xdl_simplify_non_conflicts(xe1, changes,
|
||||
XDL_MERGE_ZEALOUS < level) < 0)) {
|
||||
xdl_cleanup_merge(changes);
|
||||
return -1;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue