diff options
author | Junio C Hamano <gitster@pobox.com> | 2009-12-25 11:57:11 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2009-12-25 17:10:10 -0800 |
commit | 4421a8235783d0664faa9a1d45be114fd7ad8206 (patch) | |
tree | 90505e56f05e1125140a21516a19667176da6e73 | |
parent | 4a39f79d3482cd844443b4ef9a8ef9b3d72faa5b (diff) | |
download | git-4421a8235783d0664faa9a1d45be114fd7ad8206.tar.gz |
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>
-rw-r--r-- | builtin-checkout.c | 4 | ||||
-rw-r--r-- | cache.h | 1 | ||||
-rw-r--r-- | resolve-undo.c | 59 | ||||
-rw-r--r-- | resolve-undo.h | 2 | ||||
-rwxr-xr-x | t/t2030-unresolve-info.sh | 11 |
5 files changed, 77 insertions, 0 deletions
diff --git a/builtin-checkout.c b/builtin-checkout.c index a0fe7a4e6d..bdef1aa386 100644 --- a/builtin-checkout.c +++ b/builtin-checkout.c @@ -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]; @@ -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 { diff --git a/resolve-undo.c b/resolve-undo.c index 86e8547ca2..37d73cd949 100644 --- a/resolve-undo.c +++ b/resolve-undo.c @@ -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); + } +} diff --git a/resolve-undo.h b/resolve-undo.h index 74194d0eba..e4e5c1b1ad 100644 --- a/resolve-undo.h +++ b/resolve-undo.h @@ -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 diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh index 984480271c..ea65f391c1 100755 --- a/t/t2030-unresolve-info.sh +++ b/t/t2030-unresolve-info.sh @@ -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 |