Skip to content

Commit 4421a82

Browse files
committed
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 <[email protected]>
1 parent 4a39f79 commit 4421a82

File tree

5 files changed

+77
-0
lines changed

5 files changed

+77
-0
lines changed

builtin-checkout.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
235235
if (report_path_error(ps_matched, pathspec, 0))
236236
return 1;
237237

238+
/* "checkout -m path" to recreate conflicted state */
239+
if (opts->merge)
240+
unmerge_cache(pathspec);
241+
238242
/* Any unmerged paths? */
239243
for (pos = 0; pos < active_nr; pos++) {
240244
struct cache_entry *ce = active_cache[pos];

cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
338338
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
339339
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
340340
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
341+
#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
341342
#endif
342343

343344
enum object_type {

resolve-undo.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "cache.h"
2+
#include "dir.h"
23
#include "resolve-undo.h"
34
#include "string-list.h"
45

@@ -115,3 +116,61 @@ void resolve_undo_clear_index(struct index_state *istate)
115116
istate->resolve_undo = NULL;
116117
istate->cache_changed = 1;
117118
}
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ extern void record_resolve_undo(struct index_state *, struct cache_entry *);
1010
extern void resolve_undo_write(struct strbuf *, struct string_list *);
1111
extern struct string_list *resolve_undo_read(void *, unsigned long);
1212
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 **);
1315

1416
#endif

t/t2030-unresolve-info.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,15 @@ test_expect_success 'plumbing clears' '
9797
check_resolve_undo cleared
9898
'
9999

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+
100111
test_done

0 commit comments

Comments
 (0)