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