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>maint
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))
|
if (report_path_error(ps_matched, pathspec, 0))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
/* "checkout -m path" to recreate conflicted state */
|
||||||
|
if (opts->merge)
|
||||||
|
unmerge_cache(pathspec);
|
||||||
|
|
||||||
/* Any unmerged paths? */
|
/* Any unmerged paths? */
|
||||||
for (pos = 0; pos < active_nr; pos++) {
|
for (pos = 0; pos < active_nr; pos++) {
|
||||||
struct cache_entry *ce = active_cache[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_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 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 resolve_undo_clear() resolve_undo_clear_index(&the_index)
|
||||||
|
#define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum object_type {
|
enum object_type {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "dir.h"
|
||||||
#include "resolve-undo.h"
|
#include "resolve-undo.h"
|
||||||
#include "string-list.h"
|
#include "string-list.h"
|
||||||
|
|
||||||
|
@ -115,3 +116,61 @@ void resolve_undo_clear_index(struct index_state *istate)
|
||||||
istate->resolve_undo = NULL;
|
istate->resolve_undo = NULL;
|
||||||
istate->cache_changed = 1;
|
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 void resolve_undo_write(struct strbuf *, struct string_list *);
|
||||||
extern struct string_list *resolve_undo_read(void *, unsigned long);
|
extern struct string_list *resolve_undo_read(void *, unsigned long);
|
||||||
extern void resolve_undo_clear_index(struct index_state *);
|
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
|
#endif
|
||||||
|
|
|
@ -97,4 +97,15 @@ test_expect_success 'plumbing clears' '
|
||||||
check_resolve_undo cleared
|
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
|
test_done
|
||||||
|
|
Loading…
Reference in New Issue