@matheusbsbs / matheus-bagliano / commits / 4421a82357
Fork 0

resolve-undo: "checkout -m path" uses resolve-undo information

Once you resolved conflicts by "git add path", you cannot recreate the conflicted state with "git checkout -m path", because you lost information from higher stages in the index when you resolved them. Since we record the necessary information in the resolve-undo index extension these days, we can reproduce the unmerged state in the index and check it out. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Dec 25, 2009 at 11:57 UTC 4421a8235783d0664faa9a1d45be114fd7ad8206
5 files changed +77
builtin-checkout.c
+4
@@ -235,6 +235,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
235 if (report_path_error(ps_matched, pathspec, 0))
236 return 1;
237
238 + /* "checkout -m path" to recreate conflicted state */
239 + if (opts->merge)
240 + unmerge_cache(pathspec);
241 +
242 /* Any unmerged paths? */
243 for (pos = 0; pos < active_nr; pos++) {
244 struct cache_entry *ce = active_cache[pos];
cache.h
+1
@@ -338,6 +338,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
338 #define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
339 #define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
340 #define resolve_undo_clear() resolve_undo_clear_index(&the_index)
341 +#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
342 #endif
343
344 enum object_type {
resolve-undo.c
+59
@@ -1,4 +1,5 @@
1 #include "cache.h"
2 +#include "dir.h"
3 #include "resolve-undo.h"
4 #include "string-list.h"
5
@@ -115,3 +116,61 @@ void resolve_undo_clear_index(struct index_state *istate)
116 istate->resolve_undo = NULL;
117 istate->cache_changed = 1;
118 }
119 +
120 +int unmerge_index_entry_at(struct index_state *istate, int pos)
121 +{
122 + struct cache_entry *ce;
123 + struct string_list_item *item;
124 + struct resolve_undo_info *ru;
125 + int i, err = 0;
126 +
127 + if (!istate->resolve_undo)
128 + return pos;
129 +
130 + ce = istate->cache[pos];
131 + if (ce_stage(ce)) {
132 + /* already unmerged */
133 + while ((pos < istate->cache_nr) &&
134 + ! strcmp(istate->cache[pos]->name, ce->name))
135 + pos++;
136 + return pos - 1; /* return the last entry processed */
137 + }
138 + item = string_list_lookup(ce->name, istate->resolve_undo);
139 + if (!item)
140 + return pos;
141 + ru = item->util;
142 + if (!ru)
143 + return pos;
144 + remove_index_entry_at(istate, pos);
145 + for (i = 0; i < 3; i++) {
146 + struct cache_entry *nce;
147 + if (!ru->mode[i])
148 + continue;
149 + nce = make_cache_entry(ru->mode[i], ru->sha1[i],
150 + ce->name, i + 1, 0);
151 + if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
152 + err = 1;
153 + error("cannot unmerge '%s'", ce->name);
154 + }
155 + }
156 + if (err)
157 + return pos;
158 + free(ru);
159 + item->util = NULL;
160 + return unmerge_index_entry_at(istate, pos);
161 +}
162 +
163 +void unmerge_index(struct index_state *istate, const char **pathspec)
164 +{
165 + int i;
166 +
167 + if (!istate->resolve_undo)
168 + return;
169 +
170 + for (i = 0; i < istate->cache_nr; i++) {
171 + struct cache_entry *ce = istate->cache[i];
172 + if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
173 + continue;
174 + i = unmerge_index_entry_at(istate, i);
175 + }
176 +}
resolve-undo.h
+2
@@ -10,5 +10,7 @@ extern void record_resolve_undo(struct index_state *, struct cache_entry *);
10 extern void resolve_undo_write(struct strbuf *, struct string_list *);
11 extern struct string_list *resolve_undo_read(void *, unsigned long);
12 extern void resolve_undo_clear_index(struct index_state *);
13 +extern int unmerge_index_entry_at(struct index_state *, int);
14 +extern void unmerge_index(struct index_state *, const char **);
15
16 #endif
t/t2030-unresolve-info.sh
+11
@@ -97,4 +97,15 @@ test_expect_success 'plumbing clears' '
97 check_resolve_undo cleared
98 '
99
100 +test_expect_success 'add records checkout -m undoes' '
101 + prime_resolve_undo &&
102 + git diff HEAD &&
103 + git checkout --conflict=merge file &&
104 + echo checkout used the record and removed it &&
105 + check_resolve_undo removed &&
106 + echo the index and the work tree is unmerged again &&
107 + git diff >actual &&
108 + grep "^++<<<<<<<" actual
109 +'
110 +
111 test_done