unpack-trees: avoid nuking untracked dir in way of unmerged file
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elijah Newren committed
Sep 27, 2021 at 16:33 UTC
1fdd51aa13c27403c37b57ead32ef79b81d8128b
2 files changed
+32
-5
t/t2500-untracked-overwriting.sh
+1
-1
@@ -197,7 +197,7 @@ test_expect_failure 'git stash and untracked files' '
197
)
198
'
199
200
-test_expect_failure 'git am --abort and untracked dir vs. unmerged file' '
200
+test_expect_success 'git am --abort and untracked dir vs. unmerged file' '
201
test_setup_sequencing am_abort_and_untracked &&
202
(
203
cd sequencing_am_abort_and_untracked &&
unpack-trees.c
+31
-4
@@ -2176,9 +2176,15 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le
2176
return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
2177
}
2178
2179
+enum absent_checking_type {
2180
+ COMPLETELY_ABSENT,
2181
+ ABSENT_ANY_DIRECTORY
2182
+};
2183
+
2184
static int check_ok_to_remove(const char *name, int len, int dtype,
2185
const struct cache_entry *ce, struct stat *st,
2186
enum unpack_trees_error_types error_type,
2187
+ enum absent_checking_type absent_type,
2188
struct unpack_trees_options *o)
2189
{
2190
const struct cache_entry *result;
@@ -2213,6 +2219,10 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
2219
return 0;
2220
}
2221
2222
+ /* If we only care about directories, then we can remove */
2223
+ if (absent_type == ABSENT_ANY_DIRECTORY)
2224
+ return 0;
2225
+
2226
/*
2227
* The previous round may already have decided to
2228
* delete this path, which is in a subdirectory that
@@ -2233,6 +2243,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
2243
*/
2244
static int verify_absent_1(const struct cache_entry *ce,
2245
enum unpack_trees_error_types error_type,
2246
+ enum absent_checking_type absent_type,
2247
struct unpack_trees_options *o)
2248
{
2249
int len;
@@ -2259,7 +2270,8 @@ static int verify_absent_1(const struct cache_entry *ce,
2270
NULL, o);
2271
else
2272
ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL,
2262
- &st, error_type, o);
2273
+ &st, error_type,
2274
+ absent_type, o);
2275
}
2276
free(path);
2277
return ret;
@@ -2274,7 +2286,7 @@ static int verify_absent_1(const struct cache_entry *ce,
2286
2287
return check_ok_to_remove(ce->name, ce_namelen(ce),
2288
ce_to_dtype(ce), ce, &st,
2277
- error_type, o);
2289
+ error_type, absent_type, o);
2290
}
2291
}
2292
@@ -2284,14 +2296,23 @@ static int verify_absent(const struct cache_entry *ce,
2296
{
2297
if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
2298
return 0;
2287
- return verify_absent_1(ce, error_type, o);
2299
+ return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o);
2300
+}
2301
+
2302
+static int verify_absent_if_directory(const struct cache_entry *ce,
2303
+ enum unpack_trees_error_types error_type,
2304
+ struct unpack_trees_options *o)
2305
+{
2306
+ if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE))
2307
+ return 0;
2308
+ return verify_absent_1(ce, error_type, ABSENT_ANY_DIRECTORY, o);
2309
}
2310
2311
static int verify_absent_sparse(const struct cache_entry *ce,
2312
enum unpack_trees_error_types error_type,
2313
struct unpack_trees_options *o)
2314
{
2294
- return verify_absent_1(ce, error_type, o);
2315
+ return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o);
2316
}
2317
2318
static int merged_entry(const struct cache_entry *ce,
@@ -2365,6 +2386,12 @@ static int merged_entry(const struct cache_entry *ce,
2386
* Previously unmerged entry left as an existence
2387
* marker by read_index_unmerged();
2388
*/
2389
+ if (verify_absent_if_directory(merge,
2390
+ ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
2391
+ discard_cache_entry(merge);
2392
+ return -1;
2393
+ }
2394
+
2395
invalidate_ce_path(old, o);
2396
}
2397