Add git-unresolve <paths>...
[git.git] / unresolve.c
1 #include "cache.h"
2 #include "tree-walk.h"
3
4 static const char unresolve_usage[] =
5 "git-unresolve <paths>...";
6
7 static struct cache_file cache_file;
8 static unsigned char head_sha1[20];
9 static unsigned char merge_head_sha1[20];
10
11 static struct cache_entry *read_one_ent(const char *which,
12                                         unsigned char *ent, const char *path,
13                                         int namelen, int stage)
14 {
15         unsigned mode;
16         unsigned char sha1[20];
17         int size;
18         struct cache_entry *ce;
19
20         if (get_tree_entry(ent, path, sha1, &mode)) {
21                 error("%s: not in %s branch.", path, which);
22                 return NULL;
23         }
24         if (mode == S_IFDIR) {
25                 error("%s: not a blob in %s branch.", path, which);
26                 return NULL;
27         }
28         size = cache_entry_size(namelen);
29         ce = xcalloc(1, size);
30
31         memcpy(ce->sha1, sha1, 20);
32         memcpy(ce->name, path, namelen);
33         ce->ce_flags = create_ce_flags(namelen, stage);
34         ce->ce_mode = create_ce_mode(mode);
35         return ce;
36 }
37
38 static int unresolve_one(const char *path)
39 {
40         int namelen = strlen(path);
41         int pos;
42         int ret = 0;
43         struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
44
45         /* See if there is such entry in the index. */
46         pos = cache_name_pos(path, namelen);
47         if (pos < 0) {
48                 /* If there isn't, either it is unmerged, or
49                  * resolved as "removed" by mistake.  We do not
50                  * want to do anything in the former case.
51                  */
52                 pos = -pos-1;
53                 if (pos < active_nr) {
54                         struct cache_entry *ce = active_cache[pos];
55                         if (ce_namelen(ce) == namelen &&
56                             !memcmp(ce->name, path, namelen)) {
57                                 fprintf(stderr,
58                                         "%s: skipping still unmerged path.\n",
59                                         path);
60                                 goto free_return;
61                         }
62                 }
63         }
64
65         /* Grab blobs from given path from HEAD and MERGE_HEAD,
66          * stuff HEAD version in stage #2,
67          * stuff MERGE_HEAD version in stage #3.
68          */
69         ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
70         ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
71
72         if (!ce_2 || !ce_3) {
73                 ret = -1;
74                 goto free_return;
75         }
76         if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
77             ce_2->ce_mode == ce_3->ce_mode) {
78                 fprintf(stderr, "%s: identical in both, skipping.\n",
79                         path);
80                 goto free_return;
81         }
82
83         remove_file_from_cache(path);
84         if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
85                 error("%s: cannot add our version to the index.", path);
86                 ret = -1;
87                 goto free_return;
88         }
89         if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
90                 return 0;
91         error("%s: cannot add their version to the index.", path);
92         ret = -1;
93  free_return:
94         free(ce_2);
95         free(ce_3);
96         return ret;
97 }
98
99 static void read_head_pointers(void)
100 {
101         if (read_ref(git_path("HEAD"), head_sha1))
102                 die("Cannot read HEAD -- no initial commit yet?");
103         if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
104                 fprintf(stderr, "Not in the middle of a merge.\n");
105                 exit(0);
106         }
107 }
108
109 int main(int ac, char **av)
110 {
111         int i;
112         int err = 0;
113         int newfd;
114
115         if (ac < 2)
116                 usage(unresolve_usage);
117
118         git_config(git_default_config);
119
120         /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
121          * are not doing a merge, so exit with success status.
122          */
123         read_head_pointers();
124
125         /* Otherwise we would need to update the cache. */
126         newfd= hold_index_file_for_update(&cache_file, get_index_file());
127         if (newfd < 0)
128                 die("unable to create new cachefile");
129
130         if (read_cache() < 0)
131                 die("cache corrupted");
132
133         for (i = 1; i < ac; i++) {
134                 char *arg = av[i];
135                 err |= unresolve_one(arg);
136         }
137         if (err)
138                 die("Error encountered; index not updated.");
139
140         if (active_cache_changed) {
141                 if (write_cache(newfd, active_cache, active_nr) ||
142                     commit_index_file(&cache_file))
143                         die("Unable to write new cachefile");
144         }
145         return 0;
146 }