[PATCH 09/12] checkout: do not check out unmerged higher stages randomly
From: Junio C Hamano <hidden>
Date: 2016-06-15 22:45:15
Subsystem:
the rest · Maintainer:
Linus Torvalds
During a conflicted merge when you have unmerged stages for a
path F in the index, if you said:
$ git checkout F
we rewrote F as many times as we have stages for it, and the
last one (typically "theirs") was left in the work tree, without
resolving the conflict.
This fixes it by noticing that a specified pathspec pattern
matches an unmerged path, and by erroring out.
Signed-off-by: Junio C Hamano <redacted>
---
builtin-checkout.c | 27 +++++++++++++++++++++++++++
t/t7201-co.sh | 23 +++++++++++++++++++++++
2 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/builtin-checkout.c b/builtin-checkout.c
index b380ad6..9b33f3a 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c@@ -76,6 +76,15 @@ static int read_tree_some(struct tree *tree, const char **pathspec) return 0; } +static int skip_same_name(struct cache_entry *ce, int pos) +{ + while (++pos < active_nr && + !strcmp(active_cache[pos]->name, ce->name)) + ; /* skip */ + return pos; +} + + static int checkout_paths(struct tree *source_tree, const char **pathspec) { int pos;
@@ -107,6 +116,20 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) if (report_path_error(ps_matched, pathspec, 0)) return 1; + /* Any unmerged paths? */ + for (pos = 0; pos < active_nr; pos++) { + struct cache_entry *ce = active_cache[pos]; + if (pathspec_match(pathspec, NULL, ce->name, 0) && + ce_stage(ce)) { + errs = 1; + error("path '%s' is unmerged", ce->name); + pos = skip_same_name(ce, pos) - 1; + continue; + } + } + if (errs) + return 1; + /* Now we are committed to check them out */ memset(&state, 0, sizeof(state)); state.force = 1;
@@ -114,6 +137,10 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec) for (pos = 0; pos < active_nr; pos++) { struct cache_entry *ce = active_cache[pos]; if (pathspec_match(pathspec, NULL, ce->name, 0)) { + if (ce_stage(ce)) { + pos = skip_same_name(ce, pos) - 1; + continue; + } errs |= checkout_entry(ce, &state, NULL); } }
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 1dff84d..303cf62 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh@@ -369,4 +369,27 @@ test_expect_success \ 'checkout with --track, but without -b, fails with too short tracked name' ' test_must_fail git checkout --track renamer' +test_expect_success 'checkout an unmerged path should fail' ' + rm -f .git/index && + O=$(echo original | git hash-object -w --stdin) && + A=$(echo ourside | git hash-object -w --stdin) && + B=$(echo theirside | git hash-object -w --stdin) && + ( + echo "100644 $A 0 fild" && + echo "100644 $O 1 file" && + echo "100644 $A 2 file" && + echo "100644 $B 3 file" && + echo "100644 $A 0 filf" + ) | git update-index --index-info && + echo "none of the above" >sample && + cat sample >fild && + cat sample >file && + cat sample >filf && + test_must_fail git checkout fild file filf && + test_cmp sample fild && + test_cmp sample filf && + test_cmp sample file +' + test_done +
--
1.6.0.1.149.ga4c44