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