1 #define USE_THE_INDEX_COMPATIBILITY_MACROS
2 #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 
merge_entry(int pos,const char * path)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 
merge_one_path(const char * path)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 
merge_all(void)58 static void merge_all(void)
59 {
60 	int i;
61 	/* TODO: audit for interaction with sparse-index. */
62 	ensure_full_index(&the_index);
63 	for (i = 0; i < active_nr; i++) {
64 		const struct cache_entry *ce = active_cache[i];
65 		if (!ce_stage(ce))
66 			continue;
67 		i += merge_entry(i, ce->name)-1;
68 	}
69 }
70 
cmd_merge_index(int argc,const char ** argv,const char * prefix)71 int cmd_merge_index(int argc, const char **argv, const char *prefix)
72 {
73 	int i, force_file = 0;
74 
75 	/* Without this we cannot rely on waitpid() to tell
76 	 * what happened to our children.
77 	 */
78 	signal(SIGCHLD, SIG_DFL);
79 
80 	if (argc < 3)
81 		usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
82 
83 	read_cache();
84 
85 	/* TODO: audit for interaction with sparse-index. */
86 	ensure_full_index(&the_index);
87 
88 	i = 1;
89 	if (!strcmp(argv[i], "-o")) {
90 		one_shot = 1;
91 		i++;
92 	}
93 	if (!strcmp(argv[i], "-q")) {
94 		quiet = 1;
95 		i++;
96 	}
97 	pgm = argv[i++];
98 	for (; i < argc; i++) {
99 		const char *arg = argv[i];
100 		if (!force_file && *arg == '-') {
101 			if (!strcmp(arg, "--")) {
102 				force_file = 1;
103 				continue;
104 			}
105 			if (!strcmp(arg, "-a")) {
106 				merge_all();
107 				continue;
108 			}
109 			die("git merge-index: unknown option %s", arg);
110 		}
111 		merge_one_path(arg);
112 	}
113 	if (err && !quiet)
114 		die("merge program failed");
115 	return err;
116 }
117