Skip to content

Commit a57048a

Browse files
committed
Merge branch 'ag/merge-strategies-in-c' into seen
The resolve and octopus merge strategy backends have been rewritten in C. * ag/merge-strategies-in-c: sequencer: use the "octopus" merge strategy without forking sequencer: use the "resolve" strategy without forking merge: use the "octopus" strategy without forking merge: use the "resolve" strategy without forking merge-octopus: rewrite in C merge-recursive: move better_branch_name() to merge.c merge-resolve: rewrite in C merge-index: don't fork if the requested program is `git-merge-one-file' merge-index: libify merge_one_path() and merge_all() merge-one-file: rewrite in C t6027: modernise tests
2 parents 0e41d93 + 8f7759d commit a57048a

19 files changed

+973
-447
lines changed

Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -603,9 +603,6 @@ unexport CDPATH
603603
SCRIPT_SH += git-bisect.sh
604604
SCRIPT_SH += git-difftool--helper.sh
605605
SCRIPT_SH += git-filter-branch.sh
606-
SCRIPT_SH += git-merge-octopus.sh
607-
SCRIPT_SH += git-merge-one-file.sh
608-
SCRIPT_SH += git-merge-resolve.sh
609606
SCRIPT_SH += git-mergetool.sh
610607
SCRIPT_SH += git-quiltimport.sh
611608
SCRIPT_SH += git-request-pull.sh
@@ -924,6 +921,7 @@ LIB_OBJS += match-trees.o
924921
LIB_OBJS += mem-pool.o
925922
LIB_OBJS += merge-blobs.o
926923
LIB_OBJS += merge-recursive.o
924+
LIB_OBJS += merge-strategies.o
927925
LIB_OBJS += merge.o
928926
LIB_OBJS += mergesort.o
929927
LIB_OBJS += midx.o
@@ -1115,8 +1113,11 @@ BUILTIN_OBJS += builtin/mailsplit.o
11151113
BUILTIN_OBJS += builtin/merge-base.o
11161114
BUILTIN_OBJS += builtin/merge-file.o
11171115
BUILTIN_OBJS += builtin/merge-index.o
1116+
BUILTIN_OBJS += builtin/merge-octopus.o
1117+
BUILTIN_OBJS += builtin/merge-one-file.o
11181118
BUILTIN_OBJS += builtin/merge-ours.o
11191119
BUILTIN_OBJS += builtin/merge-recursive.o
1120+
BUILTIN_OBJS += builtin/merge-resolve.o
11201121
BUILTIN_OBJS += builtin/merge-tree.o
11211122
BUILTIN_OBJS += builtin/merge.o
11221123
BUILTIN_OBJS += builtin/mktag.o

builtin.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,12 @@ int cmd_maintenance(int argc, const char **argv, const char *prefix);
179179
int cmd_merge(int argc, const char **argv, const char *prefix);
180180
int cmd_merge_base(int argc, const char **argv, const char *prefix);
181181
int cmd_merge_index(int argc, const char **argv, const char *prefix);
182+
int cmd_merge_octopus(int argc, const char **argv, const char *prefix);
182183
int cmd_merge_ours(int argc, const char **argv, const char *prefix);
183184
int cmd_merge_file(int argc, const char **argv, const char *prefix);
185+
int cmd_merge_one_file(int argc, const char **argv, const char *prefix);
184186
int cmd_merge_recursive(int argc, const char **argv, const char *prefix);
187+
int cmd_merge_resolve(int argc, const char **argv, const char *prefix);
185188
int cmd_merge_tree(int argc, const char **argv, const char *prefix);
186189
int cmd_mktag(int argc, const char **argv, const char *prefix);
187190
int cmd_mktree(int argc, const char **argv, const char *prefix);

builtin/merge-index.c

Lines changed: 32 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,15 @@
11
#define USE_THE_INDEX_COMPATIBILITY_MACROS
22
#include "builtin.h"
3-
#include "run-command.h"
4-
5-
static const char *pgm;
6-
static int one_shot, quiet;
7-
static int err;
8-
9-
static int merge_entry(int pos, const char *path)
10-
{
11-
int found;
12-
const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL };
13-
char hexbuf[4][GIT_MAX_HEXSZ + 1];
14-
char ownbuf[4][60];
15-
16-
if (pos >= active_nr)
17-
die("git merge-index: %s not in the cache", path);
18-
found = 0;
19-
do {
20-
const struct cache_entry *ce = active_cache[pos];
21-
int stage = ce_stage(ce);
22-
23-
if (strcmp(ce->name, path))
24-
break;
25-
found++;
26-
oid_to_hex_r(hexbuf[stage], &ce->oid);
27-
xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
28-
arguments[stage] = hexbuf[stage];
29-
arguments[stage + 4] = ownbuf[stage];
30-
} while (++pos < active_nr);
31-
if (!found)
32-
die("git merge-index: %s not in the cache", path);
33-
34-
if (run_command_v_opt(arguments, 0)) {
35-
if (one_shot)
36-
err++;
37-
else {
38-
if (!quiet)
39-
die("merge program failed");
40-
exit(1);
41-
}
42-
}
43-
return found;
44-
}
45-
46-
static void merge_one_path(const char *path)
47-
{
48-
int pos = cache_name_pos(path, strlen(path));
49-
50-
/*
51-
* If it already exists in the cache as stage0, it's
52-
* already merged and there is nothing to do.
53-
*/
54-
if (pos < 0)
55-
merge_entry(-pos-1, path);
56-
}
57-
58-
static void merge_all(void)
59-
{
60-
int i;
61-
for (i = 0; i < active_nr; i++) {
62-
const struct cache_entry *ce = active_cache[i];
63-
if (!ce_stage(ce))
64-
continue;
65-
i += merge_entry(i, ce->name)-1;
66-
}
67-
}
3+
#include "lockfile.h"
4+
#include "merge-strategies.h"
685

696
int cmd_merge_index(int argc, const char **argv, const char *prefix)
707
{
71-
int i, force_file = 0;
8+
int i, force_file = 0, err = 0, one_shot = 0, quiet = 0;
9+
const char *pgm;
10+
void *data;
11+
merge_cb merge_action;
12+
struct lock_file lock = LOCK_INIT;
7213

7314
/* Without this we cannot rely on waitpid() to tell
7415
* what happened to our children.
@@ -89,7 +30,19 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
8930
quiet = 1;
9031
i++;
9132
}
33+
9234
pgm = argv[i++];
35+
if (!strcmp(pgm, "git-merge-one-file")) {
36+
merge_action = merge_one_file_cb;
37+
data = (void *)the_repository;
38+
39+
setup_work_tree();
40+
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
41+
} else {
42+
merge_action = merge_program_cb;
43+
data = (void *)pgm;
44+
}
45+
9346
for (; i < argc; i++) {
9447
const char *arg = argv[i];
9548
if (!force_file && *arg == '-') {
@@ -98,14 +51,23 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
9851
continue;
9952
}
10053
if (!strcmp(arg, "-a")) {
101-
merge_all();
54+
err |= merge_all(&the_index, one_shot, quiet,
55+
merge_action, data);
10256
continue;
10357
}
10458
die("git merge-index: unknown option %s", arg);
10559
}
106-
merge_one_path(arg);
60+
err |= merge_one_path(&the_index, one_shot, quiet, arg,
61+
merge_action, data);
62+
}
63+
64+
if (merge_action == merge_one_file_cb) {
65+
if (err) {
66+
rollback_lock_file(&lock);
67+
return err;
68+
}
69+
70+
return write_locked_index(&the_index, &lock, COMMIT_LOCK);
10771
}
108-
if (err && !quiet)
109-
die("merge program failed");
11072
return err;
11173
}

builtin/merge-octopus.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Builtin "git merge-octopus"
3+
*
4+
* Copyright (c) 2020 Alban Gruin
5+
*
6+
* Based on git-merge-octopus.sh, written by Junio C Hamano.
7+
*
8+
* Resolve two or more trees.
9+
*/
10+
11+
#include "cache.h"
12+
#include "builtin.h"
13+
#include "commit.h"
14+
#include "merge-strategies.h"
15+
16+
static const char builtin_merge_octopus_usage[] =
17+
"git merge-octopus [<bases>...] -- <head> <remote1> <remote2> [<remotes>...]";
18+
19+
int cmd_merge_octopus(int argc, const char **argv, const char *prefix)
20+
{
21+
int i, sep_seen = 0;
22+
struct commit_list *bases = NULL, *remotes = NULL;
23+
struct commit_list **next_base = &bases, **next_remote = &remotes;
24+
const char *head_arg = NULL;
25+
26+
if (argc < 5)
27+
usage(builtin_merge_octopus_usage);
28+
29+
setup_work_tree();
30+
if (repo_read_index(the_repository) < 0)
31+
die("corrupted cache");
32+
33+
/*
34+
* The first parameters up to -- are merge bases; the rest are
35+
* heads.
36+
*/
37+
for (i = 1; i < argc; i++) {
38+
if (strcmp(argv[i], "--") == 0)
39+
sep_seen = 1;
40+
else if (strcmp(argv[i], "-h") == 0)
41+
usage(builtin_merge_octopus_usage);
42+
else if (sep_seen && !head_arg)
43+
head_arg = argv[i];
44+
else {
45+
struct object_id oid;
46+
47+
get_oid(argv[i], &oid);
48+
49+
if (!oideq(&oid, the_hash_algo->empty_tree)) {
50+
struct commit *commit;
51+
commit = lookup_commit_or_die(&oid, argv[i]);
52+
53+
if (sep_seen)
54+
next_remote = commit_list_append(commit, next_remote);
55+
else
56+
next_base = commit_list_append(commit, next_base);
57+
}
58+
}
59+
}
60+
61+
/*
62+
* Reject if this is not an octopus -- resolve should be used
63+
* instead.
64+
*/
65+
if (commit_list_count(remotes) < 2)
66+
return 2;
67+
68+
return merge_strategies_octopus(the_repository, bases, head_arg, remotes);
69+
}

builtin/merge-one-file.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Builtin "git merge-one-file"
3+
*
4+
* Copyright (c) 2020 Alban Gruin
5+
*
6+
* Based on git-merge-one-file.sh, written by Linus Torvalds.
7+
*
8+
* This is the git per-file merge utility, called with
9+
*
10+
* argv[1] - original file SHA1 (or empty)
11+
* argv[2] - file in branch1 SHA1 (or empty)
12+
* argv[3] - file in branch2 SHA1 (or empty)
13+
* argv[4] - pathname in repository
14+
* argv[5] - original file mode (or empty)
15+
* argv[6] - file in branch1 mode (or empty)
16+
* argv[7] - file in branch2 mode (or empty)
17+
*
18+
* Handle some trivial cases. The _really_ trivial cases have been
19+
* handled already by git read-tree, but that one doesn't do any merges
20+
* that might change the tree layout.
21+
*/
22+
23+
#define USE_THE_INDEX_COMPATIBILITY_MACROS
24+
#include "cache.h"
25+
#include "builtin.h"
26+
#include "lockfile.h"
27+
#include "merge-strategies.h"
28+
29+
static const char builtin_merge_one_file_usage[] =
30+
"git merge-one-file <orig blob> <our blob> <their blob> <path> "
31+
"<orig mode> <our mode> <their mode>\n\n"
32+
"Blob ids and modes should be empty for missing files.";
33+
34+
static int read_mode(const char *name, const char *arg, unsigned int *mode)
35+
{
36+
char *last;
37+
int ret = 0;
38+
39+
*mode = strtol(arg, &last, 8);
40+
41+
if (*last)
42+
ret = error(_("invalid '%s' mode: expected nothing, got '%c'"), name, *last);
43+
else if (!(S_ISREG(*mode) || S_ISDIR(*mode) || S_ISLNK(*mode)))
44+
ret = error(_("invalid '%s' mode: %o"), name, *mode);
45+
46+
return ret;
47+
}
48+
49+
int cmd_merge_one_file(int argc, const char **argv, const char *prefix)
50+
{
51+
struct object_id orig_blob, our_blob, their_blob,
52+
*p_orig_blob = NULL, *p_our_blob = NULL, *p_their_blob = NULL;
53+
unsigned int orig_mode = 0, our_mode = 0, their_mode = 0, ret = 0;
54+
struct lock_file lock = LOCK_INIT;
55+
56+
if (argc != 8)
57+
usage(builtin_merge_one_file_usage);
58+
59+
if (read_cache() < 0)
60+
die("invalid index");
61+
62+
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
63+
64+
if (!get_oid(argv[1], &orig_blob)) {
65+
p_orig_blob = &orig_blob;
66+
ret = read_mode("orig", argv[5], &orig_mode);
67+
}
68+
69+
if (!get_oid(argv[2], &our_blob)) {
70+
p_our_blob = &our_blob;
71+
ret = read_mode("our", argv[6], &our_mode);
72+
}
73+
74+
if (!get_oid(argv[3], &their_blob)) {
75+
p_their_blob = &their_blob;
76+
ret = read_mode("their", argv[7], &their_mode);
77+
}
78+
79+
if (ret)
80+
return ret;
81+
82+
ret = merge_strategies_one_file(the_repository,
83+
p_orig_blob, p_our_blob, p_their_blob, argv[4],
84+
orig_mode, our_mode, their_mode);
85+
86+
if (ret) {
87+
rollback_lock_file(&lock);
88+
return !!ret;
89+
}
90+
91+
return write_locked_index(&the_index, &lock, COMMIT_LOCK);
92+
}

builtin/merge-recursive.c

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,6 @@
88
static const char builtin_merge_recursive_usage[] =
99
"git %s <base>... -- <head> <remote> ...";
1010

11-
static char *better_branch_name(const char *branch)
12-
{
13-
static char githead_env[8 + GIT_MAX_HEXSZ + 1];
14-
char *name;
15-
16-
if (strlen(branch) != the_hash_algo->hexsz)
17-
return xstrdup(branch);
18-
xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch);
19-
name = getenv(githead_env);
20-
return xstrdup(name ? name : branch);
21-
}
22-
2311
int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
2412
{
2513
const struct object_id *bases[21];
@@ -75,8 +63,8 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
7563
if (get_oid(o.branch2, &h2))
7664
die(_("could not resolve ref '%s'"), o.branch2);
7765

78-
o.branch1 = better1 = better_branch_name(o.branch1);
79-
o.branch2 = better2 = better_branch_name(o.branch2);
66+
o.branch1 = better1 = merge_get_better_branch_name(o.branch1);
67+
o.branch2 = better2 = merge_get_better_branch_name(o.branch2);
8068

8169
if (o.verbosity >= 3)
8270
printf(_("Merging %s with %s\n"), o.branch1, o.branch2);

0 commit comments

Comments
 (0)