diff options
53 files changed, 624 insertions, 288 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6c3453a10b..aef6643648 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -205,7 +205,6 @@ jobs: shell: bash run: | cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \ - -DIconv_LIBRARY=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows/lib/libiconv.lib -DIconv_INCLUDE_DIR=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows/include \ -DMSGFMT_EXE=`pwd`/git-sdk-64-minimal/mingw64/bin/msgfmt.exe -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON - name: MSBuild run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142 diff --git a/.gitignore b/.gitignore index f22b7a4cf1..3dcdb6bb5a 100644 --- a/.gitignore +++ b/.gitignore @@ -134,7 +134,6 @@ /git-remote-ftps /git-remote-fd /git-remote-ext -/git-remote-testpy /git-repack /git-replace /git-request-pull @@ -147,11 +146,9 @@ /git-rm /git-send-email /git-send-pack -/git-serve /git-sh-i18n /git-sh-i18n--envsubst /git-sh-setup -/git-sh-i18n /git-shell /git-shortlog /git-show diff --git a/Documentation/Makefile b/Documentation/Makefile index 80d1908a44..69dbe4bb0b 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -380,7 +380,10 @@ SubmittingPatches.txt: SubmittingPatches $(QUIET_GEN) cp $< $@ XSLT = docbook.xsl -XSLTOPTS = --xinclude --stringparam html.stylesheet docbook-xsl.css +XSLTOPTS = +XSLTOPTS += --xinclude +XSLTOPTS += --stringparam html.stylesheet docbook-xsl.css +XSLTOPTS += --param generate.consistent.ids 1 user-manual.html: user-manual.xml $(XSLT) $(QUIET_XSLTPROC)$(RM) $@+ $@ && \ diff --git a/Documentation/MyFirstObjectWalk.txt b/Documentation/MyFirstObjectWalk.txt index c3f2d1a831..2d10eea7a9 100644 --- a/Documentation/MyFirstObjectWalk.txt +++ b/Documentation/MyFirstObjectWalk.txt @@ -182,30 +182,6 @@ its `init_log_defaults()` sets its own state (`decoration_style`) and asks `grep` and `diff` to initialize themselves by calling each of their initialization functions. -For our first example within `git walken`, we don't intend to use any other -components within Git, and we don't have any configuration to do. However, we -may want to add some later, so for now, we can add an empty placeholder. Create -a new function in `builtin/walken.c`: - ----- -static void init_walken_defaults(void) -{ - /* - * We don't actually need the same components `git log` does; leave this - * empty for now. - */ -} ----- - -Make sure to add a line invoking it inside of `cmd_walken()`. - ----- -int cmd_walken(int argc, const char **argv, const char *prefix) -{ - init_walken_defaults(); -} ----- - ==== Configuring From `.gitconfig` Next, we should have a look at any relevant configuration settings (i.e., @@ -388,17 +364,9 @@ Next, let's try to filter the commits we see based on their author. This is equivalent to running `git log --author=<pattern>`. We can add a filter by modifying `rev_info.grep_filter`, which is a `struct grep_opt`. -First some setup. Add `init_grep_defaults()` to `init_walken_defaults()` and add -`grep_config()` to `git_walken_config()`: +First some setup. Add `grep_config()` to `git_walken_config()`: ---- -static void init_walken_defaults(void) -{ - init_grep_defaults(the_repository); -} - -... - static int git_walken_config(const char *var, const char *value, void *cb) { grep_config(var, value, cb); diff --git a/Documentation/RelNotes/2.30.0.txt b/Documentation/RelNotes/2.30.0.txt index cb4d65f9ff..df8df8a5d1 100644 --- a/Documentation/RelNotes/2.30.0.txt +++ b/Documentation/RelNotes/2.30.0.txt @@ -78,6 +78,31 @@ UI, Workflows & Features * The command line completion script (in contrib/) learned to expand commands that are alias of alias. + * "git update-ref --stdin" learns to take multiple transactions in a + single session. + + * Various subcommands of "git config" that takes value_regex + learn the "--literal-value" option to take the value_regex option + as a literal string. + + * The transport layer was taught to optionally exchange the session + ID assigned by the trace2 subsystem during fetch/push transactions. + + * "git imap-send" used to ignore configuration variables like + core.askpass; this has been corrected. + + * "git $cmd $args", when $cmd is not a recognised subcommand, by + default tries to see if $cmd is a typo of an existing subcommand + and optionally executes the corrected command if there is only one + possibility, depending on the setting of help.autocorrect; the + users can now disable the whole thing, including the cycles spent + to find a likely typo, by setting the configuration variable to + 'never'. + + * "@" sometimes worked (e.g. "git push origin @:there") as a part of + a refspec element, but "git push origin @" did not work, which has + been corrected. + Performance, Internal Implementation, Development Support etc. @@ -138,6 +163,14 @@ Performance, Internal Implementation, Development Support etc. * "git-parse-remote" shell script library outlived its usefulness. + * Like die() and error(), a call to warning() will also trigger a + trace2 event. + + * Use of non-reentrant localtime() has been removed. + + * Non-reentrant time-related library functions and ctime/asctime with + awkward calling interfaces are banned from the codebase. + Fixes since v2.29 ----------------- @@ -294,6 +327,42 @@ Fixes since v2.29 has been corrected. (merge 309a4028e7 jk/stop-pack-objects-when-fetch-is-killed later to maint). + * "git add -i" failed to honor custom colors configured to show + patches, which has been corrected. + (merge 96386faa03 js/add-i-color-fix later to maint). + + * Processes that access packdata while the .idx file gets removed + (e.g. while repacking) did not fail or fall back gracefully as they + could. + (merge 506ec2fbda tb/idx-midx-race-fix later to maint). + + * "git apply" adjusted the permission bits of working-tree files and + directories according core.sharedRepository setting by mistake and + for a long time, which has been corrected. + (merge eb3c027e17 mt/do-not-use-scld-in-working-tree later to maint). + + * "fetch-pack" could pass NULL pointer to unlink(2) when it sees an + invalid filename; the error checking has been tightened to make + this impossible. + (merge 6031af387e rs/fetch-pack-invalid-lockfile later to maint). + + * "git maintenance run/start/stop" needed to be run in a repository + to hold the lockfile they use, but didn't make sure they are + actually in a repository, which has been corrected. + + * The glossary described a branch as an "active" line of development, + which is misleading---a stale and non-moving branch is still a + branch. + (merge eef1ceabd8 so/glossary-branch-is-not-necessarily-active later to maint). + + * Newer versions of xsltproc can assign IDs in HTML documents it + generates in a consistent manner. Use the feature to help format + HTML version of the user manual reproducibly. + (merge 3569e11d69 ae/doc-reproducible-html later to maint). + + * Tighten error checking in the codepath that responds to "git fetch". + (merge d43a21bdbb jk/check-config-parsing-error-in-upload-pack later to maint). + * Other code cleanup, docfix, build fix, etc. (merge 3e0a5dc9af cc/doc-filter-branch-typofix later to maint). (merge 32c83afc2c cw/ci-ghwf-check-ws-errors later to maint). @@ -318,3 +387,7 @@ Fixes since v2.29 (merge 793c1464d3 ab/gc-keep-base-option later to maint). (merge b86339b12b mt/worktree-error-message-fix later to maint). (merge e01ae2a4a7 js/pull-rebase-use-advise later to maint). + (merge e63d774242 sn/config-doc-typofix later to maint). + (merge 08e9df2395 jk/multi-line-indent-style-fix later to maint). + (merge e66590348a da/vs-build-iconv-fix later to maint). + (merge 7fe07275be js/cmake-extra-built-ins-fix later to maint). diff --git a/Documentation/config.txt b/Documentation/config.txt index f292c2689e..6ba50b1104 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -64,7 +64,7 @@ The variable names are case-insensitive, allow only alphanumeric characters and `-`, and must start with an alphabetic character. A line that defines a value can be continued to the next line by -ending it with a `\`; the backquote and the end-of-line are +ending it with a `\`; the backslash and the end-of-line are stripped. Leading whitespaces after 'name =', the remainder of the line after the first comment character '#' or ';', and trailing whitespaces of the line are discarded unless they are enclosed in diff --git a/Documentation/config/help.txt b/Documentation/config/help.txt index 224bbf5a28..783a90a0f9 100644 --- a/Documentation/config/help.txt +++ b/Documentation/config/help.txt @@ -8,13 +8,14 @@ help.format:: the default. 'web' and 'html' are the same. help.autoCorrect:: - Automatically correct and execute mistyped commands after - waiting for the given number of deciseconds (0.1 sec). If more - than one command can be deduced from the entered text, nothing - will be executed. If the value of this option is negative, - the corrected command will be executed immediately. If the - value is 0 - the command will be just shown but not executed. - This is the default. + If git detects typos and can identify exactly one valid command similar + to the error, git will automatically run the intended command after + waiting a duration of time defined by this configuration value in + deciseconds (0.1 sec). If this value is 0, the suggested corrections + will be shown, but not executed. If it is a negative integer, or + "immediate", the suggested command + is run immediately. If "never", suggestions are not shown at all. The + default value is zero. help.htmlPath:: Specify the path where the HTML documentation resides. File system paths diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt index f5b6245270..505126a780 100644 --- a/Documentation/config/transfer.txt +++ b/Documentation/config/transfer.txt @@ -69,3 +69,7 @@ transfer.unpackLimit:: When `fetch.unpackLimit` or `receive.unpackLimit` are not set, the value of this variable is used instead. The default value is 100. + +transfer.advertiseSID:: + Boolean. When true, client and server processes will advertise their + unique session IDs to their remote counterpart. Defaults to false. diff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt index 090c888335..67c7a50b96 100644 --- a/Documentation/glossary-content.txt +++ b/Documentation/glossary-content.txt @@ -18,7 +18,7 @@ Untyped <<def_object,object>>, e.g. the contents of a file. [[def_branch]]branch:: - A "branch" is an active line of development. The most recent + A "branch" is a line of development. The most recent <<def_commit,commit>> on a branch is referred to as the tip of that branch. The tip of the branch is referenced by a branch <<def_head,head>>, which moves forward as additional development diff --git a/Documentation/technical/protocol-capabilities.txt b/Documentation/technical/protocol-capabilities.txt index ba869a7d36..9dfade930d 100644 --- a/Documentation/technical/protocol-capabilities.txt +++ b/Documentation/technical/protocol-capabilities.txt @@ -27,8 +27,8 @@ and 'push-cert' capabilities are sent and recognized by the receive-pack (push to server) process. The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized -by both upload-pack and receive-pack protocols. The 'agent' capability -may optionally be sent in both protocols. +by both upload-pack and receive-pack protocols. The 'agent' and 'session-id' +capabilities may optionally be sent in both protocols. All other capabilities are only recognized by the upload-pack (fetch from server) process. @@ -365,3 +365,16 @@ If the upload-pack server advertises the 'filter' capability, fetch-pack may send "filter" commands to request a partial clone or partial fetch and request that the server omit various objects from the packfile. + +session-id=<session id> +----------------------- + +The server may advertise a session ID that can be used to identify this process +across multiple requests. The client may advertise its own session ID back to +the server as well. + +Session IDs should be unique to a given process. They must fit within a +packet-line, and must not contain non-printable or whitespace characters. The +current implementation uses trace2 session IDs (see +link:api-trace2.html[api-trace2] for details), but this may change and users of +the session ID should not rely on this fact. diff --git a/Documentation/technical/protocol-v2.txt b/Documentation/technical/protocol-v2.txt index e597b74da3..85daeb5d9e 100644 --- a/Documentation/technical/protocol-v2.txt +++ b/Documentation/technical/protocol-v2.txt @@ -492,3 +492,16 @@ form `object-format=X`) to notify the client that the server is able to deal with objects using hash algorithm X. If not specified, the server is assumed to only handle SHA-1. If the client would like to use a hash algorithm other than SHA-1, it should specify its object-format string. + +session-id=<session id> +~~~~~~~~~~~~~~~~~~~~~~~ + +The server may advertise a session ID that can be used to identify this process +across multiple requests. The client may advertise its own session ID back to +the server as well. + +Session IDs should be unique to a given process. They must fit within a +packet-line, and must not contain non-printable or whitespace characters. The +current implementation uses trace2 session IDs (see +link:api-trace2.html[api-trace2] for details), but this may change and users of +the session ID should not rely on this fact. diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index 82bcd13f4c..c3bbcc9cfa 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.29.GIT +DEF_VER=v2.30.0-rc0 LF=' ' @@ -768,6 +768,7 @@ BUILT_INS += git-cherry-pick$X BUILT_INS += git-format-patch$X BUILT_INS += git-fsck-objects$X BUILT_INS += git-init$X +BUILT_INS += git-maintenance$X BUILT_INS += git-merge-subtree$X BUILT_INS += git-restore$X BUILT_INS += git-show$X @@ -4409,7 +4409,7 @@ static int create_one_file(struct apply_state *state, return 0; if (errno == ENOENT) { - if (safe_create_leading_directories(path)) + if (safe_create_leading_directories_no_share(path)) return 0; res = try_create_file(state, path, mode, buf, size); if (res < 0) @@ -29,4 +29,17 @@ #define vsprintf(buf,fmt,arg) BANNED(vsprintf) #endif +#undef gmtime +#define gmtime(t) BANNED(gmtime) +#undef localtime +#define localtime(t) BANNED(localtime) +#undef ctime +#define ctime(t) BANNED(ctime) +#undef ctime_r +#define ctime_r(t, buf) BANNED(ctime_r) +#undef asctime +#define asctime(t) BANNED(asctime) +#undef asctime_r +#define asctime_r(t, buf) BANNED(asctime_r) + #endif /* BANNED_H */ diff --git a/builtin/bugreport.c b/builtin/bugreport.c index 3ad4b9b62e..ad3cc9c02f 100644 --- a/builtin/bugreport.c +++ b/builtin/bugreport.c @@ -125,6 +125,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix) struct strbuf report_path = STRBUF_INIT; int report = -1; time_t now = time(NULL); + struct tm tm; char *option_output = NULL; char *option_suffix = "%Y-%m-%d-%H%M"; const char *user_relative_path = NULL; @@ -147,7 +148,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix) strbuf_complete(&report_path, '/'); strbuf_addstr(&report_path, "git-bugreport-"); - strbuf_addftime(&report_path, option_suffix, localtime(&now), 0, 0); + strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0); strbuf_addstr(&report_path, ".txt"); switch (safe_create_leading_directories(report_path.buf)) { diff --git a/builtin/gc.c b/builtin/gc.c index 592b20fb89..b57fda4924 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1446,10 +1446,6 @@ static int maintenance_register(void) struct child_process config_set = CHILD_PROCESS_INIT; struct child_process config_get = CHILD_PROCESS_INIT; - /* There is no current repository, so skip registering it */ - if (!the_repository || !the_repository->gitdir) - return 0; - /* Disable foreground maintenance */ git_config_set("maintenance.auto", "false"); @@ -1487,9 +1483,6 @@ static int maintenance_unregister(void) { struct child_process config_unset = CHILD_PROCESS_INIT; - if (!the_repository || !the_repository->gitdir) - return error(_("no current repository to unregister")); - config_unset.git_cmd = 1; strvec_pushl(&config_unset.args, "config", "--global", "--unset", "--fixed-value", "maintenance.repo", diff --git a/builtin/grep.c b/builtin/grep.c index e58e57504c..ca259af441 100644 --- a/builtin/grep.c +++ b/builtin/grep.c @@ -950,7 +950,6 @@ int cmd_grep(int argc, const char **argv, const char *prefix) OPT_END() }; - init_grep_defaults(the_repository); git_config(grep_cmd_config, NULL); grep_init(&opt, the_repository, prefix); diff --git a/builtin/log.c b/builtin/log.c index 08204e3196..bd6ff4f9f9 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -133,7 +133,6 @@ static int log_line_range_callback(const struct option *option, const char *arg, static void init_log_defaults(void) { - init_grep_defaults(the_repository); init_diff_ui_defaults(); decoration_style = auto_decoration_style(); diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index f1f0f7bef6..d49d050e6e 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -54,6 +54,7 @@ static int receive_unpack_limit = -1; static int transfer_unpack_limit = -1; static int advertise_atomic_push = 1; static int advertise_push_options; +static int advertise_sid; static int unpack_limit = 100; static off_t max_input_size; static int report_status; @@ -248,6 +249,11 @@ static int receive_pack_config(const char *var, const char *value, void *cb) return 0; } + if (strcmp(var, "transfer.advertisesid") == 0) { + advertise_sid = git_config_bool(var, value); + return 0; + } + return git_default_config(var, value, cb); } @@ -268,6 +274,8 @@ static void show_ref(const char *path, const struct object_id *oid) strbuf_addf(&cap, " push-cert=%s", push_cert_nonce); if (advertise_push_options) strbuf_addstr(&cap, " push-options"); + if (advertise_sid) + strbuf_addf(&cap, " session-id=%s", trace2_session_id()); strbuf_addf(&cap, " object-format=%s", the_hash_algo->name); strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized()); packet_write_fmt(1, "%s %s%c%s\n", @@ -2075,6 +2083,7 @@ static struct command *read_head_info(struct packet_reader *reader, if (linelen < reader->pktlen) { const char *feature_list = reader->line + linelen + 1; const char *hash = NULL; + const char *client_sid; int len = 0; if (parse_feature_request(feature_list, "report-status")) report_status = 1; @@ -2097,6 +2106,12 @@ static struct command *read_head_info(struct packet_reader *reader, } if (xstrncmpz(the_hash_algo->name, hash, len)) die("error: unsupported object format '%s'", hash); + client_sid = parse_feature_value(feature_list, "session-id", &len, NULL); + if (client_sid) { + char *sid = xstrndup(client_sid, len); + trace2_data_string("transfer", NULL, "client-sid", client_sid); + free(sid); + } } if (!strcmp(reader->line, "push-cert")) { @@ -1255,7 +1255,11 @@ int adjust_shared_perm(const char *path); * safe_create_leading_directories() temporarily changes path while it * is working but restores it before returning. * safe_create_leading_directories_const() doesn't modify path, even - * temporarily. + * temporarily. Both these variants adjust the permissions of the + * created directories to honor core.sharedRepository, so they are best + * suited for files inside the git dir. For working tree files, use + * safe_create_leading_directories_no_share() instead, as it ignores + * the core.sharedRepository setting. */ enum scld_error { SCLD_OK = 0, @@ -1266,6 +1270,7 @@ enum scld_error { }; enum scld_error safe_create_leading_directories(char *path); enum scld_error safe_create_leading_directories_const(const char *path); +enum scld_error safe_create_leading_directories_no_share(char *path); /* * Callback function for raceproof_create_file(). This function is diff --git a/compat/vcbuild/scripts/clink.pl b/compat/vcbuild/scripts/clink.pl index df167d1e1a..3bd824154b 100755 --- a/compat/vcbuild/scripts/clink.pl +++ b/compat/vcbuild/scripts/clink.pl @@ -45,7 +45,7 @@ while (@ARGV) { push(@args, "zlib.lib"); } } elsif ("$arg" eq "-liconv") { - push(@args, "libiconv.lib"); + push(@args, "iconv.lib"); } elsif ("$arg" eq "-lcrypto") { push(@args, "libcrypto.lib"); } elsif ("$arg" eq "-lssl") { diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index df539a44fa..c151dd7257 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -114,6 +114,16 @@ macro(parse_makefile_for_scripts list_var regex lang) endif() endmacro() +macro(parse_makefile_for_executables list_var regex) + file(STRINGS ${CMAKE_SOURCE_DIR}/Makefile ${list_var} REGEX "^${regex} \\+= git-(.*)") + string(REPLACE "${regex} +=" "" ${list_var} ${${list_var}}) + string(STRIP ${${list_var}} ${list_var}) #remove trailing/leading whitespaces + string(REPLACE "git-" "" ${list_var} ${${list_var}}) #strip `git-` prefix + string(REPLACE "\$X" ";" ${list_var} ${${list_var}}) #strip $X, ; is for converting the string into a list + list(TRANSFORM ${list_var} STRIP) #remove trailing/leading whitespaces for each element in list + list(REMOVE_ITEM ${list_var} "") #remove empty list elements +endmacro() + include(CheckTypeSize) include(CheckCSourceRuns) include(CheckCSourceCompiles) @@ -673,10 +683,7 @@ if(CURL_FOUND) endif() endif() -set(git_builtin_extra - cherry cherry-pick format-patch fsck-objects - init merge-subtree restore show - stage status switch whatchanged) +parse_makefile_for_executables(git_builtin_extra "BUILT_INS") #Creating hardlinks foreach(s ${git_SOURCES} ${git_builtin_extra}) diff --git a/contrib/buildsystems/engine.pl b/contrib/buildsystems/engine.pl index 2ff9620459..ed6c45988a 100755 --- a/contrib/buildsystems/engine.pl +++ b/contrib/buildsystems/engine.pl @@ -351,7 +351,7 @@ sub handleLinkLine } elsif ("$part" eq "-lexpat") { push(@libs, "libexpat.lib"); } elsif ("$part" eq "-liconv") { - push(@libs, "libiconv.lib"); + push(@libs, "iconv.lib"); } elsif ($part =~ /^[-\/]/) { push(@lflags, $part); } elsif ($part =~ /\.(a|lib)$/) { diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 1ed03623cd..463a3124da 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1829,7 +1829,7 @@ _git_fsck () _git_gitk () { - _gitk + __gitk_main } # Lists matching symbol names from a tag (as in ctags) file. diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index e0fda27f4c..6c56296997 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -116,6 +116,7 @@ __gitcomp_file () { emulate -L zsh + compset -P '*[=:]' compadd -f -p "${2-}" -- ${(f)1} && _ret=0 } diff --git a/fetch-pack.c b/fetch-pack.c index b10c432315..876f90c759 100644 --- a/fetch-pack.c +++ b/fetch-pack.c @@ -35,6 +35,7 @@ static int fetch_fsck_objects = -1; static int transfer_fsck_objects = -1; static int agent_supported; static int server_supports_filtering; +static int advertise_sid; static struct shallow_lock shallow_lock; static const char *alternate_shallow_file; static struct strbuf fsck_msg_types = STRBUF_INIT; @@ -326,6 +327,8 @@ static int find_common(struct fetch_negotiator *negotiator, if (deepen_not_ok) strbuf_addstr(&c, " deepen-not"); if (agent_supported) strbuf_addf(&c, " agent=%s", git_user_agent_sanitized()); + if (advertise_sid) + strbuf_addf(&c, " session-id=%s", trace2_session_id()); if (args->filter_options.choice) strbuf_addstr(&c, " filter"); packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf); @@ -915,8 +918,9 @@ static int get_pack(struct fetch_pack_args *args, if (start_command(&cmd)) die(_("fetch-pack: unable to fork off %s"), cmd_name); if (do_keep && pack_lockfiles) { - string_list_append_nodup(pack_lockfiles, - index_pack_lockfile(cmd.out)); + char *pack_lockfile = index_pack_lockfile(cmd.out); + if (pack_lockfile) + string_list_append_nodup(pack_lockfiles, pack_lockfile); close(cmd.out); } @@ -979,6 +983,9 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args, agent_len, agent_feature); } + if (!server_supports("session-id")) + advertise_sid = 0; + if (server_supports("shallow")) print_verbose(args, _("Server supports %s"), "shallow"); else if (args->depth > 0 || is_repository_shallow(r)) @@ -1191,6 +1198,8 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out, packet_buf_write(&req_buf, "command=fetch"); if (server_supports_v2("agent", 0)) packet_buf_write(&req_buf, "agent=%s", git_user_agent_sanitized()); + if (advertise_sid && server_supports_v2("session-id", 0)) + packet_buf_write(&req_buf, "session-id=%s", trace2_session_id()); if (args->server_options && args->server_options->nr && server_supports_v2("server-option", 1)) { int i; @@ -1711,6 +1720,7 @@ static void fetch_pack_config(void) git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta); git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects); git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects); + git_config_get_bool("transfer.advertisesid", &advertise_sid); if (!uri_protocols.nr) { char *str; @@ -535,7 +535,7 @@ static struct cmd_struct commands[] = { { "ls-tree", cmd_ls_tree, RUN_SETUP }, { "mailinfo", cmd_mailinfo, RUN_SETUP_GENTLY | NO_PARSEOPT }, { "mailsplit", cmd_mailsplit, NO_PARSEOPT }, - { "maintenance", cmd_maintenance, RUN_SETUP_GENTLY | NO_PARSEOPT }, + { "maintenance", cmd_maintenance, RUN_SETUP | NO_PARSEOPT }, { "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE }, { "merge-base", cmd_merge_base, RUN_SETUP }, { "merge-file", cmd_merge_file, RUN_SETUP_GENTLY }, @@ -14,7 +14,31 @@ static int grep_source_load(struct grep_source *gs); static int grep_source_is_binary(struct grep_source *gs, struct index_state *istate); -static struct grep_opt grep_defaults; +static void std_output(struct grep_opt *opt, const void *buf, size_t size) +{ + fwrite(buf, size, 1, stdout); +} + +static struct grep_opt grep_defaults = { + .relative = 1, + .pathname = 1, + .max_depth = -1, + .pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED, + .colors = { + [GREP_COLOR_CONTEXT] = "", + [GREP_COLOR_FILENAME] = "", + [GREP_COLOR_FUNCTION] = "", + [GREP_COLOR_LINENO] = "", + [GREP_COLOR_COLUMNNO] = "", + [GREP_COLOR_MATCH_CONTEXT] = GIT_COLOR_BOLD_RED, + [GREP_COLOR_MATCH_SELECTED] = GIT_COLOR_BOLD_RED, + [GREP_COLOR_SELECTED] = "", + [GREP_COLOR_SEP] = GIT_COLOR_CYAN, + }, + .only_matching = 0, + .color = -1, + .output = std_output, +}; #ifdef USE_LIBPCRE2 static pcre2_general_context *pcre2_global_context; @@ -42,50 +66,6 @@ static const char *color_grep_slots[] = { [GREP_COLOR_SEP] = "separator", }; -static void std_output(struct grep_opt *opt, const void *buf, size_t size) -{ - fwrite(buf, size, 1, stdout); -} - -static void color_set(char *dst, const char *color_bytes) -{ - xsnprintf(dst, COLOR_MAXLEN, "%s", color_bytes); -} - -/* - * Initialize the grep_defaults template with hardcoded defaults. - * We could let the compiler do this, but without C99 initializers - * the code gets unwieldy and unreadable, so... - */ -void init_grep_defaults(struct repository *repo) -{ - struct grep_opt *opt = &grep_defaults; - static int run_once; - - if (run_once) - return; - run_once++; - - memset(opt, 0, sizeof(*opt)); - opt->repo = repo; - opt->relative = 1; - opt->pathname = 1; - opt->max_depth = -1; - opt->pattern_type_option = GREP_PATTERN_TYPE_UNSPECIFIED; - color_set(opt->colors[GREP_COLOR_CONTEXT], ""); - color_set(opt->colors[GREP_COLOR_FILENAME], ""); - color_set(opt->colors[GREP_COLOR_FUNCTION], ""); - color_set(opt->colors[GREP_COLOR_LINENO], ""); - color_set(opt->colors[GREP_COLOR_COLUMNNO], ""); - color_set(opt->colors[GREP_COLOR_MATCH_CONTEXT], GIT_COLOR_BOLD_RED); - color_set(opt->colors[GREP_COLOR_MATCH_SELECTED], GIT_COLOR_BOLD_RED); - color_set(opt->colors[GREP_COLOR_SELECTED], ""); - color_set(opt->colors[GREP_COLOR_SEP], GIT_COLOR_CYAN); - opt->only_matching = 0; - opt->color = -1; - opt->output = std_output; -} - static int parse_pattern_type_arg(const char *opt, const char *arg) { if (!strcmp(arg, "default")) @@ -115,6 +95,14 @@ int grep_config(const char *var, const char *value, void *cb) if (userdiff_config(var, value) < 0) return -1; + /* + * The instance of grep_opt that we set up here is copied by + * grep_init() to be used by each individual invocation. + * When populating a new field of this structure here, be + * sure to think about ownership -- e.g., you might need to + * override the shallow copy in grep_init() with a deep copy. + */ + if (!strcmp(var, "grep.extendedregexp")) { opt->extended_regexp_option = git_config_bool(var, value); return 0; @@ -172,9 +160,6 @@ int grep_config(const char *var, const char *value, void *cb) */ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix) { - struct grep_opt *def = &grep_defaults; - int i; - #if defined(USE_LIBPCRE2) if (!pcre2_global_context) pcre2_global_context = pcre2_general_context_create( @@ -186,26 +171,13 @@ void grep_init(struct grep_opt *opt, struct repository *repo, const char *prefix pcre_free = free; #endif - memset(opt, 0, sizeof(*opt)); + *opt = grep_defaults; + opt->repo = repo; opt->prefix = prefix; opt->prefix_length = (prefix && *prefix) ? strlen(prefix) : 0; opt->pattern_tail = &opt->pattern_list; opt->header_tail = &opt->header_list; - - opt->only_matching = def->only_matching; - opt->color = def->color; - opt->extended_regexp_option = def->extended_regexp_option; - opt->pattern_type_option = def->pattern_type_option; - opt->linenum = def->linenum; - opt->columnnum = def->columnnum; - opt->max_depth = def->max_depth; - opt->pathname = def->pathname; - opt->relative = def->relative; - opt->output = def->output; - - for (i = 0; i < NR_GREP_COLORS; i++) - color_set(opt->colors[i], def->colors[i]); } void grep_destroy(void) @@ -170,7 +170,6 @@ struct grep_opt { void *output_priv; }; -void init_grep_defaults(struct repository *); int grep_config(const char *var, const char *value, void *); void grep_init(struct grep_opt *, struct repository *repo, const char *prefix); void grep_destroy(void); @@ -472,12 +472,26 @@ int is_in_cmdlist(struct cmdnames *c, const char *s) static int autocorrect; static struct cmdnames aliases; +#define AUTOCORRECT_NEVER (-2) +#define AUTOCORRECT_IMMEDIATELY (-1) + static int git_unknown_cmd_config(const char *var, const char *value, void *cb) { const char *p; - if (!strcmp(var, "help.autocorrect")) - autocorrect = git_config_int(var,value); + if (!strcmp(var, "help.autocorrect")) { + if (!value) + return config_error_nonbool(var); + if (!strcmp(value, "never")) { + autocorrect = AUTOCORRECT_NEVER; + } else if (!strcmp(value, "immediate")) { + autocorrect = AUTOCORRECT_IMMEDIATELY; + } else { + int v = git_config_int(var, value); + autocorrect = (v < 0) + ? AUTOCORRECT_IMMEDIATELY : v; + } + } /* Also use aliases for command lookup */ if (skip_prefix(var, "alias.", &p)) add_cmdname(&aliases, p, strlen(p)); @@ -525,6 +539,11 @@ const char *help_unknown_cmd(const char *cmd) read_early_config(git_unknown_cmd_config, NULL); + if (autocorrect == AUTOCORRECT_NEVER) { + fprintf_ln(stderr, _("git: '%s' is not a git command. See 'git --help'."), cmd); + exit(1); + } + load_command_list("git-", &main_cmds, &other_cmds); add_cmd_list(&main_cmds, &aliases); @@ -594,7 +613,7 @@ const char *help_unknown_cmd(const char *cmd) _("WARNING: You called a Git command named '%s', " "which does not exist."), cmd); - if (autocorrect < 0) + if (autocorrect == AUTOCORRECT_IMMEDIATELY) fprintf_ln(stderr, _("Continuing under the assumption that " "you meant '%s'."), diff --git a/imap-send.c b/imap-send.c index 5764dd812c..d0b94f911e 100644 --- a/imap-send.c +++ b/imap-send.c @@ -84,17 +84,17 @@ static int nfvasprintf(char **strp, const char *fmt, va_list ap) } struct imap_server_conf { - char *name; - char *tunnel; - char *host; + const char *name; + const char *tunnel; + const char *host; int port; - char *folder; - char *user; - char *pass; + const char *folder; + const char *user; + const char *pass; int use_ssl; int ssl_verify; int use_html; - char *auth_method; + const char *auth_method; }; static struct imap_server_conf server = { @@ -955,7 +955,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent srvc->pass = xstrdup(cred->password); } -static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder) +static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const char *folder) { struct credential cred = CREDENTIAL_INIT; struct imap_store *ctx; @@ -1338,15 +1338,26 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs) return 1; } -static void git_imap_config(void) +static int git_imap_config(const char *var, const char *val, void *cb) { - const char *val = NULL; - git_config_get_bool("imap.sslverify", &server.ssl_verify); - git_config_get_bool("imap.preformattedhtml", &server.use_html); - git_config_get_string("imap.folder", &server.folder); - - if (!git_config_get_value("imap.host", &val)) { + if (!strcmp("imap.sslverify", var)) + server.ssl_verify = git_config_bool(var, val); + else if (!strcmp("imap.preformattedhtml", var)) + server.use_html = git_config_bool(var, val); + else if (!strcmp("imap.folder", var)) + return git_config_string(&server.folder, var, val); + else if (!strcmp("imap.user", var)) + return git_config_string(&server.user, var, val); + else if (!strcmp("imap.pass", var)) + return git_config_string(&server.pass, var, val); + else if (!strcmp("imap.tunnel", var)) + return git_config_string(&server.tunnel, var, val); + else if (!strcmp("imap.authmethod", var)) + return git_config_string(&server.auth_method, var, val); + else if (!strcmp("imap.port", var)) + server.port = git_config_int(var, val); + else if (!strcmp("imap.host", var)) { if (!val) { git_die_config("imap.host", "Missing value for 'imap.host'"); } else { @@ -1360,13 +1371,10 @@ static void git_imap_config(void) val += 2; server.host = xstrdup(val); } - } + } else + return git_default_config(var, val, cb); - git_config_get_string("imap.user", &server.user); - git_config_get_string("imap.pass", &server.pass); - git_config_get_int("imap.port", &server.port); - git_config_get_string("imap.tunnel", &server.tunnel); - git_config_get_string("imap.authmethod", &server.auth_method); + return 0; } static int append_msgs_to_imap(struct imap_server_conf *server, @@ -1539,7 +1547,7 @@ int cmd_main(int argc, const char **argv) int nongit_ok; setup_git_directory_gently(&nongit_ok); - git_imap_config(); + git_config(git_imap_config, NULL); argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0); @@ -71,7 +71,10 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet } item->pattern = is_glob; - item->src = xstrndup(lhs, llen); + if (llen == 1 && *lhs == '@') + item->src = xstrdup("HEAD"); + else + item->src = xstrndup(lhs, llen); flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); if (item->negative) { @@ -272,15 +275,16 @@ void refspec_ref_prefixes(const struct refspec *rs, else if (item->src && !item->exact_sha1) prefix = item->src; - if (prefix) { - if (item->pattern) { - const char *glob = strchr(prefix, '*'); - strvec_pushf(ref_prefixes, "%.*s", - (int)(glob - prefix), - prefix); - } else { - expand_ref_prefix(ref_prefixes, prefix); - } + if (!prefix) + continue; + + if (item->pattern) { + const char *glob = strchr(prefix, '*'); + strvec_pushf(ref_prefixes, "%.*s", + (int)(glob - prefix), + prefix); + } else { + expand_ref_prefix(ref_prefixes, prefix); } } } @@ -355,7 +355,7 @@ static int handle_config(const char *key, const char *value, void *cb) remote = make_remote(name, namelen); remote->origin = REMOTE_CONFIG; if (current_config_scope() == CONFIG_SCOPE_LOCAL || - current_config_scope() == CONFIG_SCOPE_WORKTREE) + current_config_scope() == CONFIG_SCOPE_WORKTREE) remote->configured_in_repo = 1; if (!strcmp(subkey, "mirror")) remote->mirror = git_config_bool(key, value); diff --git a/revision.c b/revision.c index c6e169e3eb..9dff845bed 100644 --- a/revision.c +++ b/revision.c @@ -1827,7 +1827,6 @@ void repo_init_revisions(struct repository *r, revs->commit_format = CMIT_FMT_DEFAULT; revs->expand_tabs_in_log_default = 8; - init_grep_defaults(revs->repo); grep_init(&revs->grep_filter, revs->repo, prefix); revs->grep_filter.status_only = 1; diff --git a/send-pack.c b/send-pack.c index d2701bf35c..9045f8a082 100644 --- a/send-pack.c +++ b/send-pack.c @@ -425,6 +425,7 @@ int send_pack(struct send_pack_args *args, int use_sideband = 0; int quiet_supported = 0; int agent_supported = 0; + int advertise_sid = 0; int use_atomic = 0; int atomic_supported = 0; int use_push_options = 0; @@ -436,6 +437,8 @@ int send_pack(struct send_pack_args *args, const char *push_cert_nonce = NULL; struct packet_reader reader; + git_config_get_bool("transfer.advertisesid", &advertise_sid); + /* Does the other end support the reporting? */ if (server_supports("report-status-v2")) status_report = 2; @@ -451,6 +454,8 @@ int send_pack(struct send_pack_args *args, quiet_supported = 1; if (server_supports("agent")) agent_supported = 1; + if (!server_supports("session-id")) + advertise_sid = 0; if (server_supports("no-thin")) args->use_thin_pack = 0; if (server_supports("atomic")) @@ -507,6 +512,8 @@ int send_pack(struct send_pack_args *args, strbuf_addf(&cap_buf, " object-format=%s", the_hash_algo->name); if (agent_supported) strbuf_addf(&cap_buf, " agent=%s", git_user_agent_sanitized()); + if (advertise_sid) + strbuf_addf(&cap_buf, " session-id=%s", trace2_session_id()); /* * NEEDSWORK: why does delete-refs have to be so specific to @@ -8,6 +8,8 @@ #include "serve.h" #include "upload-pack.h" +static int advertise_sid; + static int always_advertise(struct repository *r, struct strbuf *value) { @@ -30,6 +32,15 @@ static int object_format_advertise(struct repository *r, return 1; } +static int session_id_advertise(struct repository *r, struct strbuf *value) +{ + if (!advertise_sid) + return 0; + if (value) + strbuf_addstr(value, trace2_session_id()); + return 1; +} + struct protocol_capability { /* * The name of the capability. The server uses this name when @@ -66,6 +77,7 @@ static struct protocol_capability capabilities[] = { { "fetch", upload_pack_advertise, upload_pack_v2 }, { "server-option", always_advertise, NULL }, { "object-format", object_format_advertise, NULL }, + { "session-id", session_id_advertise, NULL }, }; static void advertise_capabilities(void) @@ -189,6 +201,7 @@ static int process_request(void) struct packet_reader reader; struct strvec keys = STRVEC_INIT; struct protocol_capability *command = NULL; + const char *client_sid; packet_reader_init(&reader, 0, NULL, 0, PACKET_READ_CHOMP_NEWLINE | @@ -252,6 +265,9 @@ static int process_request(void) check_algorithm(the_repository, &keys); + if (has_capability(&keys, "session-id", &client_sid)) + trace2_data_string("transfer", NULL, "client-sid", client_sid); + command->command(the_repository, &keys, &reader); strvec_clear(&keys); @@ -261,6 +277,8 @@ static int process_request(void) /* Main serve loop for protocol version 2 */ void serve(struct serve_options *options) { + git_config_get_bool("transfer.advertisesid", &advertise_sid); + if (options->advertise_capabilities || !options->stateless_rpc) { /* serve by default supports v2 */ packet_write_fmt(1, "version 2\n"); diff --git a/sha1-file.c b/sha1-file.c index dd65bd5c68..c3c49d2fa5 100644 --- a/sha1-file.c +++ b/sha1-file.c @@ -291,7 +291,7 @@ int mkdir_in_gitdir(const char *path) return adjust_shared_perm(path); } -enum scld_error safe_create_leading_directories(char *path) +static enum scld_error safe_create_leading_directories_1(char *path, int share) { char *next_component = path + offset_1st_component(path); enum scld_error ret = SCLD_OK; @@ -337,7 +337,7 @@ enum scld_error safe_create_leading_directories(char *path) ret = SCLD_VANISHED; else ret = SCLD_FAILED; - } else if (adjust_shared_perm(path)) { + } else if (share && adjust_shared_perm(path)) { ret = SCLD_PERMS; } *slash = slash_character; @@ -345,6 +345,16 @@ enum scld_error safe_create_leading_directories(char *path) return ret; } +enum scld_error safe_create_leading_directories(char *path) +{ + return safe_create_leading_directories_1(path, 1); +} + +enum scld_error safe_create_leading_directories_no_share(char *path) +{ + return safe_create_leading_directories_1(path, 0); +} + enum scld_error safe_create_leading_directories_const(const char *path) { int save_errno; diff --git a/t/perf/p7519-fsmonitor.sh b/t/perf/p7519-fsmonitor.sh index 163a13bea3..9b43342806 100755 --- a/t/perf/p7519-fsmonitor.sh +++ b/t/perf/p7519-fsmonitor.sh @@ -129,8 +129,7 @@ setup_for_fsmonitor() { git config core.fsmonitor "$INTEGRATION_SCRIPT" && git update-index --fsmonitor 2>error && - cat error && - [ ! -s error ] # ensure no silent error + test_must_be_empty error # ensure no silent error } test_perf_w_drop_caches () { diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index 5cdd76dfa7..41818d8315 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -73,4 +73,30 @@ test_expect_success FILEMODE 'bogus mode is rejected' ' test_i18ngrep "invalid mode" err ' +test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree files' ' + git reset --hard && + test_config core.sharedRepository 0666 && + ( + # Remove a default ACL if possible. + (setfacl -k newdir 2>/dev/null || true) && + umask 0077 && + + # Test both files (f1) and leading dirs (d) + mkdir d && + touch f1 d/f2 && + git add f1 d/f2 && + git diff --staged >patch-f1-and-f2.txt && + + rm -rf d f1 && + git apply patch-f1-and-f2.txt && + + echo "-rw-------" >f1_mode.expected && + echo "drwx------" >d_mode.expected && + test_modebits f1 >f1_mode.actual && + test_modebits d >d_mode.actual && + test_cmp f1_mode.expected f1_mode.actual && + test_cmp d_mode.expected d_mode.actual + ) +' + test_done diff --git a/t/t5511-refspec.sh b/t/t5511-refspec.sh index f541f30bc2..f808649de4 100755 --- a/t/t5511-refspec.sh +++ b/t/t5511-refspec.sh @@ -58,6 +58,8 @@ test_refspec fetch 'HEAD~4:refs/remotes/frotz/new' invalid test_refspec push 'HEAD' test_refspec fetch 'HEAD' +test_refspec push '@' +test_refspec fetch '@' test_refspec push 'refs/heads/ nitfol' invalid test_refspec fetch 'refs/heads/ nitfol' invalid diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index d11382f769..01004ff680 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -436,70 +436,76 @@ test_expect_success 'push ref expression with non-existent, incomplete dest' ' ' -test_expect_success 'push with HEAD' ' +for head in HEAD @ +do - mk_test testrepo heads/master && - git checkout master && - git push testrepo HEAD && - check_push_result testrepo $the_commit heads/master + test_expect_success "push with $head" ' -' + mk_test testrepo heads/master && + git checkout master && + git push testrepo $head && + check_push_result testrepo $the_commit heads/master -test_expect_success 'push with HEAD nonexisting at remote' ' + ' - mk_test testrepo heads/master && - git checkout -b local master && - git push testrepo HEAD && - check_push_result testrepo $the_commit heads/local -' + test_expect_success "push with $head nonexisting at remote" ' -test_expect_success 'push with +HEAD' ' + mk_test testrepo heads/master && + git checkout -b local master && + test_when_finished "git checkout master; git branch -D local" && + git push testrepo $head && + check_push_result testrepo $the_commit heads/local + ' - mk_test testrepo heads/master && - git checkout master && - git branch -D local && - git checkout -b local && - git push testrepo master local && - check_push_result testrepo $the_commit heads/master && - check_push_result testrepo $the_commit heads/local && + test_expect_success "push with +$head" ' - # Without force rewinding should fail - git reset --hard HEAD^ && - test_must_fail git push testrepo HEAD && - check_push_result testrepo $the_commit heads/local && + mk_test testrepo heads/master && + git checkout -b local master && + test_when_finished "git checkout master; git branch -D local" && + git push testrepo master local && + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_commit heads/local && - # With force rewinding should succeed - git push testrepo +HEAD && - check_push_result testrepo $the_first_commit heads/local + # Without force rewinding should fail + git reset --hard $head^ && + test_must_fail git push testrepo $head && + check_push_result testrepo $the_commit heads/local && -' + # With force rewinding should succeed + git push testrepo +$head && + check_push_result testrepo $the_first_commit heads/local -test_expect_success 'push HEAD with non-existent, incomplete dest' ' + ' - mk_test testrepo && - git checkout master && - git push testrepo HEAD:branch && - check_push_result testrepo $the_commit heads/branch + test_expect_success "push $head with non-existent, incomplete dest" ' -' + mk_test testrepo && + git checkout master && + git push testrepo $head:branch && + check_push_result testrepo $the_commit heads/branch -test_expect_success 'push with config remote.*.push = HEAD' ' + ' - mk_test testrepo heads/local && - git checkout master && - git branch -f local $the_commit && - ( - cd testrepo && - git checkout local && - git reset --hard $the_first_commit - ) && - test_config remote.there.url testrepo && - test_config remote.there.push HEAD && - test_config branch.master.remote there && - git push && - check_push_result testrepo $the_commit heads/master && - check_push_result testrepo $the_first_commit heads/local -' + test_expect_success "push with config remote.*.push = $head" ' + + mk_test testrepo heads/local && + git checkout master && + git branch -f local $the_commit && + test_when_finished "git branch -D local" && + ( + cd testrepo && + git checkout local && + git reset --hard $the_first_commit + ) && + test_config remote.there.url testrepo && + test_config remote.there.push $head && + test_config branch.master.remote there && + git push && + check_push_result testrepo $the_commit heads/master && + check_push_result testrepo $the_first_commit heads/local + ' + +done test_expect_success 'push with remote.pushdefault' ' mk_test up_repo heads/master && diff --git a/t/t5526-fetch-submodules.sh b/t/t5526-fetch-submodules.sh index dd8e423d25..a877dd145e 100755 --- a/t/t5526-fetch-submodules.sh +++ b/t/t5526-fetch-submodules.sh @@ -18,7 +18,7 @@ add_upstream_commit() { head2=$(git rev-parse --short HEAD) && echo "Fetching submodule submodule" > ../expect.err && echo "From $pwd/submodule" >> ../expect.err && - echo " $head1..$head2 main -> origin/main" >> ../expect.err + echo " $head1..$head2 sub -> origin/sub" >> ../expect.err ) && ( cd deepsubmodule && @@ -30,7 +30,7 @@ add_upstream_commit() { head2=$(git rev-parse --short HEAD) && echo "Fetching submodule submodule/subdir/deepsubmodule" >> ../expect.err echo "From $pwd/deepsubmodule" >> ../expect.err && - echo " $head1..$head2 main -> origin/main" >> ../expect.err + echo " $head1..$head2 deep -> origin/deep" >> ../expect.err ) } @@ -41,7 +41,8 @@ test_expect_success setup ' git init && echo deepsubcontent > deepsubfile && git add deepsubfile && - git commit -m new deepsubfile + git commit -m new deepsubfile && + git branch -M deep ) && mkdir submodule && ( @@ -50,10 +51,12 @@ test_expect_success setup ' echo subcontent > subfile && git add subfile && git submodule add "$pwd/deepsubmodule" subdir/deepsubmodule && - git commit -a -m new + git commit -a -m new && + git branch -M sub ) && git submodule add "$pwd/submodule" submodule && git commit -am initial && + git branch -M super && git clone . downstream && ( cd downstream && @@ -61,7 +64,7 @@ test_expect_success setup ' ) ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "fetch --recurse-submodules recurses into submodules" ' +test_expect_success "fetch --recurse-submodules recurses into submodules" ' add_upstream_commit && ( cd downstream && @@ -71,7 +74,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "fetch --recurse-submodules recurses test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "submodule.recurse option triggers recursive fetch" ' +test_expect_success "submodule.recurse option triggers recursive fetch" ' add_upstream_commit && ( cd downstream && @@ -81,7 +84,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "submodule.recurse option triggers r test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "fetch --recurse-submodules -j2 has the same output behaviour" ' +test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" ' add_upstream_commit && ( cd downstream && @@ -111,7 +114,7 @@ test_expect_success "fetch --no-recurse-submodules only fetches superproject" ' test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" ' +test_expect_success "using fetchRecurseSubmodules=true in .gitmodules recurses into submodules" ' ( cd downstream && git config -f .gitmodules submodule.submodule.fetchRecurseSubmodules true && @@ -141,7 +144,7 @@ test_expect_success "using fetchRecurseSubmodules=false in .git/config overrides test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" ' +test_expect_success "--recurse-submodules overrides fetchRecurseSubmodules setting from .git/config" ' ( cd downstream && git fetch --recurse-submodules >../actual.out 2>../actual.err && @@ -170,7 +173,7 @@ test_expect_success "--quiet propagates to parallel submodules" ' test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "--dry-run propagates to submodules" ' +test_expect_success "--dry-run propagates to submodules" ' add_upstream_commit && ( cd downstream && @@ -180,7 +183,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "--dry-run propagates to submodules" test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Without --dry-run propagates to submodules" ' +test_expect_success "Without --dry-run propagates to submodules" ' ( cd downstream && git fetch --recurse-submodules >../actual.out 2>../actual.err @@ -189,7 +192,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Without --dry-run propagates to sub test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "recurseSubmodules=true propagates into submodules" ' +test_expect_success "recurseSubmodules=true propagates into submodules" ' add_upstream_commit && ( cd downstream && @@ -200,7 +203,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "recurseSubmodules=true propagates i test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "--recurse-submodules overrides config in submodule" ' +test_expect_success "--recurse-submodules overrides config in submodule" ' add_upstream_commit && ( cd downstream && @@ -225,7 +228,7 @@ test_expect_success "--no-recurse-submodules overrides config setting" ' test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion doesn't happen when no new commits are fetched in the superproject" ' +test_expect_success "Recursion doesn't happen when no new commits are fetched in the superproject" ' ( cd downstream && ( @@ -239,13 +242,13 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion doesn't happen when no ne test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion stops when no new submodule commits are fetched" ' +test_expect_success "Recursion stops when no new submodule commits are fetched" ' head1=$(git rev-parse --short HEAD) && git add submodule && git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.sub && - echo " $head1..$head2 main -> origin/main" >>expect.err.sub && + echo " $head1..$head2 super -> origin/super" >>expect.err.sub && head -3 expect.err >> expect.err.sub && ( cd downstream && @@ -255,7 +258,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion stops when no new submodu test_must_be_empty actual.out ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion doesn't happen when new superproject commits don't change any submodules" ' +test_expect_success "Recursion doesn't happen when new superproject commits don't change any submodules" ' add_upstream_commit && head1=$(git rev-parse --short HEAD) && echo a > file && @@ -263,7 +266,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion doesn't happen when new s git commit -m "new file" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.file && - echo " $head1..$head2 main -> origin/main" >> expect.err.file && + echo " $head1..$head2 super -> origin/super" >> expect.err.file && ( cd downstream && git fetch >../actual.out 2>../actual.err @@ -272,7 +275,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion doesn't happen when new s test_i18ncmp expect.err.file actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up config in submodule" ' +test_expect_success "Recursion picks up config in submodule" ' ( cd downstream && git fetch --recurse-submodules && @@ -287,7 +290,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up config in submod git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.sub && - echo " $head1..$head2 main -> origin/main" >> expect.err.sub && + echo " $head1..$head2 super -> origin/super" >> expect.err.sub && cat expect.err >> expect.err.sub && ( cd downstream && @@ -301,7 +304,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up config in submod test_must_be_empty actual.out ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up all submodules when necessary" ' +test_expect_success "Recursion picks up all submodules when necessary" ' add_upstream_commit && ( cd submodule && @@ -316,14 +319,14 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up all submodules w head2=$(git rev-parse --short HEAD) && echo "Fetching submodule submodule" > ../expect.err.sub && echo "From $pwd/submodule" >> ../expect.err.sub && - echo " $head1..$head2 main -> origin/main" >> ../expect.err.sub + echo " $head1..$head2 sub -> origin/sub" >> ../expect.err.sub ) && head1=$(git rev-parse --short HEAD) && git add submodule && git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && - echo " $head1..$head2 main -> origin/main" >> expect.err.2 && + echo " $head1..$head2 super -> origin/super" >> expect.err.2 && cat expect.err.sub >> expect.err.2 && tail -3 expect.err >> expect.err.2 && ( @@ -334,7 +337,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "Recursion picks up all submodules w test_must_be_empty actual.out ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" ' +test_expect_success "'--recurse-submodules=on-demand' doesn't recurse when no new commits are fetched in the superproject (and ignores config)" ' add_upstream_commit && ( cd submodule && @@ -349,7 +352,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' do head2=$(git rev-parse --short HEAD) && echo Fetching submodule submodule > ../expect.err.sub && echo "From $pwd/submodule" >> ../expect.err.sub && - echo " $head1..$head2 main -> origin/main" >> ../expect.err.sub + echo " $head1..$head2 sub -> origin/sub" >> ../expect.err.sub ) && ( cd downstream && @@ -361,14 +364,14 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' do test_must_be_empty actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" ' +test_expect_success "'--recurse-submodules=on-demand' recurses as deep as necessary (and ignores config)" ' head1=$(git rev-parse --short HEAD) && git add submodule && git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && tail -3 expect.err > expect.err.deepsub && echo "From $pwd/." > expect.err && - echo " $head1..$head2 main -> origin/main" >>expect.err && + echo " $head1..$head2 super -> origin/super" >>expect.err && cat expect.err.sub >> expect.err && cat expect.err.deepsub >> expect.err && ( @@ -389,7 +392,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' re test_i18ncmp expect.err actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" ' +test_expect_success "'--recurse-submodules=on-demand' stops when no new submodule commits are found in the superproject (and ignores config)" ' add_upstream_commit && head1=$(git rev-parse --short HEAD) && echo a >> file && @@ -397,7 +400,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' st git commit -m "new file" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.file && - echo " $head1..$head2 main -> origin/main" >> expect.err.file && + echo " $head1..$head2 super -> origin/super" >> expect.err.file && ( cd downstream && git fetch --recurse-submodules=on-demand >../actual.out 2>../actual.err @@ -406,7 +409,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'--recurse-submodules=on-demand' st test_i18ncmp expect.err.file actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'fetch.recurseSubmodules=on-demand' overrides global config" ' +test_expect_success "'fetch.recurseSubmodules=on-demand' overrides global config" ' ( cd downstream && git fetch --recurse-submodules @@ -418,7 +421,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'fetch.recurseSubmodules=on-demand' git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && - echo " $head1..$head2 main -> origin/main" >>expect.err.2 && + echo " $head1..$head2 super -> origin/super" >>expect.err.2 && head -3 expect.err >> expect.err.2 && ( cd downstream && @@ -434,7 +437,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'fetch.recurseSubmodules=on-demand' test_i18ncmp expect.err.2 actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" ' +test_expect_success "'submodule.<sub>.fetchRecurseSubmodules=on-demand' overrides fetch.recurseSubmodules" ' ( cd downstream && git fetch --recurse-submodules @@ -446,7 +449,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'submodule.<sub>.fetchRecurseSubmod git commit -m "new submodule" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err.2 && - echo " $head1..$head2 main -> origin/main" >>expect.err.2 && + echo " $head1..$head2 super -> origin/super" >>expect.err.2 && head -3 expect.err >> expect.err.2 && ( cd downstream && @@ -462,7 +465,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'submodule.<sub>.fetchRecurseSubmod test_i18ncmp expect.err.2 actual.err ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "don't fetch submodule when newly recorded commits are already present" ' +test_expect_success "don't fetch submodule when newly recorded commits are already present" ' ( cd submodule && git checkout -q HEAD^^ @@ -472,7 +475,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "don't fetch submodule when newly re git commit -m "submodule rewound" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." > expect.err && - echo " $head1..$head2 main -> origin/main" >> expect.err && + echo " $head1..$head2 super -> origin/super" >> expect.err && ( cd downstream && git fetch >../actual.out 2>../actual.err @@ -481,11 +484,11 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "don't fetch submodule when newly re test_i18ncmp expect.err actual.err && ( cd submodule && - git checkout -q master + git checkout -q sub ) ' -test_expect_success PREPARE_FOR_MAIN_BRANCH "'fetch.recurseSubmodules=on-demand' works also without .gitmodules entry" ' +test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .gitmodules entry" ' ( cd downstream && git fetch --recurse-submodules @@ -497,7 +500,7 @@ test_expect_success PREPARE_FOR_MAIN_BRANCH "'fetch.recurseSubmodules=on-demand' git commit -m "new submodule without .gitmodules" && head2=$(git rev-parse --short HEAD) && echo "From $pwd/." >expect.err.2 && - echo " $head1..$head2 main -> origin/main" >>expect.err.2 && + echo " $head1..$head2 super -> origin/super" >>expect.err.2 && head -3 expect.err >>expect.err.2 && ( cd downstream && @@ -663,9 +666,9 @@ test_expect_success 'fetch new submodule commits on-demand without .gitmodules e git config -f .gitmodules --remove-section submodule.sub1 && git add .gitmodules && git commit -m "delete gitmodules file" && - git checkout -B master && + git checkout -B super && git -C downstream fetch && - git -C downstream checkout origin/master && + git -C downstream checkout origin/super && C=$(git -C submodule commit-tree -m "yet another change outside refs/heads" HEAD^{tree}) && git -C submodule update-ref refs/changes/7 $C && diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh index f4d49d8335..2ea66205cf 100755 --- a/t/t5616-partial-clone.sh +++ b/t/t5616-partial-clone.sh @@ -251,6 +251,14 @@ test_expect_success 'implicitly construct combine: filter with repeated flags' ' test_cmp unique_types.expected unique_types.actual ' +test_expect_success 'upload-pack complains of bogus filter config' ' + printf 0000 | + test_must_fail git \ + -c uploadpackfilter.tree.maxdepth \ + upload-pack . >/dev/null 2>err && + test_i18ngrep "unable to parse.*tree.maxdepth" err +' + test_expect_success 'upload-pack fails banned object filters' ' test_config -C srv.bare uploadpackfilter.blob:none.allow false && test_must_fail ok=sigpipe git clone --no-checkout --filter=blob:none \ diff --git a/t/t5705-session-id-in-capabilities.sh b/t/t5705-session-id-in-capabilities.sh new file mode 100755 index 0000000000..f1d189d5bc --- /dev/null +++ b/t/t5705-session-id-in-capabilities.sh @@ -0,0 +1,78 @@ +#!/bin/sh + +test_description='session ID in capabilities' + +. ./test-lib.sh + +REPO="$(pwd)/repo" +LOCAL_PRISTINE="$(pwd)/local_pristine" + +test_expect_success 'setup repos for session ID capability tests' ' + git init "$REPO" && + test_commit -C "$REPO" a && + git clone "file://$REPO" "$LOCAL_PRISTINE" && + test_commit -C "$REPO" b +' + +for PROTO in 0 1 2 +do + test_expect_success "session IDs not advertised by default (fetch v${PROTO})" ' + test_when_finished "rm -rf local tr2-client-events tr2-server-events" && + cp -r "$LOCAL_PRISTINE" local && + GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \ + git -c protocol.version=$PROTO -C local fetch \ + --upload-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-upload-pack" \ + origin && + test -z "$(grep \"key\":\"server-sid\" tr2-client-events)" && + test -z "$(grep \"key\":\"client-sid\" tr2-server-events)" + ' + + test_expect_success "session IDs not advertised by default (push v${PROTO})" ' + test_when_finished "rm -rf local tr2-client-events tr2-server-events" && + test_when_finished "git -C local push --delete origin new-branch" && + cp -r "$LOCAL_PRISTINE" local && + git -C local pull --no-rebase origin && + GIT_TRACE2_EVENT_NESTING=5 \ + GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \ + git -c protocol.version=$PROTO -C local push \ + --receive-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-receive-pack" \ + origin HEAD:new-branch && + test -z "$(grep \"key\":\"server-sid\" tr2-client-events)" && + test -z "$(grep \"key\":\"client-sid\" tr2-server-events)" + ' +done + +test_expect_success 'enable SID advertisement' ' + git -C "$REPO" config transfer.advertiseSID true && + git -C "$LOCAL_PRISTINE" config transfer.advertiseSID true +' + +for PROTO in 0 1 2 +do + test_expect_success "session IDs advertised (fetch v${PROTO})" ' + test_when_finished "rm -rf local tr2-client-events tr2-server-events" && + cp -r "$LOCAL_PRISTINE" local && + GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \ + git -c protocol.version=$PROTO -C local fetch \ + --upload-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-upload-pack" \ + origin && + grep \"key\":\"server-sid\" tr2-client-events && + grep \"key\":\"client-sid\" tr2-server-events + ' + + test_expect_success "session IDs advertised (push v${PROTO})" ' + test_when_finished "rm -rf local tr2-client-events tr2-server-events" && + test_when_finished "git -C local push --delete origin new-branch" && + cp -r "$LOCAL_PRISTINE" local && + git -C local pull --no-rebase origin && + GIT_TRACE2_EVENT_NESTING=5 \ + GIT_TRACE2_EVENT="$(pwd)/tr2-client-events" \ + git -c protocol.version=$PROTO -C local push \ + --receive-pack "GIT_TRACE2_EVENT=\"$(pwd)/tr2-server-events\" git-receive-pack" \ + origin HEAD:new-branch && + grep \"key\":\"server-sid\" tr2-client-events && + grep \"key\":\"client-sid\" tr2-server-events + ' +done + +test_done diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index e4fcee8686..d1e0c8f830 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -239,13 +239,15 @@ test_expect_success 'incremental-repack task' ' ' test_expect_success EXPENSIVE 'incremental-repack 2g limit' ' + test_config core.compression 0 && + for i in $(test_seq 1 5) do test-tool genrandom foo$i $((512 * 1024 * 1024 + 1)) >>big || return 1 done && git add big && - git commit -m "Add big file (1)" && + git commit -qm "Add big file (1)" && # ensure any possible loose objects are in a pack-file git maintenance run --task=loose-objects && @@ -257,7 +259,7 @@ test_expect_success EXPENSIVE 'incremental-repack 2g limit' ' return 1 done && git add big && - git commit -m "Add big file (2)" && + git commit -qm "Add big file (2)" && # ensure any possible loose objects are in a pack-file git maintenance run --task=loose-objects && @@ -453,4 +455,12 @@ test_expect_success 'register preserves existing strategy' ' test_config maintenance.strategy incremental ' +test_expect_success 'fails when running outside of a repository' ' + nongit test_must_fail git maintenance run && + nongit test_must_fail git maintenance stop && + nongit test_must_fail git maintenance start && + nongit test_must_fail git maintenance register && + nongit test_must_fail git maintenance unregister +' + test_done diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh index b1c7919c4a..03cd5c5423 100755 --- a/t/t9003-help-autocorrect.sh +++ b/t/t9003-help-autocorrect.sh @@ -37,16 +37,30 @@ test_expect_success 'autocorrect showing candidates' ' grep "^ distimdistim" actual ' -test_expect_success 'autocorrect running commands' ' - git config help.autocorrect -1 && +for immediate in -1 immediate +do + test_expect_success 'autocorrect running commands' ' + git config help.autocorrect $immediate && - git lfg >actual && - echo "a single log entry" >expect && - test_cmp expect actual && + git lfg >actual && + echo "a single log entry" >expect && + test_cmp expect actual && - git distimdist >actual && - echo "distimdistim was called" >expect && - test_cmp expect actual + git distimdist >actual && + echo "distimdistim was called" >expect && + test_cmp expect actual + ' +done + +test_expect_success 'autocorrect can be declined altogether' ' + git config help.autocorrect never && + + test_must_fail git lfg 2>actual && + if test_have_prereq C_LOCALE_OUTPUT + then + grep "is not a git command" actual && + test_line_count = 1 actual + fi ' test_done diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 5c01c75d40..81a728c743 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -906,7 +906,7 @@ test_expect_success '__git_refs - after --opt= - full refs' ' test_cmp expected "$actual" ' -test_expect_success '__git refs - exluding refs' ' +test_expect_success '__git refs - excluding refs' ' cat >expected <<-EOF && ^HEAD ^master @@ -922,7 +922,7 @@ test_expect_success '__git refs - exluding refs' ' test_cmp expected "$actual" ' -test_expect_success '__git refs - exluding full refs' ' +test_expect_success '__git refs - excluding full refs' ' cat >expected <<-EOF && ^refs/heads/master ^refs/heads/matching-branch diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 7ba3011b90..eca4d311ef 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -367,9 +367,9 @@ test_chmod () { git update-index --add "--chmod=$@" } -# Get the modebits from a file. +# Get the modebits from a file or directory. test_modebits () { - ls -l "$1" | sed -e 's|^\(..........\).*|\1|' + ls -ld "$1" | sed -e 's|^\(..........\).*|\1|' } # Unset a configuration variable, but don't fail if it doesn't exist. @@ -955,7 +955,7 @@ test_expect_code () { # - cmp's output is not nearly as easy to read as diff -u # - not all diff versions understand "-u" -test_cmp() { +test_cmp () { eval "$GIT_TEST_CMP" '"$@"' } @@ -968,7 +968,7 @@ test_cmp() { # # test_cmp_config foo core.bar # -test_cmp_config() { +test_cmp_config () { local GD && if test "$1" = "-C" then @@ -984,7 +984,7 @@ test_cmp_config() { # test_cmp_bin - helper to compare binary files -test_cmp_bin() { +test_cmp_bin () { cmp "$@" } @@ -1418,7 +1418,7 @@ nongit () { # whitespace and put in a single packet. Note that data containing NULs must be # given on stdin, and that empty input becomes an empty packet, not a flush # packet (for that you can just print 0000 yourself). -packetize() { +packetize () { if test $# -gt 0 then packet="$*" @@ -792,3 +792,8 @@ void trace2_printf(const char *fmt, ...) va_end(ap); } #endif + +const char *trace2_session_id(void) +{ + return tr2_sid_get(); +} @@ -500,4 +500,6 @@ void trace2_collect_process_info(enum trace2_process_info_reason reason); } while (0) #endif +const char *trace2_session_id(void); + #endif /* TRACE2_H */ diff --git a/transport.c b/transport.c index 47da955e4f..679a35e7c1 100644 --- a/transport.c +++ b/transport.c @@ -286,6 +286,8 @@ static struct ref *handshake(struct transport *transport, int for_push, struct git_transport_data *data = transport->data; struct ref *refs = NULL; struct packet_reader reader; + int sid_len; + const char *server_sid; connect_setup(transport, for_push); @@ -297,6 +299,8 @@ static struct ref *handshake(struct transport *transport, int for_push, data->version = discover_version(&reader); switch (data->version) { case protocol_v2: + if (server_feature_v2("session-id", &server_sid)) + trace2_data_string("transfer", NULL, "server-sid", server_sid); if (must_list_refs) get_remote_refs(data->fd[1], &reader, &refs, for_push, ref_prefixes, @@ -310,6 +314,12 @@ static struct ref *handshake(struct transport *transport, int for_push, for_push ? REF_NORMAL : 0, &data->extra_have, &data->shallow); + server_sid = server_feature_value("session-id", &sid_len); + if (server_sid) { + char *sid = xstrndup(server_sid, sid_len); + trace2_data_string("transfer", NULL, "server-sid", sid); + free(sid); + } break; case protocol_unknown_version: BUG("unknown protocol version"); diff --git a/upload-pack.c b/upload-pack.c index 1006bebd50..25e0ee1e0d 100644 --- a/upload-pack.c +++ b/upload-pack.c @@ -110,6 +110,7 @@ struct upload_pack_data { unsigned done : 1; /* v2 only */ unsigned allow_ref_in_want : 1; /* v2 only */ unsigned allow_sideband_all : 1; /* v2 only */ + unsigned advertise_sid : 1; }; static void upload_pack_data_init(struct upload_pack_data *data) @@ -141,6 +142,7 @@ static void upload_pack_data_init(struct upload_pack_data *data) packet_writer_init(&data->writer, 1); data->keepalive = 5; + data->advertise_sid = 0; } static void upload_pack_data_clear(struct upload_pack_data *data) @@ -1057,6 +1059,7 @@ static void receive_needs(struct upload_pack_data *data, const char *features; struct object_id oid_buf; const char *arg; + int feature_len; reset_timeout(data->timeout); if (packet_reader_read(reader) != PACKET_READ_NORMAL) @@ -1109,6 +1112,13 @@ static void receive_needs(struct upload_pack_data *data, parse_feature_request(features, "filter")) data->filter_capability_requested = 1; + arg = parse_feature_value(features, "session-id", &feature_len, NULL); + if (arg) { + char *client_sid = xstrndup(arg, feature_len); + trace2_data_string("transfer", NULL, "client-sid", client_sid); + free(client_sid); + } + o = parse_object(the_repository, &oid_buf); if (!o) { packet_writer_error(&data->writer, @@ -1179,6 +1189,11 @@ static void format_symref_info(struct strbuf *buf, struct string_list *symref) strbuf_addf(buf, " symref=%s:%s", item->string, (char *)item->util); } +static void format_session_id(struct strbuf *buf, struct upload_pack_data *d) { + if (d->advertise_sid) + strbuf_addf(buf, " session-id=%s", trace2_session_id()); +} + static int send_ref(const char *refname, const struct object_id *oid, int flag, void *cb_data) { @@ -1194,9 +1209,11 @@ static int send_ref(const char *refname, const struct object_id *oid, if (capabilities) { struct strbuf symref_info = STRBUF_INIT; + struct strbuf session_id = STRBUF_INIT; format_symref_info(&symref_info, &data->symref); - packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s object-format=%s agent=%s\n", + format_session_id(&session_id, data); + packet_write_fmt(1, "%s %s%c%s%s%s%s%s%s%s object-format=%s agent=%s\n", oid_to_hex(oid), refname_nons, 0, capabilities, (data->allow_uor & ALLOW_TIP_SHA1) ? @@ -1206,9 +1223,11 @@ static int send_ref(const char *refname, const struct object_id *oid, data->stateless_rpc ? " no-done" : "", symref_info.buf, data->allow_filter ? " filter" : "", + session_id.buf, the_hash_algo->name, git_user_agent_sanitized()); strbuf_release(&symref_info); + strbuf_release(&session_id); } else { packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), refname_nons); } @@ -1300,15 +1319,18 @@ static int upload_pack_config(const char *var, const char *value, void *cb_data) data->allow_sideband_all = git_config_bool(var, value); } else if (!strcmp("core.precomposeunicode", var)) { precomposed_unicode = git_config_bool(var, value); + } else if (!strcmp("transfer.advertisesid", var)) { + data->advertise_sid = git_config_bool(var, value); } if (current_config_scope() != CONFIG_SCOPE_LOCAL && - current_config_scope() != CONFIG_SCOPE_WORKTREE) { + current_config_scope() != CONFIG_SCOPE_WORKTREE) { if (!strcmp("uploadpack.packobjectshook", var)) return git_config_string(&data->pack_objects_hook, var, value); } - parse_object_filter_config(var, value, data); + if (parse_object_filter_config(var, value, data) < 0) + return -1; return parse_hide_refs_config(var, value, "uploadpack"); } |