Merge branch 'en/rename-directory-detection'
[git] / builtin / merge-index.c
1 #include "builtin.h"
2 #include "run-command.h"
3
4 static const char *pgm;
5 static int one_shot, quiet;
6 static int err;
7
8 static int merge_entry(int pos, const char *path)
9 {
10         int found;
11         const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL };
12         char hexbuf[4][GIT_MAX_HEXSZ + 1];
13         char ownbuf[4][60];
14
15         if (pos >= active_nr)
16                 die("git merge-index: %s not in the cache", path);
17         found = 0;
18         do {
19                 const struct cache_entry *ce = active_cache[pos];
20                 int stage = ce_stage(ce);
21
22                 if (strcmp(ce->name, path))
23                         break;
24                 found++;
25                 oid_to_hex_r(hexbuf[stage], &ce->oid);
26                 xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
27                 arguments[stage] = hexbuf[stage];
28                 arguments[stage + 4] = ownbuf[stage];
29         } while (++pos < active_nr);
30         if (!found)
31                 die("git merge-index: %s not in the cache", path);
32
33         if (run_command_v_opt(arguments, 0)) {
34                 if (one_shot)
35                         err++;
36                 else {
37                         if (!quiet)
38                                 die("merge program failed");
39                         exit(1);
40                 }
41         }
42         return found;
43 }
44
45 static void merge_one_path(const char *path)
46 {
47         int pos = cache_name_pos(path, strlen(path));
48
49         /*
50          * If it already exists in the cache as stage0, it's
51          * already merged and there is nothing to do.
52          */
53         if (pos < 0)
54                 merge_entry(-pos-1, path);
55 }
56
57 static void merge_all(void)
58 {
59         int i;
60         for (i = 0; i < active_nr; i++) {
61                 const struct cache_entry *ce = active_cache[i];
62                 if (!ce_stage(ce))
63                         continue;
64                 i += merge_entry(i, ce->name)-1;
65         }
66 }
67
68 int cmd_merge_index(int argc, const char **argv, const char *prefix)
69 {
70         int i, force_file = 0;
71
72         /* Without this we cannot rely on waitpid() to tell
73          * what happened to our children.
74          */
75         signal(SIGCHLD, SIG_DFL);
76
77         if (argc < 3)
78                 usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
79
80         read_cache();
81
82         i = 1;
83         if (!strcmp(argv[i], "-o")) {
84                 one_shot = 1;
85                 i++;
86         }
87         if (!strcmp(argv[i], "-q")) {
88                 quiet = 1;
89                 i++;
90         }
91         pgm = argv[i++];
92         for (; i < argc; i++) {
93                 const char *arg = argv[i];
94                 if (!force_file && *arg == '-') {
95                         if (!strcmp(arg, "--")) {
96                                 force_file = 1;
97                                 continue;
98                         }
99                         if (!strcmp(arg, "-a")) {
100                                 merge_all();
101                                 continue;
102                         }
103                         die("git merge-index: unknown option %s", arg);
104                 }
105                 merge_one_path(arg);
106         }
107         if (err && !quiet)
108                 die("merge program failed");
109         return err;
110 }