Git fork

Merge branch 'jk/diff-no-index-with-pathspec-fix' into maint-2.51

An earlier addition to "git diff --no-index A B" to limit the
output with pathspec after the two directories misbehaved when
these directories were given with a trailing slash, which has been
corrected.

* jk/diff-no-index-with-pathspec-fix:
diff --no-index: fix logic for paths ending in '/'

+51 -28
+35 -28
diff-no-index.c
··· 21 21 22 22 static int read_directory_contents(const char *path, struct string_list *list, 23 23 const struct pathspec *pathspec, 24 - int skip) 24 + struct strbuf *match) 25 25 { 26 - struct strbuf match = STRBUF_INIT; 27 - int len; 26 + int len = match->len; 28 27 DIR *dir; 29 28 struct dirent *e; 30 29 31 30 if (!(dir = opendir(path))) 32 31 return error("Could not open directory %s", path); 33 32 34 - if (pathspec) { 35 - strbuf_addstr(&match, path); 36 - strbuf_complete(&match, '/'); 37 - strbuf_remove(&match, 0, skip); 38 - 39 - len = match.len; 40 - } 41 - 42 33 while ((e = readdir_skip_dot_and_dotdot(dir))) { 43 34 if (pathspec) { 44 35 int is_dir = 0; 45 36 46 - strbuf_setlen(&match, len); 47 - strbuf_addstr(&match, e->d_name); 37 + strbuf_setlen(match, len); 38 + strbuf_addstr(match, e->d_name); 48 39 if (NOT_CONSTANT(DTYPE(e)) != DT_UNKNOWN) { 49 40 is_dir = (DTYPE(e) == DT_DIR); 50 41 } else { ··· 57 48 } 58 49 59 50 if (!match_leading_pathspec(NULL, pathspec, 60 - match.buf, match.len, 51 + match->buf, match->len, 61 52 0, NULL, is_dir)) 62 53 continue; 63 54 } ··· 65 56 string_list_insert(list, e->d_name); 66 57 } 67 58 68 - strbuf_release(&match); 59 + strbuf_setlen(match, len); 69 60 closedir(dir); 70 61 return 0; 71 62 } ··· 169 160 170 161 static int queue_diff(struct diff_options *o, const struct git_hash_algo *algop, 171 162 const char *name1, const char *name2, int recursing, 172 - const struct pathspec *ps, int skip1, int skip2) 163 + const struct pathspec *ps, 164 + struct strbuf *ps_match1, struct strbuf *ps_match2) 173 165 { 174 166 int mode1 = 0, mode2 = 0; 175 167 enum special special1 = SPECIAL_NONE, special2 = SPECIAL_NONE; ··· 208 200 struct string_list p2 = STRING_LIST_INIT_DUP; 209 201 int i1, i2, ret = 0; 210 202 size_t len1 = 0, len2 = 0; 203 + size_t match1_len = ps_match1->len; 204 + size_t match2_len = ps_match2->len; 211 205 212 - if (name1 && read_directory_contents(name1, &p1, ps, skip1)) 206 + if (name1 && read_directory_contents(name1, &p1, ps, ps_match1)) 213 207 return -1; 214 - if (name2 && read_directory_contents(name2, &p2, ps, skip2)) { 208 + if (name2 && read_directory_contents(name2, &p2, ps, ps_match2)) { 215 209 string_list_clear(&p1, 0); 216 210 return -1; 217 211 } ··· 235 229 strbuf_setlen(&buffer1, len1); 236 230 strbuf_setlen(&buffer2, len2); 237 231 232 + if (ps) { 233 + strbuf_setlen(ps_match1, match1_len); 234 + strbuf_setlen(ps_match2, match2_len); 235 + } 236 + 238 237 if (i1 == p1.nr) 239 238 comp = 1; 240 239 else if (i2 == p2.nr) ··· 245 244 if (comp > 0) 246 245 n1 = NULL; 247 246 else { 248 - strbuf_addstr(&buffer1, p1.items[i1++].string); 247 + strbuf_addstr(&buffer1, p1.items[i1].string); 248 + if (ps) { 249 + strbuf_addstr(ps_match1, p1.items[i1].string); 250 + strbuf_complete(ps_match1, '/'); 251 + } 249 252 n1 = buffer1.buf; 253 + i1++; 250 254 } 251 255 252 256 if (comp < 0) 253 257 n2 = NULL; 254 258 else { 255 - strbuf_addstr(&buffer2, p2.items[i2++].string); 259 + strbuf_addstr(&buffer2, p2.items[i2].string); 260 + if (ps) { 261 + strbuf_addstr(ps_match2, p2.items[i2].string); 262 + strbuf_complete(ps_match2, '/'); 263 + } 256 264 n2 = buffer2.buf; 265 + i2++; 257 266 } 258 267 259 - ret = queue_diff(o, algop, n1, n2, 1, ps, skip1, skip2); 268 + ret = queue_diff(o, algop, n1, n2, 1, ps, ps_match1, ps_match2); 260 269 } 261 270 string_list_clear(&p1, 0); 262 271 string_list_clear(&p2, 0); ··· 346 355 int implicit_no_index, int argc, const char **argv) 347 356 { 348 357 struct pathspec pathspec, *ps = NULL; 349 - int i, no_index, skip1 = 0, skip2 = 0; 358 + struct strbuf ps_match1 = STRBUF_INIT, ps_match2 = STRBUF_INIT; 359 + int i, no_index; 350 360 int ret = 1; 351 361 const char *paths[2]; 352 362 char *to_free[ARRAY_SIZE(paths)] = { 0 }; ··· 387 397 NULL, &argv[2]); 388 398 if (pathspec.nr) 389 399 ps = &pathspec; 390 - 391 - skip1 = strlen(paths[0]); 392 - skip1 += paths[0][skip1] == '/' ? 0 : 1; 393 - skip2 = strlen(paths[1]); 394 - skip2 += paths[1][skip2] == '/' ? 0 : 1; 395 400 } else if (argc > 2) { 396 401 warning(_("Limiting comparison with pathspecs is only " 397 402 "supported if both paths are directories.")); ··· 415 420 revs->diffopt.flags.exit_with_status = 1; 416 421 417 422 if (queue_diff(&revs->diffopt, algop, paths[0], paths[1], 0, ps, 418 - skip1, skip2)) 423 + &ps_match1, &ps_match2)) 419 424 goto out; 420 425 diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/"); 421 426 diffcore_std(&revs->diffopt); ··· 431 436 for (i = 0; i < ARRAY_SIZE(to_free); i++) 432 437 free(to_free[i]); 433 438 strbuf_release(&replacement); 439 + strbuf_release(&ps_match1); 440 + strbuf_release(&ps_match2); 434 441 if (ps) 435 442 clear_pathspec(ps); 436 443 return ret;
+16
t/t4053-diff-no-index.sh
··· 339 339 test_cmp expect actual 340 340 ' 341 341 342 + test_expect_success 'diff --no-index first path ending in slash with pathspec' ' 343 + test_expect_code 1 git diff --name-status --no-index a/ b 1 >actual && 344 + cat >expect <<-EOF && 345 + D a/1 346 + EOF 347 + test_cmp expect actual 348 + ' 349 + 350 + test_expect_success 'diff --no-index second path ending in slash with pathspec' ' 351 + test_expect_code 1 git diff --name-status --no-index a b/ 1 >actual && 352 + cat >expect <<-EOF && 353 + D a/1 354 + EOF 355 + test_cmp expect actual 356 + ' 357 + 342 358 test_expect_success 'diff --no-index with pathspec no matches' ' 343 359 test_expect_code 0 git diff --name-status --no-index a b missing 344 360 '