Skip to content

Commit 16b8a3e

Browse files
committed
Merge branch 'jn/merge-diff3-label'
* jn/merge-diff3-label: merge-recursive: add a label for ancestor cherry-pick, revert: add a label for ancestor revert: clarify label on conflict hunks compat: add mempcpy() checkout -m --conflict=diff3: add a label for ancestor merge_trees(): add ancestor label parameter for diff3-style output merge_file(): add comment explaining behavior wrt conflict style checkout --conflict=diff3: add a label for ancestor ll_merge(): add ancestor label parameter for diff3-style output merge-file --diff3: add a label for ancestor xdl_merge(): move file1 and file2 labels to xmparam structure xdl_merge(): add optional ancestor label to diff3-style output tests: document cherry-pick behavior in face of conflicts tests: document format of conflicts from checkout -m Conflicts: builtin/revert.c
2 parents 40a56f4 + 7ca56aa commit 16b8a3e

15 files changed

+405
-79
lines changed

builtin/checkout.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ static int checkout_merged(int pos, struct checkout *state)
149149
read_mmblob(&ours, active_cache[pos+1]->sha1);
150150
read_mmblob(&theirs, active_cache[pos+2]->sha1);
151151

152-
status = ll_merge(&result_buf, path, &ancestor,
152+
status = ll_merge(&result_buf, path, &ancestor, "base",
153153
&ours, "ours", &theirs, "theirs", 0);
154154
free(ancestor.ptr);
155155
free(ours.ptr);
@@ -439,6 +439,7 @@ static int merge_working_tree(struct checkout_opts *opts,
439439
ret = reset_tree(new->commit->tree, opts, 1);
440440
if (ret)
441441
return ret;
442+
o.ancestor = old->name;
442443
o.branch1 = new->name;
443444
o.branch2 = "local";
444445
merge_trees(&o, new->commit->tree, work,

builtin/merge-file.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
7777
argv[i]);
7878
}
7979

80-
ret = xdl_merge(mmfs + 1, mmfs + 0, names[0], mmfs + 2, names[2],
81-
&xmp, &result);
80+
xmp.ancestor = names[1];
81+
xmp.file1 = names[0];
82+
xmp.file2 = names[2];
83+
ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
8284

8385
for (i = 0; i < 3; i++)
8486
free(mmfs[i].ptr);

builtin/revert.c

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ static const char *me;
4646

4747
#define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
4848

49+
static char *get_encoding(const char *message);
50+
4951
static void parse_args(int argc, const char **argv)
5052
{
5153
const char * const * usage_str =
@@ -85,33 +87,64 @@ static void parse_args(int argc, const char **argv)
8587
exit(1);
8688
}
8789

88-
static char *get_oneline(const char *message)
90+
struct commit_message {
91+
char *parent_label;
92+
const char *label;
93+
const char *subject;
94+
char *reencoded_message;
95+
const char *message;
96+
};
97+
98+
static int get_message(const char *raw_message, struct commit_message *out)
8999
{
90-
char *result;
91-
const char *p = message, *abbrev, *eol;
100+
const char *encoding;
101+
const char *p, *abbrev, *eol;
102+
char *q;
92103
int abbrev_len, oneline_len;
93104

94-
if (!p)
95-
die ("Could not read commit message of %s",
96-
sha1_to_hex(commit->object.sha1));
105+
if (!raw_message)
106+
return -1;
107+
encoding = get_encoding(raw_message);
108+
if (!encoding)
109+
encoding = "UTF-8";
110+
if (!git_commit_encoding)
111+
git_commit_encoding = "UTF-8";
112+
if ((out->reencoded_message = reencode_string(raw_message,
113+
git_commit_encoding, encoding)))
114+
out->message = out->reencoded_message;
115+
116+
abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
117+
abbrev_len = strlen(abbrev);
118+
119+
/* Find beginning and end of commit subject. */
120+
p = out->message;
97121
while (*p && (*p != '\n' || p[1] != '\n'))
98122
p++;
99-
100123
if (*p) {
101124
p += 2;
102125
for (eol = p + 1; *eol && *eol != '\n'; eol++)
103126
; /* do nothing */
104127
} else
105128
eol = p;
106-
abbrev = find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV);
107-
abbrev_len = strlen(abbrev);
108129
oneline_len = eol - p;
109-
result = xmalloc(abbrev_len + 5 + oneline_len);
110-
memcpy(result, abbrev, abbrev_len);
111-
memcpy(result + abbrev_len, "... ", 4);
112-
memcpy(result + abbrev_len + 4, p, oneline_len);
113-
result[abbrev_len + 4 + oneline_len] = '\0';
114-
return result;
130+
131+
out->parent_label = xmalloc(strlen("parent of ") + abbrev_len +
132+
strlen("... ") + oneline_len + 1);
133+
q = out->parent_label;
134+
q = mempcpy(q, "parent of ", strlen("parent of "));
135+
out->label = q;
136+
q = mempcpy(q, abbrev, abbrev_len);
137+
q = mempcpy(q, "... ", strlen("... "));
138+
out->subject = q;
139+
q = mempcpy(q, p, oneline_len);
140+
*q = '\0';
141+
return 0;
142+
}
143+
144+
static void free_message(struct commit_message *msg)
145+
{
146+
free(msg->parent_label);
147+
free(msg->reencoded_message);
115148
}
116149

117150
static char *get_encoding(const char *message)
@@ -271,9 +304,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
271304
{
272305
unsigned char head[20];
273306
struct commit *base, *next, *parent;
307+
const char *base_label, *next_label;
274308
int i, index_fd, clean;
275-
char *oneline, *reencoded_message = NULL;
276-
const char *message, *encoding;
309+
struct commit_message msg = { NULL, NULL, NULL, NULL, NULL };
277310
char *defmsg = NULL;
278311
struct merge_options o;
279312
struct tree *result, *next_tree, *base_tree, *head_tree;
@@ -349,14 +382,14 @@ static int revert_or_cherry_pick(int argc, const char **argv)
349382
if (allow_ff && !hashcmp(parent->object.sha1, head))
350383
return fast_forward_to(commit->object.sha1, head);
351384

352-
if (!(message = commit->buffer))
353-
die ("Cannot get commit message for %s",
354-
sha1_to_hex(commit->object.sha1));
355-
356385
if (parent && parse_commit(parent) < 0)
357386
die("%s: cannot parse parent commit %s",
358387
me, sha1_to_hex(parent->object.sha1));
359388

389+
if (get_message(commit->buffer, &msg) != 0)
390+
die("Cannot get commit message for %s",
391+
sha1_to_hex(commit->object.sha1));
392+
360393
/*
361394
* "commit" is an existing commit. We would want to apply
362395
* the difference it introduces since its first parent "prev"
@@ -368,26 +401,15 @@ static int revert_or_cherry_pick(int argc, const char **argv)
368401
msg_fd = hold_lock_file_for_update(&msg_file, defmsg,
369402
LOCK_DIE_ON_ERROR);
370403

371-
encoding = get_encoding(message);
372-
if (!encoding)
373-
encoding = "UTF-8";
374-
if (!git_commit_encoding)
375-
git_commit_encoding = "UTF-8";
376-
if ((reencoded_message = reencode_string(message,
377-
git_commit_encoding, encoding)))
378-
message = reencoded_message;
379-
380-
oneline = get_oneline(message);
381-
382404
index_fd = hold_locked_index(&index_lock, 1);
383405

384406
if (action == REVERT) {
385-
char *oneline_body = strchr(oneline, ' ');
386-
387407
base = commit;
408+
base_label = msg.label;
388409
next = parent;
410+
next_label = msg.parent_label;
389411
add_to_msg("Revert \"");
390-
add_to_msg(oneline_body + 1);
412+
add_to_msg(msg.subject);
391413
add_to_msg("\"\n\nThis reverts commit ");
392414
add_to_msg(sha1_to_hex(commit->object.sha1));
393415

@@ -398,9 +420,11 @@ static int revert_or_cherry_pick(int argc, const char **argv)
398420
add_to_msg(".\n");
399421
} else {
400422
base = parent;
423+
base_label = msg.parent_label;
401424
next = commit;
402-
set_author_ident_env(message);
403-
add_message_to_msg(message);
425+
next_label = msg.label;
426+
set_author_ident_env(msg.message);
427+
add_message_to_msg(msg.message);
404428
if (no_replay) {
405429
add_to_msg("(cherry picked from commit ");
406430
add_to_msg(sha1_to_hex(commit->object.sha1));
@@ -410,8 +434,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
410434

411435
read_cache();
412436
init_merge_options(&o);
437+
o.ancestor = base ? base_label : "(empty tree)";
413438
o.branch1 = "HEAD";
414-
o.branch2 = oneline;
439+
o.branch2 = next ? next_label : "(empty tree)";
415440

416441
head_tree = parse_tree_indirect(head);
417442
next_tree = next ? next->tree : empty_tree();
@@ -475,7 +500,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
475500
args[i] = NULL;
476501
return execv_git_cmd(args);
477502
}
478-
free(reencoded_message);
503+
free_message(&msg);
479504
free(defmsg);
480505

481506
return 0;

git-compat-util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ extern int git_vsnprintf(char *str, size_t maxsize,
332332
#ifdef __GLIBC_PREREQ
333333
#if __GLIBC_PREREQ(2, 1)
334334
#define HAVE_STRCHRNUL
335+
#define HAVE_MEMPCPY
335336
#endif
336337
#endif
337338

@@ -345,6 +346,14 @@ static inline char *gitstrchrnul(const char *s, int c)
345346
}
346347
#endif
347348

349+
#ifndef HAVE_MEMPCPY
350+
#define mempcpy gitmempcpy
351+
static inline void *gitmempcpy(void *dest, const void *src, size_t n)
352+
{
353+
return (char *)memcpy(dest, src, n) + n;
354+
}
355+
#endif
356+
348357
extern void release_pack_memory(size_t, int);
349358

350359
extern char *xstrdup(const char *str);

ll-merge.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct ll_merge_driver;
1515
typedef int (*ll_merge_fn)(const struct ll_merge_driver *,
1616
mmbuffer_t *result,
1717
const char *path,
18-
mmfile_t *orig,
18+
mmfile_t *orig, const char *orig_name,
1919
mmfile_t *src1, const char *name1,
2020
mmfile_t *src2, const char *name2,
2121
int flag,
@@ -36,7 +36,7 @@ struct ll_merge_driver {
3636
static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
3737
mmbuffer_t *result,
3838
const char *path_unused,
39-
mmfile_t *orig,
39+
mmfile_t *orig, const char *orig_name,
4040
mmfile_t *src1, const char *name1,
4141
mmfile_t *src2, const char *name2,
4242
int flag, int marker_size)
@@ -57,7 +57,7 @@ static int ll_binary_merge(const struct ll_merge_driver *drv_unused,
5757
static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
5858
mmbuffer_t *result,
5959
const char *path,
60-
mmfile_t *orig,
60+
mmfile_t *orig, const char *orig_name,
6161
mmfile_t *src1, const char *name1,
6262
mmfile_t *src2, const char *name2,
6363
int flag, int marker_size)
@@ -71,7 +71,8 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
7171
path, name1, name2);
7272
return ll_binary_merge(drv_unused, result,
7373
path,
74-
orig, src1, name1,
74+
orig, orig_name,
75+
src1, name1,
7576
src2, name2,
7677
flag, marker_size);
7778
}
@@ -83,21 +84,24 @@ static int ll_xdl_merge(const struct ll_merge_driver *drv_unused,
8384
xmp.style = git_xmerge_style;
8485
if (marker_size > 0)
8586
xmp.marker_size = marker_size;
86-
return xdl_merge(orig, src1, name1, src2, name2, &xmp, result);
87+
xmp.ancestor = orig_name;
88+
xmp.file1 = name1;
89+
xmp.file2 = name2;
90+
return xdl_merge(orig, src1, src2, &xmp, result);
8791
}
8892

8993
static int ll_union_merge(const struct ll_merge_driver *drv_unused,
9094
mmbuffer_t *result,
9195
const char *path_unused,
92-
mmfile_t *orig,
96+
mmfile_t *orig, const char *orig_name,
9397
mmfile_t *src1, const char *name1,
9498
mmfile_t *src2, const char *name2,
9599
int flag, int marker_size)
96100
{
97101
/* Use union favor */
98102
flag = (flag & 1) | (XDL_MERGE_FAVOR_UNION << 1);
99103
return ll_xdl_merge(drv_unused, result, path_unused,
100-
orig, src1, NULL, src2, NULL,
104+
orig, NULL, src1, NULL, src2, NULL,
101105
flag, marker_size);
102106
return 0;
103107
}
@@ -128,7 +132,7 @@ static void create_temp(mmfile_t *src, char *path)
128132
static int ll_ext_merge(const struct ll_merge_driver *fn,
129133
mmbuffer_t *result,
130134
const char *path,
131-
mmfile_t *orig,
135+
mmfile_t *orig, const char *orig_name,
132136
mmfile_t *src1, const char *name1,
133137
mmfile_t *src2, const char *name2,
134138
int flag, int marker_size)
@@ -319,7 +323,7 @@ static int git_path_check_merge(const char *path, struct git_attr_check check[2]
319323

320324
int ll_merge(mmbuffer_t *result_buf,
321325
const char *path,
322-
mmfile_t *ancestor,
326+
mmfile_t *ancestor, const char *ancestor_label,
323327
mmfile_t *ours, const char *our_label,
324328
mmfile_t *theirs, const char *their_label,
325329
int flag)
@@ -341,7 +345,7 @@ int ll_merge(mmbuffer_t *result_buf,
341345
driver = find_ll_merge_driver(ll_driver_name);
342346
if (virtual_ancestor && driver->recursive)
343347
driver = find_ll_merge_driver(driver->recursive);
344-
return driver->fn(driver, result_buf, path, ancestor,
348+
return driver->fn(driver, result_buf, path, ancestor, ancestor_label,
345349
ours, our_label, theirs, their_label,
346350
flag, marker_size);
347351
}

ll-merge.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
int ll_merge(mmbuffer_t *result_buf,
99
const char *path,
10-
mmfile_t *ancestor,
10+
mmfile_t *ancestor, const char *ancestor_label,
1111
mmfile_t *ours, const char *our_label,
1212
mmfile_t *theirs, const char *their_label,
1313
int flag);

merge-file.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ static void *three_way_filemerge(const char *path, mmfile_t *base, mmfile_t *our
3030
int merge_status;
3131
mmbuffer_t res;
3232

33-
merge_status = ll_merge(&res, path, base,
33+
/*
34+
* This function is only used by cmd_merge_tree, which
35+
* does not respect the merge.conflictstyle option.
36+
* There is no need to worry about a label for the
37+
* common ancestor.
38+
*/
39+
merge_status = ll_merge(&res, path, base, NULL,
3440
our, ".our", their, ".their", 0);
3541
if (merge_status < 0)
3642
return NULL;

merge-recursive.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ static int merge_3way(struct merge_options *o,
608608
const char *branch2)
609609
{
610610
mmfile_t orig, src1, src2;
611-
char *name1, *name2;
611+
char *base_name, *name1, *name2;
612612
int merge_status;
613613
int favor;
614614

@@ -628,10 +628,15 @@ static int merge_3way(struct merge_options *o,
628628
}
629629
}
630630

631-
if (strcmp(a->path, b->path)) {
631+
if (strcmp(a->path, b->path) ||
632+
(o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
633+
base_name = o->ancestor == NULL ? NULL :
634+
xstrdup(mkpath("%s:%s", o->ancestor, one->path));
632635
name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
633636
name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
634637
} else {
638+
base_name = o->ancestor == NULL ? NULL :
639+
xstrdup(mkpath("%s", o->ancestor));
635640
name1 = xstrdup(mkpath("%s", branch1));
636641
name2 = xstrdup(mkpath("%s", branch2));
637642
}
@@ -640,7 +645,7 @@ static int merge_3way(struct merge_options *o,
640645
read_mmblob(&src1, a->sha1);
641646
read_mmblob(&src2, b->sha1);
642647

643-
merge_status = ll_merge(result_buf, a->path, &orig,
648+
merge_status = ll_merge(result_buf, a->path, &orig, base_name,
644649
&src1, name1, &src2, name2,
645650
(!!o->call_depth) | (favor << 1));
646651

@@ -1342,6 +1347,7 @@ int merge_recursive(struct merge_options *o,
13421347
if (!o->call_depth)
13431348
read_cache();
13441349

1350+
o->ancestor = "merged common ancestors";
13451351
clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
13461352
&mrtree);
13471353

0 commit comments

Comments
 (0)