summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml1
-rw-r--r--.gitignore3
-rw-r--r--Documentation/Makefile5
-rw-r--r--Documentation/MyFirstObjectWalk.txt34
-rw-r--r--Documentation/RelNotes/2.30.0.txt73
-rw-r--r--Documentation/config.txt2
-rw-r--r--Documentation/config/help.txt15
-rw-r--r--Documentation/config/transfer.txt4
-rw-r--r--Documentation/git-config.txt35
-rw-r--r--Documentation/git-update-ref.txt3
-rw-r--r--Documentation/glossary-content.txt2
-rw-r--r--Documentation/technical/api-trace2.txt2
-rw-r--r--Documentation/technical/protocol-capabilities.txt17
-rw-r--r--Documentation/technical/protocol-v2.txt13
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--Makefile1
-rw-r--r--add-interactive.c38
-rw-r--r--add-patch.c25
-rw-r--r--apply.c2
-rw-r--r--banned.h13
-rw-r--r--builtin/branch.c4
-rw-r--r--builtin/bugreport.c3
-rw-r--r--builtin/config.c81
-rw-r--r--builtin/gc.c12
-rw-r--r--builtin/grep.c1
-rw-r--r--builtin/log.c1
-rw-r--r--builtin/receive-pack.c15
-rw-r--r--builtin/remote.c8
-rw-r--r--builtin/update-ref.c15
-rw-r--r--cache.h7
-rwxr-xr-xcompat/vcbuild/scripts/clink.pl2
-rw-r--r--config.c75
-rw-r--r--config.h36
-rw-r--r--contrib/buildsystems/CMakeLists.txt15
-rwxr-xr-xcontrib/buildsystems/engine.pl2
-rw-r--r--contrib/completion/git-completion.bash2
-rw-r--r--contrib/completion/git-completion.zsh1
-rw-r--r--fetch-pack.c14
-rwxr-xr-xgit-add--interactive.perl12
-rw-r--r--git.c2
-rw-r--r--grep.c98
-rw-r--r--grep.h1
-rw-r--r--help.c25
-rw-r--r--imap-send.c52
-rw-r--r--midx.c2
-rw-r--r--packfile.c19
-rw-r--r--refspec.c24
-rw-r--r--remote.c2
-rw-r--r--revision.c1
-rw-r--r--send-pack.c7
-rw-r--r--serve.c18
-rw-r--r--sha1-file.c14
-rwxr-xr-xt/perf/p1400-update-ref.sh20
-rwxr-xr-xt/perf/p7519-fsmonitor.sh3
-rwxr-xr-xt/t1300-config.sh149
-rwxr-xr-xt/t1400-update-ref.sh138
-rwxr-xr-xt/t3701-add-interactive.sh84
-rwxr-xr-xt/t4129-apply-samemode.sh26
-rwxr-xr-xt/t5319-multi-pack-index.sh30
-rwxr-xr-xt/t5511-refspec.sh2
-rwxr-xr-xt/t5516-fetch-push.sh106
-rwxr-xr-xt/t5526-fetch-submodules.sh83
-rwxr-xr-xt/t5616-partial-clone.sh8
-rwxr-xr-xt/t5705-session-id-in-capabilities.sh78
-rwxr-xr-xt/t7900-maintenance.sh30
-rwxr-xr-xt/t9003-help-autocorrect.sh30
-rwxr-xr-xt/t9902-completion.sh4
-rw-r--r--t/test-lib-functions.sh12
-rw-r--r--trace2.c5
-rw-r--r--trace2.h2
-rw-r--r--transport.c10
-rw-r--r--upload-pack.c28
-rw-r--r--usage.c6
73 files changed, 1244 insertions, 471 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/git-config.txt b/Documentation/git-config.txt
index 7573160f21..0e9351d3cb 100644
--- a/Documentation/git-config.txt
+++ b/Documentation/git-config.txt
@@ -9,15 +9,15 @@ git-config - Get and set repository or global options
SYNOPSIS
--------
[verse]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] name [value [value_regex]]
+'git config' [<file-option>] [--type=<type>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] name [value [value-pattern]]
'git config' [<file-option>] [--type=<type>] --add name value
-'git config' [<file-option>] [--type=<type>] --replace-all name value [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] --get-all name [value_regex]
-'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--name-only] --get-regexp name_regex [value_regex]
+'git config' [<file-option>] [--type=<type>] [--fixed-value] --replace-all name value [value-pattern]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get name [value-pattern]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all name [value-pattern]
+'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp name_regex [value-pattern]
'git config' [<file-option>] [--type=<type>] [-z|--null] --get-urlmatch name URL
-'git config' [<file-option>] --unset name [value_regex]
-'git config' [<file-option>] --unset-all name [value_regex]
+'git config' [<file-option>] [--fixed-value] --unset name [value-pattern]
+'git config' [<file-option>] [--fixed-value] --unset-all name [value-pattern]
'git config' [<file-option>] --rename-section old_name new_name
'git config' [<file-option>] --remove-section name
'git config' [<file-option>] [--show-origin] [--show-scope] [-z|--null] [--name-only] -l | --list
@@ -33,10 +33,13 @@ escaped.
Multiple lines can be added to an option by using the `--add` option.
If you want to update or unset an option which can occur on multiple
-lines, a POSIX regexp `value_regex` needs to be given. Only the
-existing values that match the regexp are updated or unset. If
-you want to handle the lines that do *not* match the regex, just
-prepend a single exclamation mark in front (see also <<EXAMPLES>>).
+lines, a `value-pattern` (which is an extended regular expression,
+unless the `--fixed-value` option is given) needs to be given. Only the
+existing values that match the pattern are updated or unset. If
+you want to handle the lines that do *not* match the pattern, just
+prepend a single exclamation mark in front (see also <<EXAMPLES>>),
+but note that this only works when the `--fixed-value` option is not
+in use.
The `--type=<type>` option instructs 'git config' to ensure that incoming and
outgoing values are canonicalize-able under the given <type>. If no
@@ -73,11 +76,11 @@ OPTIONS
--replace-all::
Default behavior is to replace at most one line. This replaces
- all lines matching the key (and optionally the value_regex).
+ all lines matching the key (and optionally the `value-pattern`).
--add::
Adds a new line to the option without altering any existing
- values. This is the same as providing '^$' as the value_regex
+ values. This is the same as providing '^$' as the `value-pattern`
in `--replace-all`.
--get::
@@ -165,6 +168,12 @@ See also <<FILES>>.
--list::
List all variables set in config file, along with their values.
+--fixed-value::
+ When used with the `value-pattern` argument, treat `value-pattern` as
+ an exact string instead of a regular expression. This will restrict
+ the name/value pairs that are matched to only those where the value
+ is exactly equal to the `value-pattern`.
+
--type <type>::
'git config' will ensure that any input or output is valid under the given
type constraint(s), and will canonicalize outgoing values in `<type>`'s
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
index d401234b03..48b6683071 100644
--- a/Documentation/git-update-ref.txt
+++ b/Documentation/git-update-ref.txt
@@ -125,7 +125,8 @@ option::
start::
Start a transaction. In contrast to a non-transactional session, a
transaction will automatically abort if the session ends without an
- explicit commit.
+ explicit commit. This command may create a new empty transaction when
+ the current one has been committed or aborted already.
prepare::
Prepare to commit the transaction. This will create lock files for all
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/api-trace2.txt b/Documentation/technical/api-trace2.txt
index 6b6085585d..c65ffafc48 100644
--- a/Documentation/technical/api-trace2.txt
+++ b/Documentation/technical/api-trace2.txt
@@ -466,7 +466,7 @@ completed.)
`"error"`::
This event is emitted when one of the `error()`, `die()`,
- or `usage()` functions are called.
+ `warning()`, or `usage()` functions are called.
+
------------
{
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='
'
diff --git a/Makefile b/Makefile
index 45bce31016..6fb86c5862 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/add-interactive.c b/add-interactive.c
index a14c0feaa2..9b8cdb4a31 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -12,10 +12,10 @@
#include "prompt.h"
static void init_color(struct repository *r, struct add_i_state *s,
- const char *slot_name, char *dst,
+ const char *section_and_slot, char *dst,
const char *default_color)
{
- char *key = xstrfmt("color.interactive.%s", slot_name);
+ char *key = xstrfmt("color.%s", section_and_slot);
const char *value;
if (!s->use_color)
@@ -40,20 +40,27 @@ void init_add_i_state(struct add_i_state *s, struct repository *r)
git_config_colorbool("color.interactive", value);
s->use_color = want_color(s->use_color);
- init_color(r, s, "header", s->header_color, GIT_COLOR_BOLD);
- init_color(r, s, "help", s->help_color, GIT_COLOR_BOLD_RED);
- init_color(r, s, "prompt", s->prompt_color, GIT_COLOR_BOLD_BLUE);
- init_color(r, s, "error", s->error_color, GIT_COLOR_BOLD_RED);
- init_color(r, s, "reset", s->reset_color, GIT_COLOR_RESET);
- init_color(r, s, "fraginfo", s->fraginfo_color,
+ init_color(r, s, "interactive.header", s->header_color, GIT_COLOR_BOLD);
+ init_color(r, s, "interactive.help", s->help_color, GIT_COLOR_BOLD_RED);
+ init_color(r, s, "interactive.prompt", s->prompt_color,
+ GIT_COLOR_BOLD_BLUE);
+ init_color(r, s, "interactive.error", s->error_color,
+ GIT_COLOR_BOLD_RED);
+
+ init_color(r, s, "diff.frag", s->fraginfo_color,
diff_get_color(s->use_color, DIFF_FRAGINFO));
- init_color(r, s, "context", s->context_color,
- diff_get_color(s->use_color, DIFF_CONTEXT));
- init_color(r, s, "old", s->file_old_color,
+ init_color(r, s, "diff.context", s->context_color, "fall back");
+ if (!strcmp(s->context_color, "fall back"))
+ init_color(r, s, "diff.plain", s->context_color,
+ diff_get_color(s->use_color, DIFF_CONTEXT));
+ init_color(r, s, "diff.old", s->file_old_color,
diff_get_color(s->use_color, DIFF_FILE_OLD));
- init_color(r, s, "new", s->file_new_color,
+ init_color(r, s, "diff.new", s->file_new_color,
diff_get_color(s->use_color, DIFF_FILE_NEW));
+ strlcpy(s->reset_color,
+ s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
+
FREE_AND_NULL(s->interactive_diff_filter);
git_config_get_string("interactive.difffilter",
&s->interactive_diff_filter);
@@ -194,7 +201,8 @@ static ssize_t find_unique(const char *string, struct prefix_item_list *list)
else if (index + 1 < list->sorted.nr &&
starts_with(list->sorted.items[index + 1].string, string))
return -1;
- else if (index < list->sorted.nr)
+ else if (index < list->sorted.nr &&
+ starts_with(list->sorted.items[index].string, string))
item = list->sorted.items[index].util;
else
return -1;
@@ -364,7 +372,7 @@ static ssize_t list_and_choose(struct add_i_state *s,
if (from < 0 || from >= items->items.nr ||
(singleton && from + 1 != to)) {
- color_fprintf_ln(stdout, s->error_color,
+ color_fprintf_ln(stderr, s->error_color,
_("Huh (%s)?"), p);
break;
} else if (singleton) {
@@ -1131,7 +1139,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
print_file_item_data.color = data.color;
print_file_item_data.reset = data.reset;
- strbuf_addstr(&header, " ");
+ strbuf_addstr(&header, " ");
strbuf_addf(&header, print_file_item_data.modified_fmt,
_("staged"), _("unstaged"), _("path"));
opts.list_opts.header = header.buf;
diff --git a/add-patch.c b/add-patch.c
index be4cf6e9e5..2fad92ca37 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -661,13 +661,18 @@ static void render_hunk(struct add_p_state *s, struct hunk *hunk,
else
new_offset += delta;
- strbuf_addf(out, "@@ -%lu,%lu +%lu,%lu @@",
- old_offset, header->old_count,
- new_offset, header->new_count);
+ strbuf_addf(out, "@@ -%lu", old_offset);
+ if (header->old_count != 1)
+ strbuf_addf(out, ",%lu", header->old_count);
+ strbuf_addf(out, " +%lu", new_offset);
+ if (header->new_count != 1)
+ strbuf_addf(out, ",%lu", header->new_count);
+ strbuf_addstr(out, " @@");
+
if (len)
strbuf_add(out, p, len);
else if (colored)
- strbuf_addf(out, "%s\n", GIT_COLOR_RESET);
+ strbuf_addf(out, "%s\n", s->s.reset_color);
else
strbuf_addch(out, '\n');
}
@@ -1060,7 +1065,7 @@ static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
s->s.file_new_color :
s->s.context_color);
strbuf_add(&s->colored, plain + current, eol - current);
- strbuf_addstr(&s->colored, GIT_COLOR_RESET);
+ strbuf_addstr(&s->colored, s->s.reset_color);
if (next > eol)
strbuf_add(&s->colored, plain + eol, next - eol);
current = next;
@@ -1456,15 +1461,15 @@ static int patch_update_file(struct add_p_state *s,
else
prompt_mode_type = PROMPT_HUNK;
- color_fprintf(stdout, s->s.prompt_color,
- "(%"PRIuMAX"/%"PRIuMAX") ",
+ printf("%s(%"PRIuMAX"/%"PRIuMAX") ", s->s.prompt_color,
(uintmax_t)hunk_index + 1,
(uintmax_t)(file_diff->hunk_nr
? file_diff->hunk_nr
: 1));
- color_fprintf(stdout, s->s.prompt_color,
- _(s->mode->prompt_mode[prompt_mode_type]),
- s->buf.buf);
+ printf(_(s->mode->prompt_mode[prompt_mode_type]),
+ s->buf.buf);
+ if (*s->s.reset_color)
+ fputs(s->s.reset_color, stdout);
fflush(stdout);
if (read_single_character(s) == EOF)
break;
diff --git a/apply.c b/apply.c
index 359ceb632c..4a4e9a0158 100644
--- a/apply.c
+++ b/apply.c
@@ -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)
diff --git a/banned.h b/banned.h
index 60a18d4403..7ab4f2e492 100644
--- a/banned.h
+++ b/banned.h
@@ -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/branch.c b/builtin/branch.c
index efb30b8820..173b736dff 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -829,10 +829,10 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
die(_("Branch '%s' has no upstream information"), branch->name);
strbuf_addf(&buf, "branch.%s.remote", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_reset(&buf);
strbuf_addf(&buf, "branch.%s.merge", branch->name);
- git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_release(&buf);
} else if (argc > 0 && argc <= 2) {
if (filter.kind != FILTER_REFS_BRANCHES)
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/config.c b/builtin/config.c
index 963d65fd3f..f71fa39b38 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -14,6 +14,7 @@ static const char *const builtin_config_usage[] = {
static char *key;
static regex_t *key_regexp;
+static const char *value_pattern;
static regex_t *regexp;
static int show_keys;
static int omit_values;
@@ -34,6 +35,7 @@ static int respect_includes_opt = -1;
static struct config_options config_options;
static int show_origin;
static int show_scope;
+static int fixed_value;
#define ACTION_GET (1<<0)
#define ACTION_GET_ALL (1<<1)
@@ -133,17 +135,18 @@ static struct option builtin_config_options[] = {
OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
OPT_GROUP(N_("Action")),
- OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
- OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-regex]"), ACTION_GET_ALL),
- OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-regex]"), ACTION_GET_REGEXP),
+ OPT_BIT(0, "get", &actions, N_("get value: name [value-pattern]"), ACTION_GET),
+ OPT_BIT(0, "get-all", &actions, N_("get all values: key [value-pattern]"), ACTION_GET_ALL),
+ OPT_BIT(0, "get-regexp", &actions, N_("get values for regexp: name-regex [value-pattern]"), ACTION_GET_REGEXP),
OPT_BIT(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
- OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value_regex]"), ACTION_REPLACE_ALL),
+ OPT_BIT(0, "replace-all", &actions, N_("replace all matching variables: name value [value-pattern]"), ACTION_REPLACE_ALL),
OPT_BIT(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
- OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-regex]"), ACTION_UNSET),
- OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
+ OPT_BIT(0, "unset", &actions, N_("remove a variable: name [value-pattern]"), ACTION_UNSET),
+ OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-pattern]"), ACTION_UNSET_ALL),
OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
+ OPT_BOOL(0, "fixed-value", &fixed_value, N_("use string equality when comparing values to 'value-pattern'")),
OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
OPT_BIT(0, "get-colorbool", &actions, N_("find the color setting: slot [stdout-is-tty]"), ACTION_GET_COLORBOOL),
@@ -296,6 +299,8 @@ static int collect_config(const char *key_, const char *value_, void *cb)
return 0;
if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
return 0;
+ if (fixed_value && strcmp(value_pattern, (value_?value_:"")))
+ return 0;
if (regexp != NULL &&
(do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
return 0;
@@ -306,7 +311,7 @@ static int collect_config(const char *key_, const char *value_, void *cb)
return format_config(&values->items[values->nr++], key_, value_);
}
-static int get_value(const char *key_, const char *regex_)
+static int get_value(const char *key_, const char *regex_, unsigned flags)
{
int ret = CONFIG_GENERIC_ERROR;
struct strbuf_list values = {NULL};
@@ -343,7 +348,9 @@ static int get_value(const char *key_, const char *regex_)
}
}
- if (regex_) {
+ if (regex_ && (flags & CONFIG_FLAGS_FIXED_VALUE))
+ value_pattern = regex_;
+ else if (regex_) {
if (regex_[0] == '!') {
do_not_match = 1;
regex_++;
@@ -631,6 +638,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
char *value;
+ int flags = 0;
given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
@@ -766,6 +774,42 @@ int cmd_config(int argc, const char **argv, const char *prefix)
usage_builtin_config();
}
+ /* check usage of --fixed-value */
+ if (fixed_value) {
+ int allowed_usage = 0;
+
+ switch (actions) {
+ /* git config --get <name> <value-pattern> */
+ case ACTION_GET:
+ /* git config --get-all <name> <value-pattern> */
+ case ACTION_GET_ALL:
+ /* git config --get-regexp <name-pattern> <value-pattern> */
+ case ACTION_GET_REGEXP:
+ /* git config --unset <name> <value-pattern> */
+ case ACTION_UNSET:
+ /* git config --unset-all <name> <value-pattern> */
+ case ACTION_UNSET_ALL:
+ allowed_usage = argc > 1 && !!argv[1];
+ break;
+
+ /* git config <name> <value> <value-pattern> */
+ case ACTION_SET_ALL:
+ /* git config --replace-all <name> <value> <value-pattern> */
+ case ACTION_REPLACE_ALL:
+ allowed_usage = argc > 2 && !!argv[2];
+ break;
+
+ /* other options don't allow --fixed-value */
+ }
+
+ if (!allowed_usage) {
+ error(_("--fixed-value only applies with 'value-pattern'"));
+ usage_builtin_config();
+ }
+
+ flags |= CONFIG_FLAGS_FIXED_VALUE;
+ }
+
if (actions & PAGING_ACTIONS)
setup_auto_pager("config", 1);
@@ -827,7 +871,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
value = normalize_value(argv[0], argv[1]);
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2], 0);
+ argv[0], value, argv[2],
+ flags);
}
else if (actions == ACTION_ADD) {
check_write();
@@ -836,7 +881,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
argv[0], value,
- CONFIG_REGEX_NONE, 0);
+ CONFIG_REGEX_NONE,
+ flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
@@ -844,23 +890,24 @@ int cmd_config(int argc, const char **argv, const char *prefix)
value = normalize_value(argv[0], argv[1]);
UNLEAK(value);
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2], 1);
+ argv[0], value, argv[2],
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1]);
+ return get_value(argv[0], argv[1], flags);
}
else if (actions == ACTION_GET_ALL) {
do_all = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1]);
+ return get_value(argv[0], argv[1], flags);
}
else if (actions == ACTION_GET_REGEXP) {
show_keys = 1;
use_key_regexp = 1;
do_all = 1;
check_argc(argc, 1, 2);
- return get_value(argv[0], argv[1]);
+ return get_value(argv[0], argv[1], flags);
}
else if (actions == ACTION_GET_URLMATCH) {
check_argc(argc, 2, 2);
@@ -871,7 +918,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_argc(argc, 1, 2);
if (argc == 2)
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1], 0);
+ argv[0], NULL, argv[1],
+ flags);
else
return git_config_set_in_file_gently(given_config_source.file,
argv[0], NULL);
@@ -880,7 +928,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
check_write();
check_argc(argc, 1, 2);
return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], NULL, argv[1], 1);
+ argv[0], NULL, argv[1],
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
int ret;
diff --git a/builtin/gc.c b/builtin/gc.c
index 3e8d76fd5a..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");
@@ -1460,7 +1456,8 @@ static int maintenance_register(void)
git_config_set("maintenance.strategy", "incremental");
config_get.git_cmd = 1;
- strvec_pushl(&config_get.args, "config", "--global", "--get", "maintenance.repo",
+ strvec_pushl(&config_get.args, "config", "--global", "--get",
+ "--fixed-value", "maintenance.repo",
the_repository->worktree ? the_repository->worktree
: the_repository->gitdir,
NULL);
@@ -1486,12 +1483,9 @@ 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",
- "maintenance.repo",
+ "--fixed-value", "maintenance.repo",
the_repository->worktree ? the_repository->worktree
: the_repository->gitdir,
NULL);
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")) {
diff --git a/builtin/remote.c b/builtin/remote.c
index c1b211b272..d11a5589e4 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -712,7 +712,7 @@ static int mv(int argc, const char **argv)
strbuf_reset(&buf);
strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
- git_config_set_multivar(buf.buf, NULL, NULL, 1);
+ git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
for (i = 0; i < oldremote->fetch.raw_nr; i++) {
char *ptr;
@@ -1491,7 +1491,8 @@ static int update(int argc, const char **argv)
static int remove_all_fetch_refspecs(const char *key)
{
- return git_config_set_multivar_gently(key, NULL, NULL, 1);
+ return git_config_set_multivar_gently(key, NULL, NULL,
+ CONFIG_FLAGS_MULTI_REPLACE);
}
static void add_branches(struct remote *remote, const char **branches,
@@ -1686,7 +1687,8 @@ static int set_url(int argc, const char **argv)
if (!delete_mode)
git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
else
- git_config_set_multivar(name_buf.buf, NULL, oldurl, 1);
+ git_config_set_multivar(name_buf.buf, NULL, oldurl,
+ CONFIG_FLAGS_MULTI_REPLACE);
out:
strbuf_release(&name_buf);
return 0;
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
index 8a2df4459c..6029a80544 100644
--- a/builtin/update-ref.c
+++ b/builtin/update-ref.c
@@ -436,6 +436,8 @@ static void update_refs_stdin(void)
switch (state) {
case UPDATE_REFS_OPEN:
case UPDATE_REFS_STARTED:
+ if (state == UPDATE_REFS_STARTED && cmd->state == UPDATE_REFS_STARTED)
+ die("cannot restart ongoing transaction");
/* Do not downgrade a transaction to a non-transaction. */
if (cmd->state >= state)
state = cmd->state;
@@ -446,7 +448,18 @@ static void update_refs_stdin(void)
state = cmd->state;
break;
case UPDATE_REFS_CLOSED:
- die("transaction is closed");
+ if (cmd->state != UPDATE_REFS_STARTED)
+ die("transaction is closed");
+
+ /*
+ * Open a new transaction if we're currently closed and
+ * get a "start".
+ */
+ state = cmd->state;
+ transaction = ref_transaction_begin(&err);
+ if (!transaction)
+ die("%s", err.buf);
+
break;
}
diff --git a/cache.h b/cache.h
index e986cf4ea9..8d279bc110 100644
--- a/cache.h
+++ b/cache.h
@@ -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/config.c b/config.c
index 8f324ed3a6..1137bd73af 100644
--- a/config.c
+++ b/config.c
@@ -2415,7 +2415,8 @@ struct config_store_data {
size_t baselen;
char *key;
int do_not_match;
- regex_t *value_regex;
+ const char *fixed_value;
+ regex_t *value_pattern;
int multi_replace;
struct {
size_t begin, end;
@@ -2429,10 +2430,10 @@ struct config_store_data {
static void config_store_data_clear(struct config_store_data *store)
{
free(store->key);
- if (store->value_regex != NULL &&
- store->value_regex != CONFIG_REGEX_NONE) {
- regfree(store->value_regex);
- free(store->value_regex);
+ if (store->value_pattern != NULL &&
+ store->value_pattern != CONFIG_REGEX_NONE) {
+ regfree(store->value_pattern);
+ free(store->value_pattern);
}
free(store->parsed);
free(store->seen);
@@ -2444,13 +2445,15 @@ static int matches(const char *key, const char *value,
{
if (strcmp(key, store->key))
return 0; /* not ours */
- if (!store->value_regex)
+ if (store->fixed_value)
+ return !strcmp(store->fixed_value, value);
+ if (!store->value_pattern)
return 1; /* always matches */
- if (store->value_regex == CONFIG_REGEX_NONE)
+ if (store->value_pattern == CONFIG_REGEX_NONE)
return 0; /* never matches */
return store->do_not_match ^
- (value && !regexec(store->value_regex, value, 0, NULL, 0));
+ (value && !regexec(store->value_pattern, value, 0, NULL, 0));
}
static int store_aux_event(enum config_event_t type,
@@ -2726,12 +2729,12 @@ void git_config_set(const char *key, const char *value)
/*
* If value==NULL, unset in (remove from) config,
- * if value_regex!=NULL, disregard key/value pairs where value does not match.
- * if value_regex==CONFIG_REGEX_NONE, do not match any existing values
+ * if value_pattern!=NULL, disregard key/value pairs where value does not match.
+ * if value_pattern==CONFIG_REGEX_NONE, do not match any existing values
* (only add a new one)
- * if multi_replace==0, nothing, or only one matching key/value is replaced,
- * else all matching key/values (regardless how many) are removed,
- * before the new pair is written.
+ * if flags contains the CONFIG_FLAGS_MULTI_REPLACE flag, all matching
+ * key/values are removed before a single new pair is written. If the
+ * flag is not present, then replace only the first match.
*
* Returns 0 on success.
*
@@ -2751,8 +2754,8 @@ void git_config_set(const char *key, const char *value)
*/
int git_config_set_multivar_in_file_gently(const char *config_filename,
const char *key, const char *value,
- const char *value_regex,
- int multi_replace)
+ const char *value_pattern,
+ unsigned flags)
{
int fd = -1, in_fd = -1;
int ret;
@@ -2769,7 +2772,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
if (ret)
goto out_free;
- store.multi_replace = multi_replace;
+ store.multi_replace = (flags & CONFIG_FLAGS_MULTI_REPLACE) != 0;
if (!config_filename)
config_filename = filename_buf = git_pathdup("config");
@@ -2812,22 +2815,24 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
int i, new_line = 0;
struct config_options opts;
- if (value_regex == NULL)
- store.value_regex = NULL;
- else if (value_regex == CONFIG_REGEX_NONE)
- store.value_regex = CONFIG_REGEX_NONE;
+ if (value_pattern == NULL)
+ store.value_pattern = NULL;
+ else if (value_pattern == CONFIG_REGEX_NONE)
+ store.value_pattern = CONFIG_REGEX_NONE;
+ else if (flags & CONFIG_FLAGS_FIXED_VALUE)
+ store.fixed_value = value_pattern;
else {
- if (value_regex[0] == '!') {
+ if (value_pattern[0] == '!') {
store.do_not_match = 1;
- value_regex++;
+ value_pattern++;
} else
store.do_not_match = 0;
- store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
- if (regcomp(store.value_regex, value_regex,
+ store.value_pattern = (regex_t*)xmalloc(sizeof(regex_t));
+ if (regcomp(store.value_pattern, value_pattern,
REG_EXTENDED)) {
- error(_("invalid pattern: %s"), value_regex);
- FREE_AND_NULL(store.value_regex);
+ error(_("invalid pattern: %s"), value_pattern);
+ FREE_AND_NULL(store.value_pattern);
ret = CONFIG_INVALID_PATTERN;
goto out_free;
}
@@ -2858,7 +2863,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
/* if nothing to unset, or too many matches, error out */
if ((store.seen_nr == 0 && value == NULL) ||
- (store.seen_nr > 1 && multi_replace == 0)) {
+ (store.seen_nr > 1 && !store.multi_replace)) {
ret = CONFIG_NOTHING_SET;
goto out_free;
}
@@ -2997,10 +3002,10 @@ write_err_out:
void git_config_set_multivar_in_file(const char *config_filename,
const char *key, const char *value,
- const char *value_regex, int multi_replace)
+ const char *value_pattern, unsigned flags)
{
if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
- value_regex, multi_replace))
+ value_pattern, flags))
return;
if (value)
die(_("could not set '%s' to '%s'"), key, value);
@@ -3009,17 +3014,17 @@ void git_config_set_multivar_in_file(const char *config_filename,
}
int git_config_set_multivar_gently(const char *key, const char *value,
- const char *value_regex, int multi_replace)
+ const char *value_pattern, unsigned flags)
{
- return git_config_set_multivar_in_file_gently(NULL, key, value, value_regex,
- multi_replace);
+ return git_config_set_multivar_in_file_gently(NULL, key, value, value_pattern,
+ flags);
}
void git_config_set_multivar(const char *key, const char *value,
- const char *value_regex, int multi_replace)
+ const char *value_pattern, unsigned flags)
{
- git_config_set_multivar_in_file(NULL, key, value, value_regex,
- multi_replace);
+ git_config_set_multivar_in_file(NULL, key, value, value_pattern,
+ flags);
}
static int section_name_match (const char *buf, const char *name)
diff --git a/config.h b/config.h
index 91cdfbfb41..c1449bb790 100644
--- a/config.h
+++ b/config.h
@@ -256,9 +256,29 @@ void git_config_set(const char *, const char *);
int git_config_parse_key(const char *, char **, size_t *);
int git_config_key_is_valid(const char *key);
-int git_config_set_multivar_gently(const char *, const char *, const char *, int);
-void git_config_set_multivar(const char *, const char *, const char *, int);
-int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
+
+/*
+ * The following macros specify flag bits that alter the behavior
+ * of the git_config_set_multivar*() methods.
+ */
+
+/*
+ * When CONFIG_FLAGS_MULTI_REPLACE is specified, all matching key/values
+ * are removed before a single new pair is written. If the flag is not
+ * present, then set operations replace only the first match.
+ */
+#define CONFIG_FLAGS_MULTI_REPLACE (1 << 0)
+
+/*
+ * When CONFIG_FLAGS_FIXED_VALUE is specified, match key/value pairs
+ * by string comparison (not regex match) to the provided value_pattern
+ * parameter.
+ */
+#define CONFIG_FLAGS_FIXED_VALUE (1 << 1)
+
+int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
+void git_config_set_multivar(const char *, const char *, const char *, unsigned);
+int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, unsigned);
/**
* takes four parameters:
@@ -276,13 +296,15 @@ int git_config_set_multivar_in_file_gently(const char *, const char *, const cha
* - the value regex, as a string. It will disregard key/value pairs where value
* does not match.
*
- * - a multi_replace value, as an int. If value is equal to zero, nothing or only
- * one matching key/value is replaced, else all matching key/values (regardless
- * how many) are removed, before the new pair is written.
+ * - a flags value with bits corresponding to the CONFIG_FLAG_* macros.
*
* It returns 0 on success.
*/
-void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
+void git_config_set_multivar_in_file(const char *config_filename,
+ const char *key,
+ const char *value,
+ const char *value_pattern,
+ unsigned flags);
/**
* rename or remove sections in the config file
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;
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
index e713fe3d02..bc3a1e8eff 100755
--- a/git-add--interactive.perl
+++ b/git-add--interactive.perl
@@ -30,9 +30,9 @@ my ($fraginfo_color) =
$diff_use_color ? (
$repo->get_color('color.diff.frag', 'cyan'),
) : ();
-my ($diff_plain_color) =
+my ($diff_context_color) =
$diff_use_color ? (
- $repo->get_color('color.diff.plain', ''),
+ $repo->get_color($repo->config('color.diff.context') ? 'color.diff.context' : 'color.diff.plain', ''),
) : ();
my ($diff_old_color) =
$diff_use_color ? (
@@ -483,10 +483,8 @@ sub list_and_choose {
my $last_lf = 0;
if ($opts->{HEADER}) {
- if (!$opts->{LIST_FLAT}) {
- print " ";
- }
- print colored $header_color, "$opts->{HEADER}\n";
+ my $indent = $opts->{LIST_FLAT} ? "" : " ";
+ print colored $header_color, "$indent$opts->{HEADER}\n";
}
for ($i = 0; $i < @stuff; $i++) {
my $chosen = $chosen[$i] ? '*' : ' ';
@@ -1048,7 +1046,7 @@ sub color_diff {
colored((/^@/ ? $fraginfo_color :
/^\+/ ? $diff_new_color :
/^-/ ? $diff_old_color :
- $diff_plain_color),
+ $diff_context_color),
$_);
} @_;
}
diff --git a/git.c b/git.c
index 4b7bd77b80..a00a0a4d94 100644
--- a/git.c
+++ b/git.c
@@ -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 },
diff --git a/grep.c b/grep.c
index 54af9f813e..efeb6dc58d 100644
--- a/grep.c
+++ b/grep.c
@@ -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)
diff --git a/grep.h b/grep.h
index 9115db8515..b5c4e223a8 100644
--- a/grep.h
+++ b/grep.h
@@ -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);
diff --git a/help.c b/help.c
index 919cbb9206..3c3bdec213 100644
--- a/help.c
+++ b/help.c
@@ -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);
diff --git a/midx.c b/midx.c
index da03c1449a..79c282b070 100644
--- a/midx.c
+++ b/midx.c
@@ -298,7 +298,7 @@ static int nth_midxed_pack_entry(struct repository *r,
pack_int_id = nth_midxed_pack_int_id(m, pos);
if (prepare_midx_pack(r, m, pack_int_id))
- die(_("error preparing packfile from multi-pack-index"));
+ return 0;
p = m->packs[pack_int_id];
/*
diff --git a/packfile.c b/packfile.c
index 9702b1218b..86f5c8dbf6 100644
--- a/packfile.c
+++ b/packfile.c
@@ -514,19 +514,8 @@ static int open_packed_git_1(struct packed_git *p)
ssize_t read_result;
const unsigned hashsz = the_hash_algo->rawsz;
- if (!p->index_data) {
- struct multi_pack_index *m;
- const char *pack_name = pack_basename(p);
-
- for (m = the_repository->objects->multi_pack_index;
- m; m = m->next) {
- if (midx_contains_pack(m, pack_name))
- break;
- }
-
- if (!m && open_pack_index(p))
- return error("packfile %s index unavailable", p->pack_name);
- }
+ if (open_pack_index(p))
+ return error("packfile %s index unavailable", p->pack_name);
if (!pack_max_fds) {
unsigned int max_fds = get_max_fd_limit();
@@ -567,10 +556,6 @@ static int open_packed_git_1(struct packed_git *p)
" supported (try upgrading GIT to a newer version)",
p->pack_name, ntohl(hdr.hdr_version));
- /* Skip index checking if in multi-pack-index */
- if (!p->index_data)
- return 0;
-
/* Verify the pack matches its index. */
if (p->num_objects != ntohl(hdr.hdr_entries))
return error("packfile %s claims to have %"PRIu32" objects"
diff --git a/refspec.c b/refspec.c
index c49347c2d7..e3d852c0bf 100644
--- a/refspec.c
+++ b/refspec.c
@@ -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);
}
}
}
diff --git a/remote.c b/remote.c
index 8a6dbbb903..8b9d090ae5 100644
--- a/remote.c
+++ b/remote.c
@@ -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
diff --git a/serve.c b/serve.c
index f6341206c4..eec2fe6f29 100644
--- a/serve.c
+++ b/serve.c
@@ -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/p1400-update-ref.sh b/t/perf/p1400-update-ref.sh
index ce5ac3ed85..dda8a74866 100755
--- a/t/perf/p1400-update-ref.sh
+++ b/t/perf/p1400-update-ref.sh
@@ -7,13 +7,14 @@ test_description="Tests performance of update-ref"
test_perf_fresh_repo
test_expect_success "setup" '
- git init --bare target-repo.git &&
test_commit PRE &&
test_commit POST &&
- printf "create refs/heads/%d PRE\n" $(test_seq 1000) >create &&
- printf "update refs/heads/%d POST PRE\n" $(test_seq 1000) >update &&
- printf "delete refs/heads/%d POST\n" $(test_seq 1000) >delete &&
- git update-ref --stdin <create
+ for i in $(test_seq 5000)
+ do
+ printf "start\ncreate refs/heads/%d PRE\ncommit\n" $i &&
+ printf "start\nupdate refs/heads/%d POST PRE\ncommit\n" $i &&
+ printf "start\ndelete refs/heads/%d POST\ncommit\n" $i
+ done >instructions
'
test_perf "update-ref" '
@@ -26,14 +27,7 @@ test_perf "update-ref" '
'
test_perf "update-ref --stdin" '
- git update-ref --stdin <update &&
- git update-ref --stdin <delete &&
- git update-ref --stdin <create
-'
-
-test_perf "nonatomic push" '
- git push ./target-repo.git $(test_seq 1000) &&
- git push --delete ./target-repo.git $(test_seq 1000)
+ git update-ref --stdin <instructions >/dev/null
'
test_done
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/t1300-config.sh b/t/t1300-config.sh
index 825d9a184f..97a04c6cc2 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -1917,4 +1917,153 @@ test_expect_success '--replace-all does not invent newlines' '
test_cmp expect .git/config
'
+test_expect_success 'set all config with value-pattern' '
+ test_when_finished rm -f config initial &&
+ git config --file=initial abc.key one &&
+
+ # no match => add new entry
+ cp initial config &&
+ git config --file=config abc.key two a+ &&
+ git config --file=config --list >actual &&
+ cat >expect <<-\EOF &&
+ abc.key=one
+ abc.key=two
+ EOF
+ test_cmp expect actual &&
+
+ # multiple matches => failure
+ test_must_fail git config --file=config abc.key three o+ 2>err &&
+ test_i18ngrep "has multiple values" err &&
+
+ # multiple values, no match => add
+ git config --file=config abc.key three a+ &&
+ git config --file=config --list >actual &&
+ cat >expect <<-\EOF &&
+ abc.key=one
+ abc.key=two
+ abc.key=three
+ EOF
+ test_cmp expect actual &&
+
+ # single match => replace
+ git config --file=config abc.key four h+ &&
+ git config --file=config --list >actual &&
+ cat >expect <<-\EOF &&
+ abc.key=one
+ abc.key=two
+ abc.key=four
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '--replace-all and value-pattern' '
+ test_when_finished rm -f config &&
+ git config --file=config --add abc.key one &&
+ git config --file=config --add abc.key two &&
+ git config --file=config --add abc.key three &&
+ git config --file=config --replace-all abc.key four "o+" &&
+ git config --file=config --list >actual &&
+ cat >expect <<-\EOF &&
+ abc.key=four
+ abc.key=three
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'refuse --fixed-value for incompatible actions' '
+ test_when_finished rm -f config &&
+ git config --file=config dev.null bogus &&
+
+ # These modes do not allow --fixed-value at all
+ test_must_fail git config --file=config --fixed-value --add dev.null bogus &&
+ test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
+ test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
+ test_must_fail git config --file=config --fixed-value --rename-section dev null &&
+ test_must_fail git config --file=config --fixed-value --remove-section dev &&
+ test_must_fail git config --file=config --fixed-value --list &&
+ test_must_fail git config --file=config --fixed-value --get-color dev.null &&
+ test_must_fail git config --file=config --fixed-value --get-colorbool dev.null &&
+
+ # These modes complain when --fixed-value has no value-pattern
+ test_must_fail git config --file=config --fixed-value dev.null bogus &&
+ test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus &&
+ test_must_fail git config --file=config --fixed-value --get dev.null &&
+ test_must_fail git config --file=config --fixed-value --get-all dev.null &&
+ test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" &&
+ test_must_fail git config --file=config --fixed-value --unset dev.null &&
+ test_must_fail git config --file=config --fixed-value --unset-all dev.null
+'
+
+test_expect_success '--fixed-value uses exact string matching' '
+ test_when_finished rm -f config initial &&
+ META="a+b*c?d[e]f.g" &&
+ git config --file=initial fixed.test "$META" &&
+
+ cp initial config &&
+ git config --file=config fixed.test bogus "$META" &&
+ git config --file=config --list >actual &&
+ cat >expect <<-EOF &&
+ fixed.test=$META
+ fixed.test=bogus
+ EOF
+ test_cmp expect actual &&
+
+ cp initial config &&
+ git config --file=config --fixed-value fixed.test bogus "$META" &&
+ git config --file=config --list >actual &&
+ cat >expect <<-\EOF &&
+ fixed.test=bogus
+ EOF
+ test_cmp expect actual &&
+
+ cp initial config &&
+ test_must_fail git config --file=config --unset fixed.test "$META" &&
+ git config --file=config --fixed-value --unset fixed.test "$META" &&
+ test_must_fail git config --file=config fixed.test &&
+
+ cp initial config &&
+ test_must_fail git config --file=config --unset-all fixed.test "$META" &&
+ git config --file=config --fixed-value --unset-all fixed.test "$META" &&
+ test_must_fail git config --file=config fixed.test &&
+
+ cp initial config &&
+ git config --file=config --replace-all fixed.test bogus "$META" &&
+ git config --file=config --list >actual &&
+ cat >expect <<-EOF &&
+ fixed.test=$META
+ fixed.test=bogus
+ EOF
+ test_cmp expect actual &&
+
+ git config --file=config --fixed-value --replace-all fixed.test bogus "$META" &&
+ git config --file=config --list >actual &&
+ cat >expect <<-EOF &&
+ fixed.test=bogus
+ fixed.test=bogus
+ EOF
+ test_cmp expect actual
+'
+
+test_expect_success '--get and --get-all with --fixed-value' '
+ test_when_finished rm -f config &&
+ META="a+b*c?d[e]f.g" &&
+ git config --file=config fixed.test bogus &&
+ git config --file=config --add fixed.test "$META" &&
+
+ git config --file=config --get fixed.test bogus &&
+ test_must_fail git config --file=config --get fixed.test "$META" &&
+ git config --file=config --get --fixed-value fixed.test "$META" &&
+ test_must_fail git config --file=config --get --fixed-value fixed.test non-existent &&
+
+ git config --file=config --get-all fixed.test bogus &&
+ test_must_fail git config --file=config --get-all fixed.test "$META" &&
+ git config --file=config --get-all --fixed-value fixed.test "$META" &&
+ test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent &&
+
+ git config --file=config --get-regexp fixed+ bogus &&
+ test_must_fail git config --file=config --get-regexp fixed+ "$META" &&
+ git config --file=config --get-regexp --fixed-value fixed+ "$META" &&
+ test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent
+'
+
test_done
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 4c01e08551..31b64be521 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -48,17 +48,17 @@ test_expect_success "fail to delete $m with stale ref" '
test $B = "$(git show-ref -s --verify $m)"
'
test_expect_success "delete $m" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref -d $m $B &&
- test_path_is_missing .git/$m
+ test_must_fail git show-ref --verify -q $m
'
test_expect_success "delete $m without oldvalue verification" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref $m $A &&
test $A = $(git show-ref -s --verify $m) &&
git update-ref -d $m &&
- test_path_is_missing .git/$m
+ test_must_fail git show-ref --verify -q $m
'
test_expect_success "fail to create $n" '
@@ -80,26 +80,26 @@ test_expect_success "fail to delete $m (by HEAD) with stale ref" '
test $B = $(git show-ref -s --verify $m)
'
test_expect_success "delete $m (by HEAD)" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref -d HEAD $B &&
- test_path_is_missing .git/$m
+ test_must_fail git show-ref --verify -q $m
'
test_expect_success "deleting current branch adds message to HEAD's log" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref $m $A &&
git symbolic-ref HEAD $m &&
git update-ref -m delete-$m -d $m &&
- test_path_is_missing .git/$m &&
+ test_must_fail git show-ref --verify -q $m &&
grep "delete-$m$" .git/logs/HEAD
'
test_expect_success "deleting by HEAD adds message to HEAD's log" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref $m $A &&
git symbolic-ref HEAD $m &&
git update-ref -m delete-by-head -d HEAD &&
- test_path_is_missing .git/$m &&
+ test_must_fail git show-ref --verify -q $m &&
grep "delete-by-head$" .git/logs/HEAD
'
@@ -188,31 +188,37 @@ test_expect_success "move $m (by HEAD)" '
test $B = $(git show-ref -s --verify $m)
'
test_expect_success "delete $m (by HEAD) should remove both packed and loose $m" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
git update-ref -d HEAD $B &&
! grep "$m" .git/packed-refs &&
- test_path_is_missing .git/$m
+ test_must_fail git show-ref --verify -q $m
'
-cp -f .git/HEAD .git/HEAD.orig
test_expect_success 'delete symref without dereference' '
- test_when_finished "cp -f .git/HEAD.orig .git/HEAD" &&
- git update-ref --no-deref -d HEAD &&
- test_path_is_missing .git/HEAD
+ test_when_finished "git update-ref -d $m" &&
+ echo foo >foo.c &&
+ git add foo.c &&
+ git commit -m foo &&
+ git symbolic-ref SYMREF $m &&
+ git update-ref --no-deref -d SYMREF &&
+ git show-ref --verify -q $m &&
+ test_must_fail git show-ref --verify -q SYMREF &&
+ test_must_fail git symbolic-ref SYMREF
'
test_expect_success 'delete symref without dereference when the referred ref is packed' '
- test_when_finished "cp -f .git/HEAD.orig .git/HEAD" &&
+ test_when_finished "git update-ref -d $m" &&
echo foo >foo.c &&
git add foo.c &&
git commit -m foo &&
+ git symbolic-ref SYMREF $m &&
git pack-refs --all &&
- git update-ref --no-deref -d HEAD &&
- test_path_is_missing .git/HEAD
+ git update-ref --no-deref -d SYMREF &&
+ git show-ref --verify -q $m &&
+ test_must_fail git show-ref --verify -q SYMREF &&
+ test_must_fail git symbolic-ref SYMREF
'
-git update-ref -d $m
-
test_expect_success 'update-ref -d is not confused by self-reference' '
git symbolic-ref refs/heads/self refs/heads/self &&
test_when_finished "rm -f .git/refs/heads/self" &&
@@ -226,25 +232,25 @@ test_expect_success 'update-ref --no-deref -d can delete self-reference' '
test_when_finished "rm -f .git/refs/heads/self" &&
test_path_is_file .git/refs/heads/self &&
git update-ref --no-deref -d refs/heads/self &&
- test_path_is_missing .git/refs/heads/self
+ test_must_fail git show-ref --verify -q refs/heads/self
'
test_expect_success 'update-ref --no-deref -d can delete reference to bad ref' '
>.git/refs/heads/bad &&
test_when_finished "rm -f .git/refs/heads/bad" &&
git symbolic-ref refs/heads/ref-to-bad refs/heads/bad &&
- test_when_finished "rm -f .git/refs/heads/ref-to-bad" &&
+ test_when_finished "git update-ref -d refs/heads/ref-to-bad" &&
test_path_is_file .git/refs/heads/ref-to-bad &&
git update-ref --no-deref -d refs/heads/ref-to-bad &&
- test_path_is_missing .git/refs/heads/ref-to-bad
+ test_must_fail git show-ref --verify -q refs/heads/ref-to-bad
'
test_expect_success '(not) create HEAD with old sha1' '
test_must_fail git update-ref HEAD $A $B
'
test_expect_success "(not) prior created .git/$m" '
- test_when_finished "rm -f .git/$m" &&
- test_path_is_missing .git/$m
+ test_when_finished "git update-ref -d $m" &&
+ test_must_fail git show-ref --verify -q $m
'
test_expect_success 'create HEAD' '
@@ -254,7 +260,7 @@ test_expect_success '(not) change HEAD with wrong SHA1' '
test_must_fail git update-ref HEAD $B $Z
'
test_expect_success "(not) changed .git/$m" '
- test_when_finished "rm -f .git/$m" &&
+ test_when_finished "git update-ref -d $m" &&
! test $B = $(git show-ref -s --verify $m)
'
@@ -284,8 +290,8 @@ test_expect_success 'empty directory removal' '
test_path_is_file .git/refs/heads/d1/d2/r1 &&
test_path_is_file .git/logs/refs/heads/d1/d2/r1 &&
git branch -d d1/d2/r1 &&
- test_path_is_missing .git/refs/heads/d1/d2 &&
- test_path_is_missing .git/logs/refs/heads/d1/d2 &&
+ test_must_fail git show-ref --verify -q refs/heads/d1/d2 &&
+ test_must_fail git show-ref --verify -q logs/refs/heads/d1/d2 &&
test_path_is_file .git/refs/heads/d1/r2 &&
test_path_is_file .git/logs/refs/heads/d1/r2
'
@@ -298,8 +304,8 @@ test_expect_success 'symref empty directory removal' '
test_path_is_file .git/refs/heads/e1/e2/r1 &&
test_path_is_file .git/logs/refs/heads/e1/e2/r1 &&
git update-ref -d HEAD &&
- test_path_is_missing .git/refs/heads/e1/e2 &&
- test_path_is_missing .git/logs/refs/heads/e1/e2 &&
+ test_must_fail git show-ref --verify -q refs/heads/e1/e2 &&
+ test_must_fail git show-ref --verify -q logs/refs/heads/e1/e2 &&
test_path_is_file .git/refs/heads/e1/r2 &&
test_path_is_file .git/logs/refs/heads/e1/r2 &&
test_path_is_file .git/logs/HEAD
@@ -1388,7 +1394,8 @@ test_expect_success 'handle per-worktree refs in refs/bisect' '
git rev-parse refs/bisect/something >../worktree-head &&
git for-each-ref | grep refs/bisect/something
) &&
- test_path_is_missing .git/refs/bisect &&
+ git show-ref >actual &&
+ ! grep 'refs/bisect' actual &&
test_must_fail git rev-parse refs/bisect/something &&
git update-ref refs/bisect/something HEAD &&
git rev-parse refs/bisect/something >main-head &&
@@ -1500,7 +1507,7 @@ test_expect_success 'transaction can handle abort' '
git update-ref --stdin <stdin >actual &&
printf "%s: ok\n" start abort >expect &&
test_cmp expect actual &&
- test_path_is_missing .git/$b
+ test_must_fail git show-ref --verify -q $b
'
test_expect_success 'transaction aborts by default' '
@@ -1511,7 +1518,7 @@ test_expect_success 'transaction aborts by default' '
git update-ref --stdin <stdin >actual &&
printf "%s: ok\n" start >expect &&
test_cmp expect actual &&
- test_path_is_missing .git/$b
+ test_must_fail git show-ref --verify -q $b
'
test_expect_success 'transaction with prepare aborts by default' '
@@ -1523,7 +1530,68 @@ test_expect_success 'transaction with prepare aborts by default' '
git update-ref --stdin <stdin >actual &&
printf "%s: ok\n" start prepare >expect &&
test_cmp expect actual &&
- test_path_is_missing .git/$b
+ test_must_fail git show-ref --verify -q $b
+'
+
+test_expect_success 'transaction can commit multiple times' '
+ cat >stdin <<-EOF &&
+ start
+ create refs/heads/branch-1 $A
+ commit
+ start
+ create refs/heads/branch-2 $B
+ commit
+ EOF
+ git update-ref --stdin <stdin >actual &&
+ printf "%s: ok\n" start commit start commit >expect &&
+ test_cmp expect actual &&
+ echo "$A" >expect &&
+ git rev-parse refs/heads/branch-1 >actual &&
+ test_cmp expect actual &&
+ echo "$B" >expect &&
+ git rev-parse refs/heads/branch-2 >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'transaction can create and delete' '
+ cat >stdin <<-EOF &&
+ start
+ create refs/heads/create-and-delete $A
+ commit
+ start
+ delete refs/heads/create-and-delete $A
+ commit
+ EOF
+ git update-ref --stdin <stdin >actual &&
+ printf "%s: ok\n" start commit start commit >expect &&
+ test_must_fail git show-ref --verify refs/heads/create-and-delete
+'
+
+test_expect_success 'transaction can commit after abort' '
+ cat >stdin <<-EOF &&
+ start
+ create refs/heads/abort $A
+ abort
+ start
+ create refs/heads/abort $A
+ commit
+ EOF
+ git update-ref --stdin <stdin >actual &&
+ printf "%s: ok\n" start abort start commit >expect &&
+ echo "$A" >expect &&
+ git rev-parse refs/heads/abort >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'transaction cannot restart ongoing transaction' '
+ cat >stdin <<-EOF &&
+ start
+ create refs/heads/restart $A
+ start
+ commit
+ EOF
+ test_must_fail git update-ref --stdin <stdin >actual &&
+ test_must_fail git show-ref --verify refs/heads/restart
'
test_done
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index ca04fac417..cc3f434a97 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -589,6 +589,90 @@ test_expect_success 'diffs can be colorized' '
grep "$(printf "\\033")" output
'
+test_expect_success 'colors can be overridden' '
+ git reset --hard &&
+ test_when_finished "git rm -f color-test" &&
+ test_write_lines context old more-context >color-test &&
+ git add color-test &&
+ test_write_lines context new more-context another-one >color-test &&
+
+ echo trigger an error message >input &&
+ force_color git \
+ -c color.interactive.error=blue \
+ add -i 2>err.raw <input &&
+ test_decode_color <err.raw >err &&
+ grep "<BLUE>Huh (trigger)?<RESET>" err &&
+
+ test_write_lines help quit >input &&
+ force_color git \
+ -c color.interactive.header=red \
+ -c color.interactive.help=green \
+ -c color.interactive.prompt=yellow \
+ add -i >actual.raw <input &&
+ test_decode_color <actual.raw >actual &&
+ cat >expect <<-\EOF &&
+ <RED> staged unstaged path<RESET>
+ 1: +3/-0 +2/-1 color-test
+
+ <RED>*** Commands ***<RESET>
+ 1: <YELLOW>s<RESET>tatus 2: <YELLOW>u<RESET>pdate 3: <YELLOW>r<RESET>evert 4: <YELLOW>a<RESET>dd untracked
+ 5: <YELLOW>p<RESET>atch 6: <YELLOW>d<RESET>iff 7: <YELLOW>q<RESET>uit 8: <YELLOW>h<RESET>elp
+ <YELLOW>What now<RESET>> <GREEN>status - show paths with changes<RESET>
+ <GREEN>update - add working tree state to the staged set of changes<RESET>
+ <GREEN>revert - revert staged set of changes back to the HEAD version<RESET>
+ <GREEN>patch - pick hunks and update selectively<RESET>
+ <GREEN>diff - view diff between HEAD and index<RESET>
+ <GREEN>add untracked - add contents of untracked files to the staged set of changes<RESET>
+ <RED>*** Commands ***<RESET>
+ 1: <YELLOW>s<RESET>tatus 2: <YELLOW>u<RESET>pdate 3: <YELLOW>r<RESET>evert 4: <YELLOW>a<RESET>dd untracked
+ 5: <YELLOW>p<RESET>atch 6: <YELLOW>d<RESET>iff 7: <YELLOW>q<RESET>uit 8: <YELLOW>h<RESET>elp
+ <YELLOW>What now<RESET>> Bye.
+ EOF
+ test_cmp expect actual &&
+
+ : exercise recolor_hunk by editing and then look at the hunk again &&
+ test_write_lines s e K q >input &&
+ force_color git \
+ -c color.interactive.prompt=yellow \
+ -c color.diff.meta=italic \
+ -c color.diff.frag=magenta \
+ -c color.diff.context=cyan \
+ -c color.diff.old=bold \
+ -c color.diff.new=blue \
+ -c core.editor=touch \
+ add -p >actual.raw <input &&
+ test_decode_color <actual.raw >actual.decoded &&
+ sed "s/index [0-9a-f]*\\.\\.[0-9a-f]* 100644/<INDEX-LINE>/" <actual.decoded >actual &&
+ cat >expect <<-\EOF &&
+ <ITALIC>diff --git a/color-test b/color-test<RESET>
+ <ITALIC><INDEX-LINE><RESET>
+ <ITALIC>--- a/color-test<RESET>
+ <ITALIC>+++ b/color-test<RESET>
+ <MAGENTA>@@ -1,3 +1,4 @@<RESET>
+ <CYAN> context<RESET>
+ <BOLD>-old<RESET>
+ <BLUE>+<RESET><BLUE>new<RESET>
+ <CYAN> more-context<RESET>
+ <BLUE>+<RESET><BLUE>another-one<RESET>
+ <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? <RESET><BOLD>Split into 2 hunks.<RESET>
+ <MAGENTA>@@ -1,3 +1,3 @@<RESET>
+ <CYAN> context<RESET>
+ <BOLD>-old<RESET>
+ <BLUE>+<RESET><BLUE>new<RESET>
+ <CYAN> more-context<RESET>
+ <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
+ <CYAN> more-context<RESET>
+ <BLUE>+<RESET><BLUE>another-one<RESET>
+ <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
+ <CYAN> context<RESET>
+ <BOLD>-old<RESET>
+ <BLUE>+new<RESET>
+ <CYAN> more-context<RESET>
+ <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET>
+ EOF
+ test_cmp expect actual
+'
+
test_expect_success 'colorized diffs respect diff.wsErrorHighlight' '
git reset --hard &&
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/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index ace469c95c..297de502a9 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -138,7 +138,7 @@ test_expect_success 'write midx with one v2 pack' '
compare_results_with_midx "one v2 pack"
-test_expect_success 'corrupt idx not opened' '
+test_expect_success 'corrupt idx reports errors' '
idx=$(test-tool read-midx $objdir | grep "\.idx\$") &&
mv $objdir/pack/$idx backup-$idx &&
test_when_finished "mv backup-\$idx \$objdir/pack/\$idx" &&
@@ -149,7 +149,7 @@ test_expect_success 'corrupt idx not opened' '
test_copy_bytes 1064 <backup-$idx >$objdir/pack/$idx &&
git -c core.multiPackIndex=true rev-list --objects --all 2>err &&
- test_must_be_empty err
+ grep "index unavailable" err
'
test_expect_success 'add more objects' '
@@ -755,4 +755,30 @@ test_expect_success 'repack --batch-size=<large> repacks everything' '
)
'
+test_expect_success 'load reverse index when missing .idx, .pack' '
+ git init repo &&
+ test_when_finished "rm -fr repo" &&
+ (
+ cd repo &&
+
+ git config core.multiPackIndex true &&
+
+ test_commit base &&
+ git repack -ad &&
+ git multi-pack-index write &&
+
+ git rev-parse HEAD >tip &&
+ pack=$(ls .git/objects/pack/pack-*.pack) &&
+ idx=$(ls .git/objects/pack/pack-*.idx) &&
+
+ mv $idx $idx.bak &&
+ git cat-file --batch-check="%(objectsize:disk)" <tip &&
+
+ mv $idx.bak $idx &&
+
+ mv $pack $pack.bak &&
+ git cat-file --batch-check="%(objectsize:disk)" <tip
+ )
+'
+
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 5da945cf15..d98c550267 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 d9e68bb2bf..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 &&
@@ -404,11 +406,23 @@ test_expect_success 'register and unregister' '
test_cmp before actual
'
+test_expect_success !MINGW 'register and unregister with regex metacharacters' '
+ META="a+b*c" &&
+ git init "$META" &&
+ git -C "$META" maintenance register &&
+ git config --get-all --show-origin maintenance.repo &&
+ git config --get-all --global --fixed-value \
+ maintenance.repo "$(pwd)/$META" &&
+ git -C "$META" maintenance unregister &&
+ test_must_fail git config --get-all --global --fixed-value \
+ maintenance.repo "$(pwd)/$META"
+'
+
test_expect_success 'start from empty cron table' '
GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance start &&
# start registers the repo
- git config --get --global maintenance.repo "$(pwd)" &&
+ git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
grep "for-each-repo --config=maintenance.repo maintenance run --schedule=daily" cron.txt &&
grep "for-each-repo --config=maintenance.repo maintenance run --schedule=hourly" cron.txt &&
@@ -419,7 +433,7 @@ test_expect_success 'stop from existing schedule' '
GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop &&
# stop does not unregister the repo
- git config --get --global maintenance.repo "$(pwd)" &&
+ git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
# Operation is idempotent
GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop &&
@@ -441,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="$*"
diff --git a/trace2.c b/trace2.c
index 2c6b570077..256120c7fd 100644
--- a/trace2.c
+++ b/trace2.c
@@ -792,3 +792,8 @@ void trace2_printf(const char *fmt, ...)
va_end(ap);
}
#endif
+
+const char *trace2_session_id(void)
+{
+ return tr2_sid_get();
+}
diff --git a/trace2.h b/trace2.h
index b18bc5529c..ede18c2e06 100644
--- a/trace2.h
+++ b/trace2.h
@@ -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 be8fffbc07..3b66bf92ba 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");
}
diff --git a/usage.c b/usage.c
index 06665823a2..1868a24f7a 100644
--- a/usage.c
+++ b/usage.c
@@ -81,6 +81,12 @@ static void error_builtin(const char *err, va_list params)
static void warn_builtin(const char *warn, va_list params)
{
+ /*
+ * We call this trace2 function first and expect it to va_copy 'params'
+ * before using it (because an 'ap' can only be walked once).
+ */
+ trace2_cmd_error_va(warn, params);
+
vreportf("warning: ", warn, params);
}