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