From 4c2390067030d67c1b79fd96eb656ae63b91643b Mon Sep 17 00:00:00 2001 From: Jialong Wang Date: Mon, 16 Mar 2026 21:15:44 -0400 Subject: [PATCH 1/9] t2203: avoid suppressing git status exit code When git status is piped into grep, the exit status of the Git command is hidden by the pipeline. Capture the status output in a temporary file first, and then filter it as needed, so that any failure from git status is still noticed by the test suite. Signed-off-by: Jialong Wang Signed-off-by: Junio C Hamano --- t/t2203-add-intent.sh | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/t/t2203-add-intent.sh b/t/t2203-add-intent.sh index 192ad14b5f474f..44c1936e4d698b 100755 --- a/t/t2203-add-intent.sh +++ b/t/t2203-add-intent.sh @@ -16,7 +16,8 @@ test_expect_success 'intent to add' ' ' test_expect_success 'git status' ' - git status --porcelain | grep -v actual >actual && + git status --porcelain >actual.raw && + grep -v actual actual.raw >actual && cat >expect <<-\EOF && DA 1.t A elif @@ -26,7 +27,8 @@ test_expect_success 'git status' ' ' test_expect_success 'git status with porcelain v2' ' - git status --porcelain=v2 | grep -v "^?" >actual && + git status --porcelain=v2 >actual.raw && + grep -v "^?" actual.raw >actual && nam1=$(echo 1 | git hash-object --stdin) && nam2=$(git hash-object elif) && cat >expect <<-EOF && @@ -171,17 +173,20 @@ test_expect_success 'rename detection finds the right names' ' mv first third && git add -N third && - git status | grep -v "^?" >actual.1 && + git status >actual.raw.1 && + grep -v "^?" actual.raw.1 >actual.1 && test_grep "renamed: *first -> third" actual.1 && - git status --porcelain | grep -v "^?" >actual.2 && + git status --porcelain >actual.raw.2 && + grep -v "^?" actual.raw.2 >actual.2 && cat >expected.2 <<-\EOF && R first -> third EOF test_cmp expected.2 actual.2 && hash=$(git hash-object third) && - git status --porcelain=v2 | grep -v "^?" >actual.3 && + git status --porcelain=v2 >actual.raw.3 && + grep -v "^?" actual.raw.3 >actual.3 && cat >expected.3 <<-EOF && 2 .R N... 100644 100644 100644 $hash $hash R100 third first EOF @@ -211,11 +216,13 @@ test_expect_success 'double rename detection in status' ' mv second third && git add -N third && - git status | grep -v "^?" >actual.1 && + git status >actual.raw.1 && + grep -v "^?" actual.raw.1 >actual.1 && test_grep "renamed: *first -> second" actual.1 && test_grep "renamed: *second -> third" actual.1 && - git status --porcelain | grep -v "^?" >actual.2 && + git status --porcelain >actual.raw.2 && + grep -v "^?" actual.raw.2 >actual.2 && cat >expected.2 <<-\EOF && R first -> second R second -> third @@ -223,7 +230,8 @@ test_expect_success 'double rename detection in status' ' test_cmp expected.2 actual.2 && hash=$(git hash-object third) && - git status --porcelain=v2 | grep -v "^?" >actual.3 && + git status --porcelain=v2 >actual.raw.3 && + grep -v "^?" actual.raw.3 >actual.3 && cat >expected.3 <<-EOF && 2 R. N... 100644 100644 100644 $hash $hash R100 second first 2 .R N... 100644 100644 100644 $hash $hash R100 third second From c5e15c9a58c0b32ec8be3ae96434834124de175e Mon Sep 17 00:00:00 2001 From: Jialong Wang Date: Tue, 17 Mar 2026 12:23:19 -0400 Subject: [PATCH 2/9] apply: report the location of corrupt patches When parsing a corrupt patch, git apply reports only the line number. That does not tell the user which input the line number refers to. Include the patch input path in the error message so the reported location is easier to use. Reset the line number for each patch input so the reported location stays correct when multiple input files are provided. Add tests for file input, standard input, multiple patch inputs, and existing binary-diff corrupt patch cases. Signed-off-by: Jialong Wang Signed-off-by: Junio C Hamano --- apply.c | 4 +++- t/t4012-diff-binary.sh | 4 ++-- t/t4100-apply-stat.sh | 38 +++++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/apply.c b/apply.c index b6dd1066a0c3e1..b7b0a201b38d4f 100644 --- a/apply.c +++ b/apply.c @@ -1875,7 +1875,8 @@ static int parse_single_patch(struct apply_state *state, len = parse_fragment(state, line, size, patch, fragment); if (len <= 0) { free(fragment); - return error(_("corrupt patch at line %d"), state->linenr); + return error(_("corrupt patch at %s:%d"), + state->patch_input_file, state->linenr); } fragment->patch = line; fragment->size = len; @@ -4825,6 +4826,7 @@ static int apply_patch(struct apply_state *state, int flush_attributes = 0; state->patch_input_file = filename; + state->linenr = 1; if (read_patch_file(&buf, fd) < 0) return -128; offset = 0; diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh index d1d30ac2a9474e..97b5ac04071d36 100755 --- a/t/t4012-diff-binary.sh +++ b/t/t4012-diff-binary.sh @@ -68,7 +68,7 @@ test_expect_success 'apply detecting corrupt patch correctly' ' sed -e "s/-CIT/xCIT/" broken && test_must_fail git apply --stat --summary broken 2>detected && detected=$(cat detected) && - detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") && + detected=$(expr "$detected" : "error.*broken:\\([0-9]*\\)\$") && detected=$(sed -ne "${detected}p" broken) && test "$detected" = xCIT ' @@ -77,7 +77,7 @@ test_expect_success 'apply detecting corrupt patch correctly' ' git diff --binary | sed -e "s/-CIT/xCIT/" >broken && test_must_fail git apply --stat --summary broken 2>detected && detected=$(cat detected) && - detected=$(expr "$detected" : "error.*at line \\([0-9]*\\)\$") && + detected=$(expr "$detected" : "error.*broken:\\([0-9]*\\)\$") && detected=$(sed -ne "${detected}p" broken) && test "$detected" = xCIT ' diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index a5664f3eb3c675..b19fc9fe50dd09 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -48,7 +48,43 @@ test_expect_success 'applying a hunk header which overflows fails' ' +b EOF test_must_fail git apply patch 2>err && - echo "error: corrupt patch at line 4" >expect && + echo "error: corrupt patch at patch:4" >expect && + test_cmp expect err +' + +test_expect_success 'applying a hunk header which overflows from stdin fails' ' + cat >patch <<-\EOF && + diff -u a/file b/file + --- a/file + +++ b/file + @@ -98765432109876543210 +98765432109876543210 @@ + -a + +b + EOF + test_must_fail git apply err && + echo "error: corrupt patch at :4" >expect && + test_cmp expect err +' + +test_expect_success 'applying multiple patches reports the corrupted input' ' + cat >good.patch <<-\EOF && + diff -u a/file b/file + --- a/file + +++ b/file + @@ -1 +1 @@ + -a + +b + EOF + cat >bad.patch <<-\EOF && + diff -u a/file b/file + --- a/file + +++ b/file + @@ -98765432109876543210 +98765432109876543210 @@ + -a + +b + EOF + test_must_fail git apply --stat --summary good.patch bad.patch 2>err && + echo "error: corrupt patch at bad.patch:4" >expect && test_cmp expect err ' test_done From 838c0ba5004b37009d8d2649ed1be7b77770c2f0 Mon Sep 17 00:00:00 2001 From: Jialong Wang Date: Tue, 17 Mar 2026 12:23:20 -0400 Subject: [PATCH 3/9] apply: report input location in header parsing errors Several header parsing errors in apply.c still report only line numbers. When applying more than one input, that does not tell the user which input the line belongs to. Report the patch input location for these header parsing errors, and update the related tests. While touching parse_git_diff_header(), update the helper state to use the current header line when reporting these errors. Signed-off-by: Jialong Wang Signed-off-by: Junio C Hamano --- apply.c | 86 ++++++++++++++++++++++++++++++++----------- apply.h | 1 + range-diff.c | 2 +- t/t4100-apply-stat.sh | 38 +++++++++++++++++++ t/t4254-am-corrupt.sh | 3 +- 5 files changed, 106 insertions(+), 24 deletions(-) diff --git a/apply.c b/apply.c index b7b0a201b38d4f..700809f3e6b5cf 100644 --- a/apply.c +++ b/apply.c @@ -42,6 +42,7 @@ struct gitdiff_data { struct strbuf *root; + const char *patch_input_file; int linenr; int p_value; }; @@ -900,7 +901,8 @@ static int parse_traditional_patch(struct apply_state *state, } } if (!name) - return error(_("unable to find filename in patch at line %d"), state->linenr); + return error(_("unable to find filename in patch at %s:%d"), + state->patch_input_file, state->linenr); return 0; } @@ -937,20 +939,35 @@ static int gitdiff_verify_name(struct gitdiff_data *state, if (*name) { char *another; - if (isnull) + if (isnull) { + if (state->patch_input_file) + return error(_("git apply: bad git-diff - expected /dev/null, got %s at %s:%d"), + *name, state->patch_input_file, state->linenr); return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"), *name, state->linenr); + } another = find_name(state->root, line, NULL, state->p_value, TERM_TAB); if (!another || strcmp(another, *name)) { free(another); + if (state->patch_input_file) + return error((side == DIFF_NEW_NAME) ? + _("git apply: bad git-diff - inconsistent new filename at %s:%d") : + _("git apply: bad git-diff - inconsistent old filename at %s:%d"), + state->patch_input_file, state->linenr); return error((side == DIFF_NEW_NAME) ? - _("git apply: bad git-diff - inconsistent new filename on line %d") : - _("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr); + _("git apply: bad git-diff - inconsistent new filename on line %d") : + _("git apply: bad git-diff - inconsistent old filename on line %d"), + state->linenr); } free(another); } else { - if (!is_dev_null(line)) - return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr); + if (!is_dev_null(line)) { + if (state->patch_input_file) + return error(_("git apply: bad git-diff - expected /dev/null at %s:%d"), + state->patch_input_file, state->linenr); + return error(_("git apply: bad git-diff - expected /dev/null on line %d"), + state->linenr); + } } return 0; @@ -974,12 +991,19 @@ static int gitdiff_newname(struct gitdiff_data *state, DIFF_NEW_NAME); } -static int parse_mode_line(const char *line, int linenr, unsigned int *mode) +static int parse_mode_line(const char *line, + const char *patch_input_file, + int linenr, + unsigned int *mode) { char *end; *mode = strtoul(line, &end, 8); - if (end == line || !isspace(*end)) + if (end == line || !isspace(*end)) { + if (patch_input_file) + return error(_("invalid mode at %s:%d: %s"), + patch_input_file, linenr, line); return error(_("invalid mode on line %d: %s"), linenr, line); + } *mode = canon_mode(*mode); return 0; } @@ -988,14 +1012,16 @@ static int gitdiff_oldmode(struct gitdiff_data *state, const char *line, struct patch *patch) { - return parse_mode_line(line, state->linenr, &patch->old_mode); + return parse_mode_line(line, state->patch_input_file, state->linenr, + &patch->old_mode); } static int gitdiff_newmode(struct gitdiff_data *state, const char *line, struct patch *patch) { - return parse_mode_line(line, state->linenr, &patch->new_mode); + return parse_mode_line(line, state->patch_input_file, state->linenr, + &patch->new_mode); } static int gitdiff_delete(struct gitdiff_data *state, @@ -1314,6 +1340,7 @@ static int check_header_line(int linenr, struct patch *patch) } int parse_git_diff_header(struct strbuf *root, + const char *patch_input_file, int *linenr, int p_value, const char *line, @@ -1345,6 +1372,7 @@ int parse_git_diff_header(struct strbuf *root, size -= len; (*linenr)++; parse_hdr_state.root = root; + parse_hdr_state.patch_input_file = patch_input_file; parse_hdr_state.linenr = *linenr; parse_hdr_state.p_value = p_value; @@ -1382,6 +1410,7 @@ int parse_git_diff_header(struct strbuf *root, int res; if (len < oplen || memcmp(p->str, line, oplen)) continue; + parse_hdr_state.linenr = *linenr; res = p->fn(&parse_hdr_state, line + oplen, patch); if (res < 0) return -1; @@ -1396,12 +1425,20 @@ int parse_git_diff_header(struct strbuf *root, done: if (!patch->old_name && !patch->new_name) { if (!patch->def_name) { - error(Q_("git diff header lacks filename information when removing " - "%d leading pathname component (line %d)", - "git diff header lacks filename information when removing " - "%d leading pathname components (line %d)", - parse_hdr_state.p_value), - parse_hdr_state.p_value, *linenr); + if (patch_input_file) + error(Q_("git diff header lacks filename information when removing " + "%d leading pathname component at %s:%d", + "git diff header lacks filename information when removing " + "%d leading pathname components at %s:%d", + parse_hdr_state.p_value), + parse_hdr_state.p_value, patch_input_file, *linenr); + else + error(Q_("git diff header lacks filename information when removing " + "%d leading pathname component (line %d)", + "git diff header lacks filename information when removing " + "%d leading pathname components (line %d)", + parse_hdr_state.p_value), + parse_hdr_state.p_value, *linenr); return -128; } patch->old_name = xstrdup(patch->def_name); @@ -1409,8 +1446,12 @@ int parse_git_diff_header(struct strbuf *root, } if ((!patch->new_name && !patch->is_delete) || (!patch->old_name && !patch->is_new)) { - error(_("git diff header lacks filename information " - "(line %d)"), *linenr); + if (patch_input_file) + error(_("git diff header lacks filename information at %s:%d"), + patch_input_file, *linenr); + else + error(_("git diff header lacks filename information (line %d)"), + *linenr); return -128; } patch->is_toplevel_relative = 1; @@ -1577,8 +1618,9 @@ static int find_header(struct apply_state *state, struct fragment dummy; if (parse_fragment_header(line, len, &dummy) < 0) continue; - error(_("patch fragment without header at line %d: %.*s"), - state->linenr, (int)len-1, line); + error(_("patch fragment without header at %s:%d: %.*s"), + state->patch_input_file, state->linenr, + (int)len-1, line); return -128; } @@ -1590,7 +1632,9 @@ static int find_header(struct apply_state *state, * or mode change, so we handle that specially */ if (!memcmp("diff --git ", line, 11)) { - int git_hdr_len = parse_git_diff_header(&state->root, &state->linenr, + int git_hdr_len = parse_git_diff_header(&state->root, + state->patch_input_file, + &state->linenr, state->p_value, line, len, size, patch); if (git_hdr_len < 0) diff --git a/apply.h b/apply.h index 90e887ec0edadf..5f2f03d3ede23c 100644 --- a/apply.h +++ b/apply.h @@ -167,6 +167,7 @@ int check_apply_state(struct apply_state *state, int force_apply); * Returns -1 on failure, the length of the parsed header otherwise. */ int parse_git_diff_header(struct strbuf *root, + const char *patch_input_file, int *linenr, int p_value, const char *line, diff --git a/range-diff.c b/range-diff.c index 57edff40a85f24..2712a9a107ab06 100644 --- a/range-diff.c +++ b/range-diff.c @@ -140,7 +140,7 @@ static int read_patches(const char *range, struct string_list *list, if (eol) *eol = '\n'; orig_len = len; - len = parse_git_diff_header(&root, &linenr, 0, line, + len = parse_git_diff_header(&root, NULL, &linenr, 0, line, len, size, &patch); if (len < 0) { error(_("could not parse git header '%.*s'"), diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index b19fc9fe50dd09..b3d93d8ed6cda7 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -87,4 +87,42 @@ test_expect_success 'applying multiple patches reports the corrupted input' ' echo "error: corrupt patch at bad.patch:4" >expect && test_cmp expect err ' + +test_expect_success 'applying a patch without a header reports the input' ' + cat >fragment.patch <<-\EOF && + @@ -1 +1 @@ + -a + +b + EOF + test_must_fail git apply fragment.patch 2>err && + echo "error: patch fragment without header at fragment.patch:1: @@ -1 +1 @@" >expect && + test_cmp expect err +' + +test_expect_success 'applying a patch with a missing filename reports the input' ' + cat >missing.patch <<-\EOF && + diff --git a/f b/f + index 7898192..6178079 100644 + --- a/f + @@ -1 +1 @@ + -a + +b + EOF + test_must_fail git apply missing.patch 2>err && + echo "error: git diff header lacks filename information at missing.patch:4" >expect && + test_cmp expect err +' + +test_expect_success 'applying a patch with an invalid mode reports the input' ' + cat >mode.patch <<-\EOF && + diff --git a/f b/f + old mode 10x644 + EOF + test_must_fail git apply mode.patch 2>err && + cat >expect <<-\EOF && + error: invalid mode at mode.patch:2: 10x644 + + EOF + test_cmp expect err +' test_done diff --git a/t/t4254-am-corrupt.sh b/t/t4254-am-corrupt.sh index ae0a56cf5ec2d7..96ddf3c53a45b9 100755 --- a/t/t4254-am-corrupt.sh +++ b/t/t4254-am-corrupt.sh @@ -65,9 +65,8 @@ test_expect_success setup ' test_expect_success 'try to apply corrupted patch' ' test_when_finished "git am --abort" && test_must_fail git -c advice.amWorkDir=false -c advice.mergeConflict=false am bad-patch.diff 2>actual && - echo "error: git diff header lacks filename information (line 4)" >expected && test_path_is_file f && - test_cmp expected actual + test_grep "error: git diff header lacks filename information at .*rebase-apply/patch:4" actual ' test_expect_success "NUL in commit message's body" ' From 2ef795b027c10f5e253151106a6fb4265552cc04 Mon Sep 17 00:00:00 2001 From: Jialong Wang Date: Tue, 17 Mar 2026 12:23:21 -0400 Subject: [PATCH 4/9] apply: report input location in binary and garbage patch errors Several binary parsing paths in apply.c still report only line numbers. When more than one patch input is fed to a single invocation, that does not tell the user which input the line belongs to. Report the patch input location for corrupt and unrecognized binary patches, as well as the "patch with only garbage" case, and update the related tests. Signed-off-by: Jialong Wang Signed-off-by: Junio C Hamano --- apply.c | 10 ++++++---- t/t4100-apply-stat.sh | 12 ++++++++++++ t/t4103-apply-binary.sh | 20 +++++++++++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/apply.c b/apply.c index 700809f3e6b5cf..84b4a569c58b6a 100644 --- a/apply.c +++ b/apply.c @@ -2110,8 +2110,8 @@ static struct fragment *parse_binary_hunk(struct apply_state *state, corrupt: free(data); *status_p = -1; - error(_("corrupt binary patch at line %d: %.*s"), - state->linenr-1, llen-1, buffer); + error(_("corrupt binary patch at %s:%d: %.*s"), + state->patch_input_file, state->linenr-1, llen-1, buffer); return NULL; } @@ -2147,7 +2147,8 @@ static int parse_binary(struct apply_state *state, forward = parse_binary_hunk(state, &buffer, &size, &status, &used); if (!forward && !status) /* there has to be one hunk (forward hunk) */ - return error(_("unrecognized binary patch at line %d"), state->linenr-1); + return error(_("unrecognized binary patch at %s:%d"), + state->patch_input_file, state->linenr-1); if (status) /* otherwise we already gave an error message */ return status; @@ -2309,7 +2310,8 @@ static int parse_chunk(struct apply_state *state, char *buffer, unsigned long si */ if ((state->apply || state->check) && (!patch->is_binary && !metadata_changes(patch))) { - error(_("patch with only garbage at line %d"), state->linenr); + error(_("patch with only garbage at %s:%d"), + state->patch_input_file, state->linenr); return -128; } } diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index b3d93d8ed6cda7..8393076469e083 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -125,4 +125,16 @@ test_expect_success 'applying a patch with an invalid mode reports the input' ' EOF test_cmp expect err ' + +test_expect_success 'applying a patch with only garbage reports the input' ' + cat >garbage.patch <<-\EOF && + diff --git a/f b/f + --- a/f + +++ b/f + this is garbage + EOF + test_must_fail git apply garbage.patch 2>err && + echo "error: patch with only garbage at garbage.patch:4" >expect && + test_cmp expect err +' test_done diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh index 8e302a5a57e820..f2d41e06bcdd63 100755 --- a/t/t4103-apply-binary.sh +++ b/t/t4103-apply-binary.sh @@ -179,6 +179,24 @@ test_expect_success PERL_TEST_HELPERS 'reject truncated binary diff' ' " patch.trunc && do_reset && - test_must_fail git apply patch.trunc + test_must_fail git apply patch.trunc 2>err && + line=$(awk "END { print NR + 1 }" patch.trunc) && + grep "error: corrupt binary patch at patch.trunc:$line: " err +' + +test_expect_success 'reject unrecognized binary diff' ' + cat >patch.bad <<-\EOF && + diff --git a/f b/f + new file mode 100644 + index 0000000..7898192 + GIT binary patch + bogus + EOF + test_must_fail git apply patch.bad 2>err && + cat >expect <<-\EOF && + error: unrecognized binary patch at patch.bad:4 + error: No valid patches in input (allow with "--allow-empty") + EOF + test_cmp expect err ' test_done From c5fc44f54595f123c277e5839cbafa1bc9c8c050 Mon Sep 17 00:00:00 2001 From: Jialong Wang Date: Wed, 18 Mar 2026 15:09:42 -0400 Subject: [PATCH 5/9] object-name: turn INTERPRET_BRANCH_* constants into enum values Replace the INTERPRET_BRANCH_* preprocessor constants with enum values and use that type where these flags are stored or passed around. These flags describe which kinds of branches may be considered during branch-name interpretation, so represent them as an enum describing branch kinds while keeping the existing bitmask semantics and INTERPRET_BRANCH_* element names. Signed-off-by: Jialong Wang Signed-off-by: Junio C Hamano --- builtin/branch.c | 2 +- object-name.c | 6 ++++-- object-name.h | 11 +++++++---- refs.c | 3 ++- refs.h | 3 ++- 5 files changed, 16 insertions(+), 9 deletions(-) diff --git a/builtin/branch.c b/builtin/branch.c index a1a43380d0640b..1572a4f9ef2ab6 100644 --- a/builtin/branch.c +++ b/builtin/branch.c @@ -228,7 +228,7 @@ static int delete_branches(int argc, const char **argv, int force, int kinds, int ret = 0; int remote_branch = 0; struct strbuf bname = STRBUF_INIT; - unsigned allowed_interpret; + enum interpret_branch_kind allowed_interpret; struct string_list refs_to_delete = STRING_LIST_INIT_DUP; struct string_list_item *item; int branch_name_pos; diff --git a/object-name.c b/object-name.c index 7b14c3bf9b9b48..2b2a0435fdee9e 100644 --- a/object-name.c +++ b/object-name.c @@ -1660,7 +1660,8 @@ static int interpret_empty_at(const char *name, int namelen, int len, struct str static int reinterpret(struct repository *r, const char *name, int namelen, int len, - struct strbuf *buf, unsigned allowed) + struct strbuf *buf, + enum interpret_branch_kind allowed) { /* we have extra data, which might need further processing */ struct strbuf tmp = STRBUF_INIT; @@ -1692,7 +1693,8 @@ static void set_shortened_ref(struct repository *r, struct strbuf *buf, const ch free(s); } -static int branch_interpret_allowed(const char *refname, unsigned allowed) +static int branch_interpret_allowed(const char *refname, + enum interpret_branch_kind allowed) { if (!allowed) return 1; diff --git a/object-name.h b/object-name.h index cda4934cd5f7fb..167a9154ea2d67 100644 --- a/object-name.h +++ b/object-name.h @@ -101,9 +101,12 @@ int set_disambiguate_hint_config(const char *var, const char *value); * If the input was ok but there are not N branch switches in the * reflog, it returns 0. */ -#define INTERPRET_BRANCH_LOCAL (1<<0) -#define INTERPRET_BRANCH_REMOTE (1<<1) -#define INTERPRET_BRANCH_HEAD (1<<2) +enum interpret_branch_kind { + INTERPRET_BRANCH_LOCAL = (1 << 0), + INTERPRET_BRANCH_REMOTE = (1 << 1), + INTERPRET_BRANCH_HEAD = (1 << 2), +}; + struct interpret_branch_name_options { /* * If "allowed" is non-zero, it is a treated as a bitfield of allowable @@ -111,7 +114,7 @@ struct interpret_branch_name_options { * ("refs/remotes/"), or "HEAD". If no "allowed" bits are set, any expansion is * allowed, even ones to refs outside of those namespaces. */ - unsigned allowed; + enum interpret_branch_kind allowed; /* * If ^{upstream} or ^{push} (or equivalent) is requested, and the diff --git a/refs.c b/refs.c index 6fb8f9d10c9800..18b28db6d40c77 100644 --- a/refs.c +++ b/refs.c @@ -740,7 +740,8 @@ static char *substitute_branch_name(struct repository *r, return NULL; } -void copy_branchname(struct strbuf *sb, const char *name, unsigned allowed) +void copy_branchname(struct strbuf *sb, const char *name, + enum interpret_branch_kind allowed) { int len = strlen(name); struct interpret_branch_name_options options = { diff --git a/refs.h b/refs.h index d98c1fc5913d98..d65de6ab5fe11b 100644 --- a/refs.h +++ b/refs.h @@ -1,6 +1,7 @@ #ifndef REFS_H #define REFS_H +#include "object-name.h" #include "commit.h" #include "repository.h" #include "repo-settings.h" @@ -225,7 +226,7 @@ char *repo_default_branch_name(struct repository *r, int quiet); * repo_interpret_branch_name() for details. */ void copy_branchname(struct strbuf *sb, const char *name, - unsigned allowed); + enum interpret_branch_kind allowed); /* * Like copy_branchname() above, but confirm that the result is From 638c7bfbbed1d003abdcdce7c51032c772f3303f Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 18 Mar 2026 20:07:35 +0000 Subject: [PATCH 6/9] t2107: modernize path existence check Replace '! test -f' with 'test_path_is_missing' to get better debugging information by reporting loudly what expectation was not met when the assertion fails. Signed-off-by: Aditya Signed-off-by: Junio C Hamano --- t/t2107-update-index-basic.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t2107-update-index-basic.sh b/t/t2107-update-index-basic.sh index cc72ead79f3978..3bffe5da8a87cc 100755 --- a/t/t2107-update-index-basic.sh +++ b/t/t2107-update-index-basic.sh @@ -86,7 +86,7 @@ test_expect_success '.lock files cleaned up' ' # the_index.cache_changed is zero, rollback_lock_file fails git update-index --refresh --verbose >out && test_must_be_empty out && - ! test -f .git/index.lock + test_path_is_missing .git/index.lock ) ' From 60d8b5af9b553230faaae4fd276398d4f9fe4e39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Thu, 19 Mar 2026 17:24:40 +0100 Subject: [PATCH 7/9] commit-reach: simplify cleanup of remaining bitmaps in ahead_behind () MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't bother extracting the last few remaining prio_queue items in order when we only want to free their associated bitmaps; just iterate over the item array. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- commit-reach.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/commit-reach.c b/commit-reach.c index 9604bbdcce2f35..d3a9b3ed6fe561 100644 --- a/commit-reach.c +++ b/commit-reach.c @@ -1117,10 +1117,8 @@ void ahead_behind(struct repository *r, /* STALE is used here, PARENT2 is used by insert_no_dup(). */ repo_clear_commit_marks(r, PARENT2 | STALE); - while (prio_queue_peek(&queue)) { - struct commit *c = prio_queue_get(&queue); - free_bit_array(c); - } + for (size_t i = 0; i < queue.nr; i++) + free_bit_array(queue.array[i].data); clear_bit_arrays(&bit_arrays); clear_prio_queue(&queue); } From 84df6e350125f22c45060ad3233691621c5de671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Thu, 19 Mar 2026 19:48:07 +0100 Subject: [PATCH 8/9] split-index: stop using the_repository and the_hash_algo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reference the hash algorithm of the passed-in index throughout the code. Signed-off-by: René Scharfe Signed-off-by: Junio C Hamano --- split-index.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/split-index.c b/split-index.c index 4c74c4adda45d6..6ba210738c51f6 100644 --- a/split-index.c +++ b/split-index.c @@ -1,4 +1,3 @@ -#define USE_THE_REPOSITORY_VARIABLE #define DISABLE_SIGN_COMPARE_WARNINGS #include "git-compat-util.h" @@ -6,6 +5,7 @@ #include "hash.h" #include "mem-pool.h" #include "read-cache-ll.h" +#include "repository.h" #include "split-index.h" #include "strbuf.h" #include "ewah/ewok.h" @@ -25,16 +25,17 @@ struct split_index *init_split_index(struct index_state *istate) int read_link_extension(struct index_state *istate, const void *data_, unsigned long sz) { + const struct git_hash_algo *algo = istate->repo->hash_algo; const unsigned char *data = data_; struct split_index *si; int ret; - if (sz < the_hash_algo->rawsz) + if (sz < algo->rawsz) return error("corrupt link extension (too short)"); si = init_split_index(istate); - oidread(&si->base_oid, data, the_repository->hash_algo); - data += the_hash_algo->rawsz; - sz -= the_hash_algo->rawsz; + oidread(&si->base_oid, data, algo); + data += algo->rawsz; + sz -= algo->rawsz; if (!sz) return 0; si->delete_bitmap = ewah_new(); @@ -56,7 +57,7 @@ int write_link_extension(struct strbuf *sb, struct index_state *istate) { struct split_index *si = istate->split_index; - strbuf_add(sb, si->base_oid.hash, the_hash_algo->rawsz); + strbuf_add(sb, si->base_oid.hash, istate->repo->hash_algo->rawsz); if (!si->delete_bitmap && !si->replace_bitmap) return 0; ewah_serialize_strbuf(si->delete_bitmap, sb); From 270e10ad6dda3379ea0da7efd11e4fbf2cd7a325 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 30 Mar 2026 13:56:44 -0700 Subject: [PATCH 9/9] The 23rd batch Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.54.0.adoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/RelNotes/2.54.0.adoc b/Documentation/RelNotes/2.54.0.adoc index 4a3e0d3dfb0126..f7b2db616d0413 100644 --- a/Documentation/RelNotes/2.54.0.adoc +++ b/Documentation/RelNotes/2.54.0.adoc @@ -100,6 +100,10 @@ UI, Workflows & Features * The reference-transaction hook was taught to be triggered before taking locks on references in the "preparing" phase. + * "git apply" now reports the name of the input file along with the + line number when it encounters a corrupt patch, and correctly + resets the line counter when processing multiple patch files. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -239,6 +243,16 @@ Performance, Internal Implementation, Development Support etc. * Uses of prio_queue as a LIFO stack of commits have been written with commit_stack. + * The cleanup of remaining bitmaps in "ahead_behind()" has been + simplified. + + * split-index.c has been updated to not use the global the_repository + and the_hash_algo variables. + + * The unsigned integer that is used as an bitset to specify the kind + of branches interpret_branch_name() function has been changed to + use a dedicated enum type. + Fixes since v2.53 -----------------