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>
This commit is contained in:
parent
4a39f79d34
commit
4421a82357
@ -235,6 +235,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec,
|
||||
if (report_path_error(ps_matched, pathspec, 0))
|
||||
return 1;
|
||||
|
||||
/* "checkout -m path" to recreate conflicted state */
|
||||
if (opts->merge)
|
||||
unmerge_cache(pathspec);
|
||||
|
||||
/* Any unmerged paths? */
|
||||
for (pos = 0; pos < active_nr; pos++) {
|
||||
struct cache_entry *ce = active_cache[pos];
|
||||
|
1
cache.h
1
cache.h
@ -338,6 +338,7 @@ static inline void remove_name_hash(struct cache_entry *ce)
|
||||
#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
|
||||
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
|
||||
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
|
||||
#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
|
||||
#endif
|
||||
|
||||
enum object_type {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "cache.h"
|
||||
#include "dir.h"
|
||||
#include "resolve-undo.h"
|
||||
#include "string-list.h"
|
||||
|
||||
@ -115,3 +116,61 @@ void resolve_undo_clear_index(struct index_state *istate)
|
||||
istate->resolve_undo = NULL;
|
||||
istate->cache_changed = 1;
|
||||
}
|
||||
|
||||
int unmerge_index_entry_at(struct index_state *istate, int pos)
|
||||
{
|
||||
struct cache_entry *ce;
|
||||
struct string_list_item *item;
|
||||
struct resolve_undo_info *ru;
|
||||
int i, err = 0;
|
||||
|
||||
if (!istate->resolve_undo)
|
||||
return pos;
|
||||
|
||||
ce = istate->cache[pos];
|
||||
if (ce_stage(ce)) {
|
||||
/* already unmerged */
|
||||
while ((pos < istate->cache_nr) &&
|
||||
! strcmp(istate->cache[pos]->name, ce->name))
|
||||
pos++;
|
||||
return pos - 1; /* return the last entry processed */
|
||||
}
|
||||
item = string_list_lookup(ce->name, istate->resolve_undo);
|
||||
if (!item)
|
||||
return pos;
|
||||
ru = item->util;
|
||||
if (!ru)
|
||||
return pos;
|
||||
remove_index_entry_at(istate, pos);
|
||||
for (i = 0; i < 3; i++) {
|
||||
struct cache_entry *nce;
|
||||
if (!ru->mode[i])
|
||||
continue;
|
||||
nce = make_cache_entry(ru->mode[i], ru->sha1[i],
|
||||
ce->name, i + 1, 0);
|
||||
if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
|
||||
err = 1;
|
||||
error("cannot unmerge '%s'", ce->name);
|
||||
}
|
||||
}
|
||||
if (err)
|
||||
return pos;
|
||||
free(ru);
|
||||
item->util = NULL;
|
||||
return unmerge_index_entry_at(istate, pos);
|
||||
}
|
||||
|
||||
void unmerge_index(struct index_state *istate, const char **pathspec)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!istate->resolve_undo)
|
||||
return;
|
||||
|
||||
for (i = 0; i < istate->cache_nr; i++) {
|
||||
struct cache_entry *ce = istate->cache[i];
|
||||
if (!match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL))
|
||||
continue;
|
||||
i = unmerge_index_entry_at(istate, i);
|
||||
}
|
||||
}
|
||||
|
@ -10,5 +10,7 @@ extern void record_resolve_undo(struct index_state *, struct cache_entry *);
|
||||
extern void resolve_undo_write(struct strbuf *, struct string_list *);
|
||||
extern struct string_list *resolve_undo_read(void *, unsigned long);
|
||||
extern void resolve_undo_clear_index(struct index_state *);
|
||||
extern int unmerge_index_entry_at(struct index_state *, int);
|
||||
extern void unmerge_index(struct index_state *, const char **);
|
||||
|
||||
#endif
|
||||
|
@ -97,4 +97,15 @@ test_expect_success 'plumbing clears' '
|
||||
check_resolve_undo cleared
|
||||
'
|
||||
|
||||
test_expect_success 'add records checkout -m undoes' '
|
||||
prime_resolve_undo &&
|
||||
git diff HEAD &&
|
||||
git checkout --conflict=merge file &&
|
||||
echo checkout used the record and removed it &&
|
||||
check_resolve_undo removed &&
|
||||
echo the index and the work tree is unmerged again &&
|
||||
git diff >actual &&
|
||||
grep "^++<<<<<<<" actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user