Merge branch 'maint'
[git] / builtin-merge-index.c
1 #include "cache.h"
2 #include "run-command.h"
3 #include "exec_cmd.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][60];
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                 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                 strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
27                 sprintf(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_file(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                 struct cache_entry *ce = active_cache[i];
63                 if (!ce_stage(ce))
64                         continue;
65                 i += merge_entry(i, ce->name)-1;
66         }
67 }
68
69 int cmd_merge_index(int argc, const char **argv, const char *prefix)
70 {
71         int i, force_file = 0;
72
73         /* Without this we cannot rely on waitpid() to tell
74          * what happened to our children.
75          */
76         signal(SIGCHLD, SIG_DFL);
77
78         if (argc < 3)
79                 usage("git merge-index [-o] [-q] <merge-program> (-a | [--] <filename>*)");
80
81         read_cache();
82
83         i = 1;
84         if (!strcmp(argv[i], "-o")) {
85                 one_shot = 1;
86                 i++;
87         }
88         if (!strcmp(argv[i], "-q")) {
89                 quiet = 1;
90                 i++;
91         }
92         pgm = argv[i++];
93         for (; i < argc; i++) {
94                 const char *arg = argv[i];
95                 if (!force_file && *arg == '-') {
96                         if (!strcmp(arg, "--")) {
97                                 force_file = 1;
98                                 continue;
99                         }
100                         if (!strcmp(arg, "-a")) {
101                                 merge_all();
102                                 continue;
103                         }
104                         die("git merge-index: unknown option %s", arg);
105                 }
106                 merge_file(arg);
107         }
108         if (err && !quiet)
109                 die("merge program failed");
110         return err;
111 }