From 44451a2e5eec5360378be23e2cdbd9ecee49e14e Mon Sep 17 00:00:00 2001 From: John Cai Date: Sat, 6 May 2023 04:15:29 +0000 Subject: [PATCH 01/16] attr: teach "--attr-source=" global option to "git" Earlier, 47cfc9bd (attr: add flag `--source` to work with tree-ish, 2023-01-14) taught "git check-attr" the "--source=" option to allow it to read attribute files from a tree-ish, but did so only for the command. Just like "check-attr" users wanted a way to use attributes from a tree-ish and not from the working tree files, users of other commands (like "git diff") would benefit from the same. Undo most of the UI change the commit made, while keeping the internal logic to read attributes from a given tree-ish. Expose the internal logic via a new "--attr-source=" command line option given to "git", so that it can be used with any git command that runs as part of the main git process. Additionally, add an environment variable GIT_ATTR_SOURCE that is set when --attr-source is passed in, so that subprocesses use the same value for the attributes source tree. Signed-off-by: John Cai Signed-off-by: Junio C Hamano --- Documentation/git.txt | 8 ++++++++ archive.c | 2 +- attr.c | 37 +++++++++++++++++++++++++++++++++++-- attr.h | 13 +++++++++---- builtin/check-attr.c | 17 ++++++++--------- builtin/pack-objects.c | 2 +- convert.c | 2 +- environment.h | 1 + git.c | 16 ++++++++++++++++ ll-merge.c | 4 ++-- pathspec.c | 2 +- t/lib-diff-alternative.sh | 31 ++++++++++++++++++++++++++----- t/t0003-attributes.sh | 11 ++++++++++- t/t4018-diff-funcname.sh | 19 +++++++++++++++++++ userdiff.c | 2 +- ws.c | 2 +- 16 files changed, 140 insertions(+), 29 deletions(-) diff --git a/Documentation/git.txt b/Documentation/git.txt index 74973d3cc4..02707cb01d 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -212,6 +212,11 @@ If you just want to run git as if it was started in `` then use nohelpers (exclude helper commands), alias and config (retrieve command list from config variable completion.commands) +--attr-source=:: + Read gitattributes from instead of the worktree. See + linkgit:gitattributes[5]. This is equivalent to setting the + `GIT_ATTR_SOURCE` environment variable. + GIT COMMANDS ------------ @@ -686,6 +691,9 @@ for further details. tells Git not to verify the SSL certificate when fetching or pushing over HTTPS. +`GIT_ATTR_SOURCE`:: + Sets the treeish that gitattributes will be read from. + `GIT_ASKPASS`:: If this environment variable is set, then Git commands which need to acquire passwords or passphrases (e.g. for HTTP or IMAP authentication) diff --git a/archive.c b/archive.c index 8570cf37ff..e809514fe7 100644 --- a/archive.c +++ b/archive.c @@ -128,7 +128,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate, static struct attr_check *check; if (!check) check = attr_check_initl("export-ignore", "export-subst", NULL); - git_check_attr(istate, NULL, path, check); + git_check_attr(istate, path, check); return check; } diff --git a/attr.c b/attr.c index 2d8aeb8b58..11238d6083 100644 --- a/attr.c +++ b/attr.c @@ -20,6 +20,7 @@ #include "object-store.h" #include "setup.h" #include "thread-utils.h" +#include "object-name.h" const char git_attr__true[] = "(builtin)true"; const char git_attr__false[] = "\0(builtin)false"; @@ -1169,11 +1170,42 @@ static void collect_some_attrs(struct index_state *istate, fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem); } +static const char *default_attr_source_tree_object_name; + +void set_git_attr_source(const char *tree_object_name) +{ + default_attr_source_tree_object_name = xstrdup(tree_object_name); +} + +static void compute_default_attr_source(struct object_id *attr_source) +{ + if (!default_attr_source_tree_object_name) + default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT); + + if (!default_attr_source_tree_object_name || !is_null_oid(attr_source)) + return; + + if (repo_get_oid_treeish(the_repository, default_attr_source_tree_object_name, attr_source)) + die(_("bad --attr-source or GIT_ATTR_SOURCE")); +} + +static struct object_id *default_attr_source(void) +{ + static struct object_id attr_source; + + if (is_null_oid(&attr_source)) + compute_default_attr_source(&attr_source); + if (is_null_oid(&attr_source)) + return NULL; + return &attr_source; +} + void git_check_attr(struct index_state *istate, - const struct object_id *tree_oid, const char *path, + const char *path, struct attr_check *check) { int i; + const struct object_id *tree_oid = default_attr_source(); collect_some_attrs(istate, tree_oid, path, check); @@ -1186,10 +1218,11 @@ void git_check_attr(struct index_state *istate, } } -void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid, +void git_all_attrs(struct index_state *istate, const char *path, struct attr_check *check) { int i; + const struct object_id *tree_oid = default_attr_source(); attr_check_reset(check); collect_some_attrs(istate, tree_oid, path, check); diff --git a/attr.h b/attr.h index 9884ea2bc6..676bd17ce2 100644 --- a/attr.h +++ b/attr.h @@ -45,7 +45,7 @@ * const char *path; * * setup_check(); - * git_check_attr(&the_index, tree_oid, path, check); + * git_check_attr(&the_index, path, check); * ------------ * * - Act on `.value` member of the result, left in `check->items[]`: @@ -120,7 +120,6 @@ #define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024) struct index_state; -struct object_id; /** * An attribute is an opaque object that is identified by its name. Pass the @@ -135,6 +134,12 @@ struct git_attr; struct all_attrs_item; struct attr_stack; +/* + * The textual object name for the tree-ish used by git_check_attr() + * to read attributes from (instead of from the working tree). + */ +void set_git_attr_source(const char *); + /* * Given a string, return the gitattribute object that * corresponds to it. @@ -203,14 +208,14 @@ void attr_check_free(struct attr_check *check); const char *git_attr_name(const struct git_attr *); void git_check_attr(struct index_state *istate, - const struct object_id *tree_oid, const char *path, + const char *path, struct attr_check *check); /* * Retrieve all attributes that apply to the specified path. * check holds the attributes and their values. */ -void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid, +void git_all_attrs(struct index_state *istate, const char *path, struct attr_check *check); enum git_attr_direction { diff --git a/builtin/check-attr.c b/builtin/check-attr.c index 037bf1aaa2..748f3578b2 100644 --- a/builtin/check-attr.c +++ b/builtin/check-attr.c @@ -63,7 +63,7 @@ static void output_attr(struct attr_check *check, const char *file) } static void check_attr(const char *prefix, struct attr_check *check, - const struct object_id *tree_oid, int collect_all, + int collect_all, const char *file) { @@ -71,9 +71,9 @@ static void check_attr(const char *prefix, struct attr_check *check, prefix_path(prefix, prefix ? strlen(prefix) : 0, file); if (collect_all) { - git_all_attrs(&the_index, tree_oid, full_path, check); + git_all_attrs(&the_index, full_path, check); } else { - git_check_attr(&the_index, tree_oid, full_path, check); + git_check_attr(&the_index, full_path, check); } output_attr(check, file); @@ -81,7 +81,7 @@ static void check_attr(const char *prefix, struct attr_check *check, } static void check_attr_stdin_paths(const char *prefix, struct attr_check *check, - const struct object_id *tree_oid, int collect_all) + int collect_all) { struct strbuf buf = STRBUF_INIT; struct strbuf unquoted = STRBUF_INIT; @@ -95,7 +95,7 @@ static void check_attr_stdin_paths(const char *prefix, struct attr_check *check, die("line is badly quoted"); strbuf_swap(&buf, &unquoted); } - check_attr(prefix, check, tree_oid, collect_all, buf.buf); + check_attr(prefix, check, collect_all, buf.buf); maybe_flush_or_die(stdout, "attribute to stdout"); } strbuf_release(&buf); @@ -111,7 +111,6 @@ static NORETURN void error_with_usage(const char *msg) int cmd_check_attr(int argc, const char **argv, const char *prefix) { struct attr_check *check; - struct object_id *tree_oid = NULL; struct object_id initialized_oid; int cnt, i, doubledash, filei; @@ -187,14 +186,14 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix) if (source) { if (repo_get_oid_tree(the_repository, source, &initialized_oid)) die("%s: not a valid tree-ish source", source); - tree_oid = &initialized_oid; + set_git_attr_source(source); } if (stdin_paths) - check_attr_stdin_paths(prefix, check, tree_oid, all_attrs); + check_attr_stdin_paths(prefix, check, all_attrs); else { for (i = filei; i < argc; i++) - check_attr(prefix, check, tree_oid, all_attrs, argv[i]); + check_attr(prefix, check, all_attrs, argv[i]); maybe_flush_or_die(stdout, "attribute to stdout"); } diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index a5b466839b..9cfc8801f9 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -1331,7 +1331,7 @@ static int no_try_delta(const char *path) if (!check) check = attr_check_initl("delta", NULL); - git_check_attr(the_repository->index, NULL, path, check); + git_check_attr(the_repository->index, path, check); if (ATTR_FALSE(check->items[0].value)) return 1; return 0; diff --git a/convert.c b/convert.c index 5a2ea5308d..e65938bb1a 100644 --- a/convert.c +++ b/convert.c @@ -1314,7 +1314,7 @@ void convert_attrs(struct index_state *istate, git_config(read_convert_config, NULL); } - git_check_attr(istate, NULL, path, check); + git_check_attr(istate, path, check); ccheck = check->items; ca->crlf_action = git_path_check_crlf(ccheck + 4); if (ca->crlf_action == CRLF_UNDEFINED) diff --git a/environment.h b/environment.h index a63f0c6a24..30cb7e0fa3 100644 --- a/environment.h +++ b/environment.h @@ -55,6 +55,7 @@ const char *getenv_safe(struct strvec *argv, const char *name); #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH" #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS" #define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR" +#define GIT_ATTR_SOURCE_ENVIRONMENT "GIT_ATTR_SOURCE" /* * Environment variable used in handshaking the wire protocol. diff --git a/git.c b/git.c index 45899be826..2f42da20f4 100644 --- a/git.c +++ b/git.c @@ -9,6 +9,7 @@ #include "alias.h" #include "replace-object.h" #include "setup.h" +#include "attr.h" #include "shallow.h" #include "trace.h" #include "trace2.h" @@ -314,6 +315,21 @@ static int handle_options(const char ***argv, int *argc, int *envchanged) } else { exit(list_cmds(cmd)); } + } else if (!strcmp(cmd, "--attr-source")) { + if (*argc < 2) { + fprintf(stderr, _("no attribute source given for --attr-source\n" )); + usage(git_usage_string); + } + setenv(GIT_ATTR_SOURCE_ENVIRONMENT, (*argv)[1], 1); + if (envchanged) + *envchanged = 1; + (*argv)++; + (*argc)--; + } else if (skip_prefix(cmd, "--attr-source=", &cmd)) { + set_git_attr_source(cmd); + setenv(GIT_ATTR_SOURCE_ENVIRONMENT, cmd, 1); + if (envchanged) + *envchanged = 1; } else { fprintf(stderr, _("unknown option: %s\n"), cmd); usage(git_usage_string); diff --git a/ll-merge.c b/ll-merge.c index 28bc94c45d..6580970a67 100644 --- a/ll-merge.c +++ b/ll-merge.c @@ -393,7 +393,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf, normalize_file(theirs, path, istate); } - git_check_attr(istate, NULL, path, check); + git_check_attr(istate, path, check); ll_driver_name = check->items[0].value; if (check->items[1].value) { marker_size = atoi(check->items[1].value); @@ -421,7 +421,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path) if (!check) check = attr_check_initl("conflict-marker-size", NULL); - git_check_attr(istate, NULL, path, check); + git_check_attr(istate, path, check); if (check->items[0].value) { marker_size = atoi(check->items[0].value); if (marker_size <= 0) diff --git a/pathspec.c b/pathspec.c index 6972d515f0..09103a137e 100644 --- a/pathspec.c +++ b/pathspec.c @@ -734,7 +734,7 @@ int match_pathspec_attrs(struct index_state *istate, if (name[namelen]) name = to_free = xmemdupz(name, namelen); - git_check_attr(istate, NULL, name, item->attr_check); + git_check_attr(istate, name, item->attr_check); free(to_free); diff --git a/t/lib-diff-alternative.sh b/t/lib-diff-alternative.sh index a8f5d3274a..c4dc2d46dc 100644 --- a/t/lib-diff-alternative.sh +++ b/t/lib-diff-alternative.sh @@ -112,15 +112,36 @@ EOF STRATEGY=$1 - test_expect_success "$STRATEGY diff from attributes" ' + test_expect_success "setup attributes files for tests with $STRATEGY" ' + git checkout -b master && echo "file* diff=driver" >.gitattributes && - git config diff.driver.algorithm "$STRATEGY" && - test_must_fail git diff --no-index file1 file2 > output && - cat expect && - cat output && + git add file1 file2 .gitattributes && + git commit -m "adding files" && + git checkout -b branchA && + echo "file* diff=driverA" >.gitattributes && + git add .gitattributes && + git commit -m "adding driverA as diff driver" && + git checkout master && + git clone --bare --no-local . bare.git + ' + + test_expect_success "$STRATEGY diff from attributes" ' + test_must_fail git -c diff.driver.algorithm=$STRATEGY diff --no-index file1 file2 > output && test_cmp expect output ' + test_expect_success "diff from attributes with bare repo with source" ' + git -C bare.git --attr-source=branchA -c diff.driver.algorithm=myers \ + -c diff.driverA.algorithm=$STRATEGY \ + diff HEAD:file1 HEAD:file2 >output && + test_cmp expect output + ' + + test_expect_success "diff from attributes with bare repo with invalid source" ' + test_must_fail git -C bare.git --attr-source=invalid-branch diff \ + HEAD:file1 HEAD:file2 + ' + test_expect_success "$STRATEGY diff from attributes has valid diffstat" ' echo "file* diff=driver" >.gitattributes && git config diff.driver.algorithm "$STRATEGY" && diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh index 89b306cb11..26e082f05b 100755 --- a/t/t0003-attributes.sh +++ b/t/t0003-attributes.sh @@ -30,8 +30,17 @@ attr_check_quote () { attr_check_source () { path="$1" expect="$2" source="$3" git_opts="$4" && - git $git_opts check-attr --source $source test -- "$path" >actual 2>err && echo "$path: test: $expect" >expect && + + git $git_opts check-attr --source $source test -- "$path" >actual 2>err && + test_cmp expect actual && + test_must_be_empty err && + + git $git_opts --attr-source="$source" check-attr test -- "$path" >actual 2>err && + test_cmp expect actual && + test_must_be_empty err + + GIT_ATTR_SOURCE="$source" git $git_opts check-attr test -- "$path" >actual 2>err && test_cmp expect actual && test_must_be_empty err } diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh index 42a2b9a13b..c8d555771d 100755 --- a/t/t4018-diff-funcname.sh +++ b/t/t4018-diff-funcname.sh @@ -63,6 +63,25 @@ do test_i18ngrep ! fatal msg && test_i18ngrep ! error msg ' + + test_expect_success "builtin $p pattern compiles on bare repo with --attr-source" ' + test_when_finished "rm -rf bare.git" && + git checkout -B master && + git add . && + echo "*.java diff=notexist" >.gitattributes && + git add .gitattributes && + git commit -am "changing gitattributes" && + git checkout -B branchA && + echo "*.java diff=$p" >.gitattributes && + git add .gitattributes && + git commit -am "changing gitattributes" && + git clone --bare --no-local . bare.git && + git -C bare.git symbolic-ref HEAD refs/heads/master && + test_expect_code 1 git -C bare.git --attr-source=branchA \ + diff --exit-code HEAD:A.java HEAD:B.java 2>msg && + test_i18ngrep ! fatal msg && + test_i18ngrep ! error msg + ' done test_expect_success 'last regexp must not be negated' ' diff --git a/userdiff.c b/userdiff.c index eaec6ebb5e..664c7c1402 100644 --- a/userdiff.c +++ b/userdiff.c @@ -444,7 +444,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate, check = attr_check_initl("diff", NULL); if (!path) return NULL; - git_check_attr(istate, NULL, path, check); + git_check_attr(istate, path, check); if (ATTR_TRUE(check->items[0].value)) return &driver_true; diff --git a/ws.c b/ws.c index da3d0e28cb..903bfcd53e 100644 --- a/ws.c +++ b/ws.c @@ -79,7 +79,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname) if (!attr_whitespace_rule) attr_whitespace_rule = attr_check_initl("whitespace", NULL); - git_check_attr(istate, NULL, pathname, attr_whitespace_rule); + git_check_attr(istate, pathname, attr_whitespace_rule); value = attr_whitespace_rule->items[0].value; if (ATTR_TRUE(value)) { /* true (whitespace) */ From fa5103dd8913366b031ad8daa11f27e9452638be Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 13 May 2023 08:11:25 +0000 Subject: [PATCH 02/16] rebase --update-refs: fix loops The `total_nr` field in the `todo_list` structure merely serves display purposes, and should only be used when generating the progress message. In these two instances, however, we want to loop over all of the commands in the parsed rebase script. The loop limit therefore needs to be `nr`, which refers to the count of commands in the current `todo_list`. This is important because the two numbers, `nr` and `total_nr` can differ wildly, e.g. due to `total_nr` _not_ counting comments or empty lines, while `nr` skips any commands that already moved from the `git-rebase-todo` file to the `done` file. Signed-off-by: Johannes Schindelin Acked-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sequencer.c b/sequencer.c index 0cf3842201..0101a72701 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4205,7 +4205,7 @@ void todo_list_filter_update_refs(struct repository *r, if (!is_null_oid(&rec->after)) continue; - for (j = 0; !found && j < todo_list->total_nr; j++) { + for (j = 0; !found && j < todo_list->nr; j++) { struct todo_item *item = &todo_list->items[j]; const char *arg = todo_list->buf.buf + item->arg_offset; @@ -4235,7 +4235,7 @@ void todo_list_filter_update_refs(struct repository *r, * For each todo_item, check if its ref is in the update_refs list. * If not, then add it as an un-updated ref. */ - for (i = 0; i < todo_list->total_nr; i++) { + for (i = 0; i < todo_list->nr; i++) { struct todo_item *item = &todo_list->items[i]; const char *arg = todo_list->buf.buf + item->arg_offset; int j, found = 0; From 170eea9750e1bca7a35b5d27def9ee77df92fdf1 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Sat, 13 May 2023 08:11:26 +0000 Subject: [PATCH 03/16] rebase -r: fix the total number shown in the progress For regular, non-`--rebase-merges` runs, there is very little work to do for the parser when determining the total number of commands in a rebase script: it is simply the number of lines after stripping the commented lines and then trimming the trailing empty line, if any. The `--rebase-merges` mode complicates things by introducing empty lines and comments in the middle of the script. These should _not_ be counted as commands, and indeed, when an interactive rebase is interrupted and subsequently resumed, the total number of commands can magically shrink, sometimes dramatically. The reason for this strange behavior is that empty lines _are_ counted in `edit_todo_list()` (but not the comments, as they are stripped via `strbuf_stripspace(..., 1)`, which is a bug. Let's fix this so that the correct total number is shown from the get-go, by carefully adjusting it according to what's in the rebase script. Extra care needs to be taken in case the user edits the script: the number of commands might be different after the user edited than beforehand. Note: Even though commented lines are skipped in `edit_todo_list()`, we still need to handle `TODO_COMMENT` items by decrementing the already-incremented `total_nr` again: empty lines are also marked as `TODO_COMMENT`. Signed-off-by: Johannes Schindelin Acked-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 9 ++++++--- t/t3430-rebase-merges.sh | 8 ++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 0101a72701..659d98603e 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2453,7 +2453,6 @@ void todo_list_release(struct todo_list *todo_list) static struct todo_item *append_new_todo(struct todo_list *todo_list) { ALLOC_GROW(todo_list->items, todo_list->nr + 1, todo_list->alloc); - todo_list->total_nr++; return todo_list->items + todo_list->nr++; } @@ -2609,7 +2608,7 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf, char *p = buf, *next_p; int i, res = 0, fixup_okay = file_exists(rebase_path_done()); - todo_list->current = todo_list->nr = 0; + todo_list->current = todo_list->nr = todo_list->total_nr = 0; for (i = 1; *p; i++, p = next_p) { char *eol = strchrnul(p, '\n'); @@ -2630,6 +2629,9 @@ int todo_list_parse_insn_buffer(struct repository *r, char *buf, item->commit = NULL; } + if (item->command != TODO_COMMENT) + todo_list->total_nr++; + if (fixup_okay) ; /* do nothing */ else if (is_fixup(item->command)) @@ -6096,7 +6098,8 @@ int complete_action(struct repository *r, struct replay_opts *opts, unsigned fla todo_list_to_strbuf(r, &new_todo, &buf2, -1, 0); strbuf_swap(&new_todo.buf, &buf2); strbuf_release(&buf2); - new_todo.total_nr -= new_todo.nr; + /* Nothing is done yet, and we're reparsing, so let's reset the count */ + new_todo.total_nr = 0; if (todo_list_parse_insn_buffer(r, new_todo.buf.buf, &new_todo) < 0) BUG("invalid todo list after expanding IDs:\n%s", new_todo.buf.buf); diff --git a/t/t3430-rebase-merges.sh b/t/t3430-rebase-merges.sh index f351701fec..499c31a8d9 100755 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@ -517,4 +517,12 @@ test_expect_success '--rebase-merges with message matched with onto label' ' EOF ' +test_expect_success 'progress shows the correct total' ' + git checkout -b progress H && + git rebase --rebase-merges --force-rebase --verbose A 2> err && + # Expecting "Rebasing (N/14)" here, no bogus total number + grep "^Rebasing.*/14.$" err >progress && + test_line_count = 14 progress +' + test_done From 0aefe4c8412087f8cf02f5cfcdde4f827a76c6d7 Mon Sep 17 00:00:00 2001 From: Corentin Garcia Date: Sat, 13 May 2023 09:30:02 +0000 Subject: [PATCH 04/16] doc/git-config: add unit for http.lowSpeedLimit Add the unit (bytes per second) for http.lowSpeedLimit in the documentation. Signed-off-by: Corentin Garcia Signed-off-by: Junio C Hamano --- Documentation/config/http.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/config/http.txt b/Documentation/config/http.txt index afeeccfbfa..51a70781e5 100644 --- a/Documentation/config/http.txt +++ b/Documentation/config/http.txt @@ -246,8 +246,9 @@ significantly since the entire buffer is allocated even for small pushes. http.lowSpeedLimit, http.lowSpeedTime:: - If the HTTP transfer speed is less than 'http.lowSpeedLimit' - for longer than 'http.lowSpeedTime' seconds, the transfer is aborted. + If the HTTP transfer speed, in bytes per second, is less than + 'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds, + the transfer is aborted. Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and `GIT_HTTP_LOW_SPEED_TIME` environment variables. From c205923649568dee9c543d5b7f040d2c660a2272 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 15 May 2023 19:26:44 -0700 Subject: [PATCH 05/16] tests: do not negate test_path_exists As a way to assert the path 'foo' is missing, "! test_path_exists foo" is a poor way to do so, as the helper is designed to complain when 'foo' is missing, but the intention of the author who used negated form was to make sure it does not exist. This does not help debugging the tests. Use test_path_is_missing instead, which is a more appropriate helper. Signed-off-by: Junio C Hamano --- t/t4067-diff-partial-clone.sh | 4 ++-- t/t4115-apply-symlink.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh index f60f5cbd65..7af3a08862 100755 --- a/t/t4067-diff-partial-clone.sh +++ b/t/t4067-diff-partial-clone.sh @@ -151,7 +151,7 @@ test_expect_success 'diff does not fetch anything if inexact rename detection is # Ensure no fetches. GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD && - ! test_path_exists trace + test_path_is_missing trace ' test_expect_success 'diff --break-rewrites fetches only if necessary, and batches blobs if it does' ' @@ -171,7 +171,7 @@ test_expect_success 'diff --break-rewrites fetches only if necessary, and batche # Ensure no fetches. GIT_TRACE_PACKET="$(pwd)/trace" git -C client diff --raw -M HEAD^ HEAD && - ! test_path_exists trace && + test_path_is_missing trace && # But with --break-rewrites, ensure that there is exactly 1 negotiation # by checking that there is only 1 "done" line sent. ("done" marks the diff --git a/t/t4115-apply-symlink.sh b/t/t4115-apply-symlink.sh index e95e6d4e7d..a22a90d552 100755 --- a/t/t4115-apply-symlink.sh +++ b/t/t4115-apply-symlink.sh @@ -74,7 +74,7 @@ test_expect_success SYMLINKS 'symlink escape when creating new files' ' error: affected file ${SQ}renamed-symlink/create-me${SQ} is beyond a symbolic link EOF test_cmp expected_stderr stderr && - ! test_path_exists .git/create-me + test_path_is_missing .git/create-me ' test_expect_success SYMLINKS 'symlink escape when modifying file' ' From eab648d2b4c1ca6fbc28de454b51d7d00f5a3e60 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 15 May 2023 19:26:45 -0700 Subject: [PATCH 06/16] t2021: do not negate test_path_is_dir In this test, a path (some_dir) that is originally a directory is to be removed and then to be replaced with a file of the same name. The expectation is that the path becomes a file at the end. However, "! test_path_is_dir some_dir" is used to catch a breakage that leaves the path as a directory. But as with all the "test_path_is..." helpers, this use of the helper makes it loud when the expectation (i.e. it is a directory) is met, and otherwise is silent when it is not---this does not help debugging. Be more explicit and state that we expect the path to become a file. Signed-off-by: Junio C Hamano --- t/t2021-checkout-overwrite.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t2021-checkout-overwrite.sh b/t/t2021-checkout-overwrite.sh index 034f62c13c..ecfacf0f7f 100755 --- a/t/t2021-checkout-overwrite.sh +++ b/t/t2021-checkout-overwrite.sh @@ -77,7 +77,7 @@ test_expect_success 'checkout --overwrite-ignore should succeed if only ignored echo autogenerated information >some_dir/ignore && echo ignore >.git/info/exclude && git checkout --overwrite-ignore df_conflict && - ! test_path_is_dir some_dir + test_path_is_file some_dir ' test_done From b126b65b3381cd8659552b39699b3b3d9a4f5393 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 15 May 2023 19:26:46 -0700 Subject: [PATCH 07/16] test: do not negate test_path_is_* to assert absense These tests use "! test_path_is_dir" or "! test_path_is_file" to ensure that the path is not recursively checked out or "submodule update" did not touch the working tree. Use "test_path_is_missing" to assert that the path does not exist, instead of negating test_path_is_* helpers; they are designed to be loud in wrong occasions. Besides, negating "test_path_is_dir" would mean we would be happy if a file exists there, which is not the case for these tests. Signed-off-by: Junio C Hamano --- t/lib-submodule-update.sh | 2 +- t/t5572-pull-submodule.sh | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh index dee14992c5..9acb0d5d19 100644 --- a/t/lib-submodule-update.sh +++ b/t/lib-submodule-update.sh @@ -802,7 +802,7 @@ test_submodule_recursing_with_args_common () { git branch -t no_submodule origin/no_submodule && $command no_submodule && test_superproject_content origin/no_submodule && - ! test_path_is_dir sub1 && + test_path_is_missing sub1 && test_must_fail git config -f .git/modules/sub1/config core.worktree && test_must_fail git config -f .git/modules/sub1/modules/sub2/config core.worktree ) diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh index 09097eff3f..4e917bf87d 100755 --- a/t/t5572-pull-submodule.sh +++ b/t/t5572-pull-submodule.sh @@ -121,7 +121,7 @@ test_expect_success "fetch.recurseSubmodules option triggers recursive fetch (bu sub_oid=$(git -C child rev-parse HEAD) && git -C super/sub cat-file -e $sub_oid && # Check that the submodule worktree did not update - ! test_path_is_file super/sub/merge_strategy_5.t + test_path_is_missing super/sub/merge_strategy_5.t ' test_expect_success "fetch.recurseSubmodules takes precedence over submodule.recurse" ' @@ -134,7 +134,7 @@ test_expect_success "fetch.recurseSubmodules takes precedence over submodule.rec sub_oid=$(git -C child rev-parse HEAD) && git -C super/sub cat-file -e $sub_oid && # Check that the submodule worktree did not update - ! test_path_is_file super/sub/merge_strategy_6.t + test_path_is_missing super/sub/merge_strategy_6.t ' test_expect_success 'pull --rebase --recurse-submodules (remote superproject submodule changes, local submodule changes)' ' From 52c0f3318d98dd065ceb68d91bb6720eee20deb3 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Tue, 16 May 2023 17:33:43 -0400 Subject: [PATCH 08/16] run-command.c: fix missing include under `NO_PTHREADS` Git 2.41-rc0 fails to compile run-command.c with `NO_PTHREADS` defined, i.e. $ make NO_PTHREADS=1 run-command.o as `ALLOC_GROW()` macro is used in the `atexit()` emulation but the macro definition is not available. This bisects to 36bf195890 (alloc.h: move ALLOC_GROW() functions from cache.h, 2023-02-24), which replaced includes of with , which is the new home of `ALLOC_GROW()` (and `ALLOC_GROW_BY()`). We can see that run-command.c is the only one that try to use these macros without including . $ git grep -l -e '[^_]ALLOC_GROW(' -e 'ALLOC_GROW_BY(' \*.c | sort >/tmp/1 $ git grep -l 'alloc\.h' \*.c | sort >/tmp/2 $ comm -23 /tmp/[12] compat/simple-ipc/ipc-unix-socket.c run-command.c The "compat/" file only talks about the macro in the comment, and is not broken. We could fix this by conditionally including "alloc.h" when `NO_PTHREADS` is defined. But we have relatively few examples of conditional includes throughout the tree[^1]. Instead, include "alloc.h" unconditionally in run-command.c to allow it to successfully compile even when NO_PTHREADS is defined. [^1]: With `git grep -E -A1 '#if(n)?def' -- **/*.c | grep '#include' -B1`. Reported-by: Randall S. Becker Co-authored-by: Junio C Hamano Signed-off-by: Junio C Hamano Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- run-command.c | 1 + 1 file changed, 1 insertion(+) diff --git a/run-command.c b/run-command.c index 6bd16acb06..f19f875252 100644 --- a/run-command.c +++ b/run-command.c @@ -11,6 +11,7 @@ #include "packfile.h" #include "hook.h" #include "compat/nonblock.h" +#include "alloc.h" void child_process_init(struct child_process *child) { From 3307f7dde2ae8f5281d0782f7291a073c9b1cdc2 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 17 May 2023 09:06:32 +0200 Subject: [PATCH 09/16] imap-send: include strbuf.h We make liberal use of the strbuf API functions and types, but the inclusion of comes indirectly by including , which does not happen if you build with NO_CURL. Signed-off-by: Christian Hesse Helped-by: Taylor Blau Signed-off-by: Junio C Hamano --- imap-send.c | 1 + 1 file changed, 1 insertion(+) diff --git a/imap-send.c b/imap-send.c index a62424e90a..7f5426177a 100644 --- a/imap-send.c +++ b/imap-send.c @@ -29,6 +29,7 @@ #include "run-command.h" #include "parse-options.h" #include "setup.h" +#include "strbuf.h" #include "wrapper.h" #if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG) typedef void *SSL; From 004e0f790f947c9c511a9ac4f905021c7dbfa9e1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 May 2023 10:13:09 -0700 Subject: [PATCH 10/16] A bit more before -rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.41.0.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt index e177aff2d0..a4b4b1d826 100644 --- a/Documentation/RelNotes/2.41.0.txt +++ b/Documentation/RelNotes/2.41.0.txt @@ -3,7 +3,7 @@ Git v2.41 Release Notes UI, Workflows & Features - * Allow information carried on the WWW-AUthenticate header to be + * Allow information carried on the WWW-Authenticate header to be passed to the credential helpers. * A new "fetch.hideRefs" option can be used to exclude specified refs @@ -113,6 +113,10 @@ UI, Workflows & Features * "git fetch" learned the "--porcelain" option that emits what it did in a machine-parseable format. + * "git --attr-source= cmd $args" is a new way to have any + command to read attributes not from the working tree but from the + given tree object. + Performance, Internal Implementation, Development Support etc. From 933e3a4ee205353d8f093d5dfcd226fa432c4e58 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Wed, 17 May 2023 19:24:43 +0000 Subject: [PATCH 11/16] upload-pack: advertise capabilities when cloning empty repos When cloning an empty repository, protocol versions 0 and 1 currently offer nothing but the header and flush packets for the /info/refs endpoint. This means that no capabilities are provided, so the client side doesn't know what capabilities are present. However, this does pose a problem when working with SHA-256 repositories, since we use the capabilities to know the remote side's object format (hash algorithm). As of 8b214c2e9d ("clone: propagate object-format when cloning from void", 2023-04-05), this has been fixed for protocol v2, since there we always read the hash algorithm from the remote. Fortunately, the push version of the protocol already indicates a clue for how to solve this. When the /info/refs endpoint is accessed for a push and the remote is empty, we include a dummy "capabilities^{}" ref pointing to the all-zeros object ID. The protocol documentation already indicates this should _always_ be sent, even for fetches and clones, so let's just do that, which means we'll properly announce the hash algorithm as part of the capabilities. This just works with the existing code because we share the same ref code for fetches and clones, and libgit2, JGit, and dulwich do as well. There is one minor issue to fix, though. If we called send_ref with namespaces, we would return NULL with the capabilities entry, which would cause a crash. Instead, let's refactor out a function to print just the ref itself without stripping the namespace and use it for our special capabilities entry. Add several sets of tests for HTTP as well as for local clones. The behavior can be slightly different for HTTP versus a local or SSH clone because of the stateless-rpc functionality, so it's worth testing both. Signed-off-by: brian m. carlson Signed-off-by: Junio C Hamano --- t/t5551-http-fetch-smart.sh | 27 +++++++++++++++++++++++++++ t/t5700-protocol-v1.sh | 31 +++++++++++++++++++++++++++++-- upload-pack.c | 22 +++++++++++++++++----- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 0908534f25..21b7767cbd 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -611,6 +611,33 @@ test_expect_success 'client falls back from v2 to v0 to match server' ' grep symref=HEAD:refs/heads/ trace ' +test_expect_success 'create empty http-accessible SHA-256 repository' ' + mkdir "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" && + (cd "$HTTPD_DOCUMENT_ROOT_PATH/sha256.git" && + git --bare init --object-format=sha256 + ) +' + +test_expect_success 'clone empty SHA-256 repository with protocol v2' ' + rm -fr sha256 && + echo sha256 >expected && + git -c protocol.version=2 clone "$HTTPD_URL/smart/sha256.git" && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp actual expected && + git ls-remote "$HTTPD_URL/smart/sha256.git" >actual && + test_must_be_empty actual +' + +test_expect_success 'clone empty SHA-256 repository with protocol v0' ' + rm -fr sha256 && + echo sha256 >expected && + GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=0 clone "$HTTPD_URL/smart/sha256.git" && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp actual expected && + git ls-remote "$HTTPD_URL/smart/sha256.git" >actual && + test_must_be_empty actual +' + test_expect_success 'passing hostname resolution information works' ' BOGUS_HOST=gitbogusexamplehost.invalid && BOGUS_HTTPD_URL=$HTTPD_PROTO://$BOGUS_HOST:$LIB_HTTPD_PORT && diff --git a/t/t5700-protocol-v1.sh b/t/t5700-protocol-v1.sh index 6c8d4c6cf1..a73b4d4ff6 100755 --- a/t/t5700-protocol-v1.sh +++ b/t/t5700-protocol-v1.sh @@ -244,15 +244,28 @@ test_expect_success 'push with ssh:// using protocol v1' ' grep "push< version 1" log ' +test_expect_success 'clone propagates object-format from empty repo' ' + test_when_finished "rm -fr src256 dst256" && + + echo sha256 >expect && + git init --object-format=sha256 src256 && + git clone --no-local src256 dst256 && + git -C dst256 rev-parse --show-object-format >actual && + + test_cmp expect actual +' + # Test protocol v1 with 'http://' transport # . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd -test_expect_success 'create repo to be served by http:// transport' ' +test_expect_success 'create repos to be served by http:// transport' ' git init "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" && git -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" config http.receivepack true && - test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one + test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" one && + git init --object-format=sha256 "$HTTPD_DOCUMENT_ROOT_PATH/sha256" && + git -C "$HTTPD_DOCUMENT_ROOT_PATH/sha256" config http.receivepack true ' test_expect_success 'clone with http:// using protocol v1' ' @@ -269,6 +282,20 @@ test_expect_success 'clone with http:// using protocol v1' ' grep "git< version 1" log ' +test_expect_success 'clone with http:// using protocol v1 with empty SHA-256 repo' ' + GIT_TRACE_PACKET=1 GIT_TRACE_CURL=1 git -c protocol.version=1 \ + clone "$HTTPD_URL/smart/sha256" sha256 2>log && + + echo sha256 >expect && + git -C sha256 rev-parse --show-object-format >actual && + test_cmp expect actual && + + # Client requested to use protocol v1 + grep "Git-Protocol: version=1" log && + # Server responded using protocol v1 + grep "git< version 1" log +' + test_expect_success 'fetch with http:// using protocol v1' ' test_commit -C "$HTTPD_DOCUMENT_ROOT_PATH/http_parent" two && diff --git a/upload-pack.c b/upload-pack.c index 08633dc121..d3312006a3 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -120,6 +120,7 @@ struct upload_pack_data { unsigned allow_ref_in_want : 1; /* v2 only */ unsigned allow_sideband_all : 1; /* v2 only */ unsigned advertise_sid : 1; + unsigned sent_capabilities : 1; }; static void upload_pack_data_init(struct upload_pack_data *data) @@ -1206,18 +1207,17 @@ static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) { strbuf_addf(buf, " session-id=%s", trace2_session_id()); } -static int send_ref(const char *refname, const struct object_id *oid, - int flag UNUSED, void *cb_data) +static void write_v0_ref(struct upload_pack_data *data, + const char *refname, const char *refname_nons, + const struct object_id *oid) { static const char *capabilities = "multi_ack thin-pack side-band" " side-band-64k ofs-delta shallow deepen-since deepen-not" " deepen-relative no-progress include-tag multi_ack_detailed"; - const char *refname_nons = strip_namespace(refname); struct object_id peeled; - struct upload_pack_data *data = cb_data; if (mark_our_ref(refname_nons, refname, oid, &data->hidden_refs)) - return 0; + return; if (capabilities) { struct strbuf symref_info = STRBUF_INIT; @@ -1240,12 +1240,20 @@ static int send_ref(const char *refname, const struct object_id *oid, git_user_agent_sanitized()); strbuf_release(&symref_info); strbuf_release(&session_id); + data->sent_capabilities = 1; } else { packet_fwrite_fmt(stdout, "%s %s\n", oid_to_hex(oid), refname_nons); } capabilities = NULL; if (!peel_iterated_oid(oid, &peeled)) packet_fwrite_fmt(stdout, "%s %s^{}\n", oid_to_hex(&peeled), refname_nons); + return; +} + +static int send_ref(const char *refname, const struct object_id *oid, + int flag UNUSED, void *cb_data) +{ + write_v0_ref(cb_data, refname, strip_namespace(refname), oid); return 0; } @@ -1379,6 +1387,10 @@ void upload_pack(const int advertise_refs, const int stateless_rpc, data.no_done = 1; head_ref_namespaced(send_ref, &data); for_each_namespaced_ref(send_ref, &data); + if (!data.sent_capabilities) { + const char *refname = "capabilities^{}"; + write_v0_ref(&data, refname, refname, null_oid()); + } /* * fflush stdout before calling advertise_shallow_grafts because send_ref * uses stdio. From 3ece9bf0f9e24909b090cf348d89e8920bd4f82f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 May 2023 14:10:39 -0700 Subject: [PATCH 12/16] send-email: clear the $message_id after validation Recently git-send-email started parsing the same message twice, once to validate _all_ the message before sending even the first one, and then after the validation hook is happy and each message gets sent, to read the contents to find out where to send to etc. Unfortunately, the effect of reading the messages for validation lingered even after the validation is done. Namely $message_id gets assigned if exists in the input files but the variable is global, and it is not cleared before pre_process_file runs. This causes reading a message without a message-id followed by reading a message with a message-id to misbehave---the sub reports as if the message had the same id as the previously written one. Clear the variable before starting to read the headers in pre_process_file. Tested-by: Douglas Anderson Signed-off-by: Junio C Hamano --- git-send-email.perl | 2 ++ t/t9001-send-email.sh | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/git-send-email.perl b/git-send-email.perl index 10c450ef68..37dfd4b8c5 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -1768,6 +1768,8 @@ sub pre_process_file { $subject = $initial_subject; $message = ""; $message_num++; + undef $message_id; + # First unfold multiline header fields while(<$fh>) { last if /^\s*$/; diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 36bb85d6b4..8d49eff91a 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -47,7 +47,7 @@ clean_fake_sendmail () { test_expect_success $PREREQ 'Extract patches' ' patches=$(git format-patch -s --cc="One " --cc=two@example.com -n HEAD^1) && - threaded_patches=$(git format-patch -o threaded -s --in-reply-to="format" HEAD^1) + threaded_patches=$(git format-patch -o threaded --thread=shallow -s --in-reply-to="format" HEAD^1) ' # Test no confirm early to ensure remaining tests will not hang @@ -588,6 +588,21 @@ test_expect_success $PREREQ "--validate hook supports header argument" ' outdir/000?-*.patch ' +test_expect_success $PREREQ 'clear message-id before parsing a new message' ' + clean_fake_sendmail && + echo true | write_script my-hooks/sendemail-validate && + test_config core.hooksPath my-hooks && + GIT_SEND_EMAIL_NOTTY=1 \ + git send-email --validate --to=recipient@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches $threaded_patches && + id0=$(grep "^Message-ID: " $threaded_patches) && + id1=$(grep "^Message-ID: " msgtxt1) && + id2=$(grep "^Message-ID: " msgtxt2) && + test "z$id0" = "z$id2" && + test "z$id1" != "z$id2" +' + for enc in 7bit 8bit quoted-printable base64 do test_expect_success $PREREQ "--transfer-encoding=$enc produces correct header" ' From 20bd08aefb20168c6c227d2bfd1965761f9201ea Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 17 May 2023 14:10:39 -0700 Subject: [PATCH 13/16] t9001: mark the script as no longer leak checker clean The test uses "format-patch --thread" which is known to leak the generated message ID list. Plugging these leaks involves straightening out the memory ownership rules around rev_info.message_id and rev_info.ref_message_ids, and is beyond the scope of send-email fix, so for now mark the test as leaky to unblock the topic before the release. Signed-off-by: Junio C Hamano --- t/t9001-send-email.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 8d49eff91a..2051103226 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -4,7 +4,7 @@ test_description='git send-email' GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME -TEST_PASSES_SANITIZE_LEAK=true +# no longer TEST_PASSES_SANITIZE_LEAK=true - format-patch --thread leaks . ./test-lib.sh # May be altered later in the test From eb1c42da8e21cc2a8dacd21023a179b788858887 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 18 May 2023 15:21:02 -0400 Subject: [PATCH 14/16] t/lib-httpd: make CGIPassAuth support conditional Commit 988aad99b4 (t5563: add tests for basic and anoymous HTTP access, 2023-02-27) added tests that require Apache to support the CGIPassAuth directive, which was added in Apache 2.4.13. This is fairly old (~8 years), but recent enough that we still encounter it in the wild (e.g., RHEL/CentOS 7, which is not EOL until June 2024). We can live with skipping the new tests on such a platform. But unfortunately, since the directive is used unconditionally in our apache.conf, it means the web server fails to start entirely, and we cannot run other HTTP tests at all (e.g., the basic ones in t5551). We can fix that by making the config conditional, and only triggering it for t5563. That solves the problem for t5551 (which then ignores the directive entirely). For t5563, we'd see apache complain in start_httpd; with the default setting of GIT_TEST_HTTPD, we'd then skip the whole script. But that leaves one small problem: people may set GIT_TEST_HTTPD=1 explicitly, which instructs the tests to fail (rather than skip) when we can't start the webserver (to avoid accidentally missing some tests). This could be worked around by having the user manually set GIT_SKIP_TESTS on a platform with an older Apache. But we can be a bit friendlier by doing the version check ourselves and setting an appropriate prereq. We'll use the (lack of) prereq to then skip the rest of t5563. In theory we could use the prereq to skip individual tests, but in practice this whole script depends on it. Reported-by: Todd Zullinger Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/lib-httpd.sh | 14 ++++++++++++++ t/lib-httpd/apache.conf | 2 ++ t/t5563-simple-http-auth.sh | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/t/lib-httpd.sh b/t/lib-httpd.sh index 2c49569f67..7f6db7d078 100644 --- a/t/lib-httpd.sh +++ b/t/lib-httpd.sh @@ -181,6 +181,20 @@ enable_http2 () { test_set_prereq HTTP2 } +enable_cgipassauth () { + # We are looking for 2.4.13 or more recent. Since we only support + # 2.4 and up, no need to check for older major/minor. + if test "$HTTPD_VERSION_MAJOR" = 2 && + test "$HTTPD_VERSION_MINOR" = 4 && + test "$(echo $HTTPD_VERSION | cut -d. -f3)" -lt 13 + then + echo >&4 "apache $HTTPD_VERSION too old for CGIPassAuth" + return + fi + HTTPD_PARA="$HTTPD_PARA -DUSE_CGIPASSAUTH" + test_set_prereq CGIPASSAUTH +} + start_httpd() { prepare_httpd >&3 2>&4 diff --git a/t/lib-httpd/apache.conf b/t/lib-httpd/apache.conf index 76335cdb24..4eef1d1266 100644 --- a/t/lib-httpd/apache.conf +++ b/t/lib-httpd/apache.conf @@ -138,7 +138,9 @@ Alias /auth/dumb/ www/auth/dumb/ SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL + CGIPassAuth on + ScriptAlias /smart/incomplete_length/git-upload-pack incomplete-length-upload-pack-v2-http.sh/ ScriptAlias /smart/incomplete_body/git-upload-pack incomplete-body-upload-pack-v2-http.sh/ diff --git a/t/t5563-simple-http-auth.sh b/t/t5563-simple-http-auth.sh index ccf7e54b07..1ec51e0a2b 100755 --- a/t/t5563-simple-http-auth.sh +++ b/t/t5563-simple-http-auth.sh @@ -5,6 +5,12 @@ test_description='test http auth header and credential helper interop' . ./test-lib.sh . "$TEST_DIRECTORY"/lib-httpd.sh +enable_cgipassauth +if ! test_have_prereq CGIPASSAUTH +then + skip_all="no CGIPassAuth support" + test_done +fi start_httpd test_expect_success 'setup_credential_helper' ' From 4a714b37029a4b63dbd22f7d7ed81f7a0d693680 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 19 May 2023 08:33:18 -0700 Subject: [PATCH 15/16] Git 2.41-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.41.0.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt index a4b4b1d826..af9f3fd730 100644 --- a/Documentation/RelNotes/2.41.0.txt +++ b/Documentation/RelNotes/2.41.0.txt @@ -48,7 +48,7 @@ UI, Workflows & Features * "git clone" from an empty repository learned to propagate the choice of the hash algorithm from the source repository to the - newly created repository. + newly created repository over any one of the v0/v1/v2 protocol. * "git mergetool" and "git difftool" learns a new configuration guiDefault to optionally favor configured guitool over non-gui-tool From 9e49351c3060e1fa6e0d2de64505b7becf157f28 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 20 May 2023 05:35:44 +0900 Subject: [PATCH 16/16] A few more topics after 2.41-rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.41.0.txt | 4 ++++ GIT-VERSION-GEN | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt index af9f3fd730..c77484c6b5 100644 --- a/Documentation/RelNotes/2.41.0.txt +++ b/Documentation/RelNotes/2.41.0.txt @@ -369,6 +369,10 @@ Fixes since v2.40 by git forges to disable replace-refs feature. (merge b6551feadf ds/merge-tree-use-config later to maint). + * A few bugs in the sequencer machinery that results in miscounting + the steps have been corrected. + (merge 170eea9750 js/rebase-count-fixes later to maint). + * Other code cleanup, docfix, build fix, etc. (merge f7111175df as/doc-markup-fix later to maint). (merge 90ff7c9898 fc/test-aggregation-clean-up later to maint). diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 9a1111af9b..85d7d7a2f4 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.40.GIT +DEF_VER=v2.41.0-rc1 LF=' '