@matheusbsbs / matheus-bagliano / commits / 8fdcf31254
Fork 0

checkout: do not check out unmerged higher stages randomly

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 <gitster@pobox.com>

Junio C Hamano committed Aug 29, 2008 at 13:40 UTC 8fdcf3125465f70c0cad5be5ab192d46e46307c7
2 files changed +50 -1
builtin-checkout.c
+28 -1
@@ -76,6 +76,15 @@ static int read_tree_some(struct tree *tree, const char **pathspec)
76 return 0;
77 }
78
79 +static int skip_same_name(struct cache_entry *ce, int pos)
80 +{
81 + while (++pos < active_nr &&
82 + !strcmp(active_cache[pos]->name, ce->name))
83 + ; /* skip */
84 + return pos;
85 +}
86 +
87 +
88 static int checkout_paths(struct tree *source_tree, const char **pathspec)
89 {
90 int pos;
@@ -107,6 +116,20 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
116 if (report_path_error(ps_matched, pathspec, 0))
117 return 1;
118
119 + /* Any unmerged paths? */
120 + for (pos = 0; pos < active_nr; pos++) {
121 + struct cache_entry *ce = active_cache[pos];
122 + if (pathspec_match(pathspec, NULL, ce->name, 0)) {
123 + if (!ce_stage(ce))
124 + continue;
125 + errs = 1;
126 + error("path '%s' is unmerged", ce->name);
127 + pos = skip_same_name(ce, pos) - 1;
128 + }
129 + }
130 + if (errs)
131 + return 1;
132 +
133 /* Now we are committed to check them out */
134 memset(&state, 0, sizeof(state));
135 state.force = 1;
@@ -114,7 +137,11 @@ static int checkout_paths(struct tree *source_tree, const char **pathspec)
137 for (pos = 0; pos < active_nr; pos++) {
138 struct cache_entry *ce = active_cache[pos];
139 if (pathspec_match(pathspec, NULL, ce->name, 0)) {
117 - errs |= checkout_entry(ce, &state, NULL);
140 + if (!ce_stage(ce)) {
141 + errs |= checkout_entry(ce, &state, NULL);
142 + continue;
143 + }
144 + pos = skip_same_name(ce, pos) - 1;
145 }
146 }
147
t/t7201-co.sh
+22
@@ -337,4 +337,26 @@ test_expect_success \
337 test refs/heads/delete-me = "$(git symbolic-ref HEAD)" &&
338 test_must_fail git checkout --track -b track'
339
340 +test_expect_success 'checkout an unmerged path should fail' '
341 + rm -f .git/index &&
342 + O=$(echo original | git hash-object -w --stdin) &&
343 + A=$(echo ourside | git hash-object -w --stdin) &&
344 + B=$(echo theirside | git hash-object -w --stdin) &&
345 + (
346 + echo "100644 $A 0 fild" &&
347 + echo "100644 $O 1 file" &&
348 + echo "100644 $A 2 file" &&
349 + echo "100644 $B 3 file" &&
350 + echo "100644 $A 0 filf"
351 + ) | git update-index --index-info &&
352 + echo "none of the above" >sample &&
353 + cat sample >fild &&
354 + cat sample >file &&
355 + cat sample >filf &&
356 + test_must_fail git checkout fild file filf &&
357 + test_cmp sample fild &&
358 + test_cmp sample filf &&
359 + test_cmp sample file
360 +'
361 +
362 test_done