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