Make a short-and-sweet "git-add -i" synonym for "git-add --interactive"
[git] / merge-index.c
1 #include "cache.h"
2
3 static const char *pgm;
4 static const char *arguments[8];
5 static int one_shot, quiet;
6 static int err;
7
8 static void run_program(void)
9 {
10         pid_t pid = fork();
11         int status;
12
13         if (pid < 0)
14                 die("unable to fork");
15         if (!pid) {
16                 execlp(pgm, arguments[0],
17                             arguments[1],
18                             arguments[2],
19                             arguments[3],
20                             arguments[4],
21                             arguments[5],
22                             arguments[6],
23                             arguments[7],
24                             NULL);
25                 die("unable to execute '%s'", pgm);
26         }
27         if (waitpid(pid, &status, 0) < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) {
28                 if (one_shot) {
29                         err++;
30                 } else {
31                         if (!quiet)
32                                 die("merge program failed");
33                         exit(1);
34                 }
35         }
36 }
37
38 static int merge_entry(int pos, const char *path)
39 {
40         int found;
41         
42         if (pos >= active_nr)
43                 die("git-merge-index: %s not in the cache", path);
44         arguments[0] = pgm;
45         arguments[1] = "";
46         arguments[2] = "";
47         arguments[3] = "";
48         arguments[4] = path;
49         arguments[5] = "";
50         arguments[6] = "";
51         arguments[7] = "";
52         found = 0;
53         do {
54                 static char hexbuf[4][60];
55                 static char ownbuf[4][60];
56                 struct cache_entry *ce = active_cache[pos];
57                 int stage = ce_stage(ce);
58
59                 if (strcmp(ce->name, path))
60                         break;
61                 found++;
62                 strcpy(hexbuf[stage], sha1_to_hex(ce->sha1));
63                 sprintf(ownbuf[stage], "%o", ntohl(ce->ce_mode) & (~S_IFMT));
64                 arguments[stage] = hexbuf[stage];
65                 arguments[stage + 4] = ownbuf[stage];
66         } while (++pos < active_nr);
67         if (!found)
68                 die("git-merge-index: %s not in the cache", path);
69         run_program();
70         return found;
71 }
72
73 static void merge_file(const char *path)
74 {
75         int pos = cache_name_pos(path, strlen(path));
76
77         /*
78          * If it already exists in the cache as stage0, it's
79          * already merged and there is nothing to do.
80          */
81         if (pos < 0)
82                 merge_entry(-pos-1, path);
83 }
84
85 static void merge_all(void)
86 {
87         int i;
88         for (i = 0; i < active_nr; i++) {
89                 struct cache_entry *ce = active_cache[i];
90                 if (!ce_stage(ce))
91                         continue;
92                 i += merge_entry(i, ce->name)-1;
93         }
94 }
95
96 int main(int argc, char **argv)
97 {
98         int i, force_file = 0;
99
100         /* Without this we cannot rely on waitpid() to tell
101          * what happened to our children.
102          */
103         signal(SIGCHLD, SIG_DFL);
104
105         if (argc < 3)
106                 usage("git-merge-index [-o] [-q] <merge-program> (-a | <filename>*)");
107
108         setup_git_directory();
109         read_cache();
110
111         i = 1;
112         if (!strcmp(argv[i], "-o")) {
113                 one_shot = 1;
114                 i++;
115         }
116         if (!strcmp(argv[i], "-q")) {
117                 quiet = 1;
118                 i++;
119         }
120         pgm = argv[i++];
121         for (; i < argc; i++) {
122                 char *arg = argv[i];
123                 if (!force_file && *arg == '-') {
124                         if (!strcmp(arg, "--")) {
125                                 force_file = 1;
126                                 continue;
127                         }
128                         if (!strcmp(arg, "-a")) {
129                                 merge_all();
130                                 continue;
131                         }
132                         die("git-merge-index: unknown option %s", arg);
133                 }
134                 merge_file(arg);
135         }
136         if (err && !quiet)
137                 die("merge program failed");
138         return err;
139 }