Merge branch 'dl/stash-show-untracked-fixup'
[git] / builtin / merge-index.c
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
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
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
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
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 }