]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'mh/credential-unrecognized-attrs'
authorTaylor Blau <me@ttaylorr.com>
Fri, 18 Nov 2022 23:43:59 +0000 (18:43 -0500)
committerTaylor Blau <me@ttaylorr.com>
Fri, 18 Nov 2022 23:43:59 +0000 (18:43 -0500)
Docfix.

* mh/credential-unrecognized-attrs:
  docs: clarify that credential discards unrecognised attributes

37 files changed:
.github/workflows/main.yml
Documentation/MyFirstContribution.txt
Documentation/RelNotes/2.39.0.txt
Documentation/git-credential-cache.txt
Documentation/git-repack.txt
Documentation/gitcredentials.txt
Documentation/technical/repository-version.txt
INSTALL
Makefile
builtin/read-tree.c
builtin/repack.c
builtin/reset.c
ci/lib.sh
contrib/buildsystems/CMakeLists.txt
reset.c
revision.c
revision.h
sequencer.c
sha1dc_git.h
sparse-index.c
t/helper/test-cache-tree.c [new file with mode: 0644]
t/helper/test-sha1.c
t/helper/test-tool.c
t/helper/test-tool.h
t/perf/p0006-read-tree-checkout.sh
t/perf/p0090-cache-tree.sh [new file with mode: 0755]
t/perf/p7102-reset.sh [new file with mode: 0755]
t/t0013-sha1dc.sh
t/t0061-run-command.sh
t/t1022-read-tree-partial-clone.sh
t/t1800-hook.sh
t/t3404-rebase-interactive.sh
t/t5526-fetch-submodules.sh
t/t7001-mv.sh
t/t7700-repack.sh
unpack-trees.c
unpack-trees.h

index bd6f75b8e0fed74880a2608618b7480d4018797d..592f9193a8c812d56c9890422e7b3f762dd03bf9 100644 (file)
@@ -37,14 +37,14 @@ jobs:
           echo "::set-output name=enabled::$enabled"
       - name: skip if the commit or tree was already tested
         id: skip-if-redundant
-        uses: actions/github-script@v3
+        uses: actions/github-script@v6
         if: steps.check-ref.outputs.enabled == 'yes'
         with:
           github-token: ${{secrets.GITHUB_TOKEN}}
           script: |
             try {
               // Figure out workflow ID, commit and tree
-              const { data: run } = await github.actions.getWorkflowRun({
+              const { data: run } = await github.rest.actions.getWorkflowRun({
                 owner: context.repo.owner,
                 repo: context.repo.repo,
                 run_id: context.runId,
@@ -54,7 +54,7 @@ jobs:
               const tree_id = run.head_commit.tree_id;
 
               // See whether there is a successful run for that commit or tree
-              const { data: runs } = await github.actions.listWorkflowRuns({
+              const { data: runs } = await github.rest.actions.listWorkflowRuns({
                 owner: context.repo.owner,
                 repo: context.repo.repo,
                 per_page: 500,
index 1a4be8ee0adde5db48e5f53a8fe79dd17036b270..ccfd0cb5f3e2aadb04bed17b5082ae71fc5fa2e0 100644 (file)
@@ -736,7 +736,7 @@ the {lore}[Git mailing list archive]:
 2022-02-21  1:43     ` John Cai
 2022-02-21  1:50       ` Taylor Blau
 2022-02-23 19:50         ` John Cai
-2022-02-18 20:00   ` // other replies ellided
+2022-02-18 20:00   ` // other replies elided
 2022-02-18 18:40 ` [PATCH 2/3] reflog: call reflog_delete from reflog.c John Cai via GitGitGadget
 2022-02-18 19:15   ` Ævar Arnfjörð Bjarmason
 2022-02-18 20:26     ` Junio C Hamano
index f21f94947578e40e6882d05f7d8a0e95edc9e3cd..f9bc29f7d29cf96aaece6936d8398e2544cb6a45 100644 (file)
@@ -98,6 +98,17 @@ Performance, Internal Implementation, Development Support etc.
 
  * Simplify the run-command API.
 
+ * Update the actions/github-script dependency in CI to avoid a
+   deprecation warning.
+
+ * Progress on being able to initialize a rev_info struct with a
+   macro.
+
+ * Add trace2 counters to the region to clear skip worktree bits in a
+   sparse checkout.
+
+ * Modernize test script to avoid "test -f" and friends.
+
 Fixes since v2.38
 -----------------
 
index 0216c18ef80c9a9d32095ec3969091aff1c20344..432e159d95246ccb9e716ad1554c8b6047db1870 100644 (file)
@@ -69,10 +69,10 @@ $ git push http://example.com/repo.git
 ------------------------------------
 
 You can provide options via the credential.helper configuration
-variable (this example drops the cache time to 5 minutes):
+variable (this example increases the cache time to 1 hour):
 
 -------------------------------------------------------
-$ git config credential.helper 'cache --timeout=300'
+$ git config credential.helper 'cache --timeout=3600'
 -------------------------------------------------------
 
 GIT
index 0bf13893d8147d872dbedeed9def497b2a5a0fea..4017157949e6d764a619f870c0eed538d3e99f64 100644 (file)
@@ -74,6 +74,12 @@ to the new separate pack will be written.
        immediately instead of waiting for the next `git gc` invocation.
        Only useful with `--cruft -d`.
 
+--expire-to=<dir>::
+       Write a cruft pack containing pruned objects (if any) to the
+       directory `<dir>`. This option is useful for keeping a copy of
+       any pruned objects in a separate directory as a backup. Only
+       useful with `--cruft -d`.
+
 -l::
        Pass the `--local` option to 'git pack-objects'. See
        linkgit:git-pack-objects[1].
index e856e3c83300265666950b6c1f199fc21a722561..d6665d2f31f6ea2f418c6e01bc2cba47f98f671f 100644 (file)
@@ -17,9 +17,10 @@ DESCRIPTION
 
 Git will sometimes need credentials from the user in order to perform
 operations; for example, it may need to ask for a username and password
-in order to access a remote repository over HTTP. This manual describes
-the mechanisms Git uses to request these credentials, as well as some
-features to avoid inputting these credentials repeatedly.
+in order to access a remote repository over HTTP. Some remotes accept
+a personal access token or OAuth access token as a password. This
+manual describes the mechanisms Git uses to request these credentials,
+as well as some features to avoid inputting these credentials repeatedly.
 
 REQUESTING CREDENTIALS
 ----------------------
index 7844ef30ffdefd9158ae49ddd5d03d6a5c4edd4c..8ef664b0b9537ad3c8fc554e68448a69a3b7f439 100644 (file)
@@ -82,9 +82,9 @@ When the config key `extensions.preciousObjects` is set to `true`,
 objects in the repository MUST NOT be deleted (e.g., by `git-prune` or
 `git repack -d`).
 
-==== `partialclone`
+==== `partialClone`
 
-When the config key `extensions.partialclone` is set, it indicates
+When the config key `extensions.partialClone` is set, it indicates
 that the repo was created with a partial clone (or later performed
 a partial fetch) and that the remote may have omitted sending
 certain unwanted objects.  Such a remote is called a "promisor remote"
diff --git a/INSTALL b/INSTALL
index 89b15d71df521b2b710b77481e9607c03b78fccc..334478839744b48ce273ca75f464fada3596ce98 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -133,10 +133,6 @@ Issues of note:
          you are using libcurl older than 7.34.0.  Otherwise you can use
          NO_OPENSSL without losing git-imap-send.
 
-         By default, git uses OpenSSL for SHA1 but it will use its own
-         library (inspired by Mozilla's) with either NO_OPENSSL or
-         BLK_SHA1.
-
        - "libcurl" library is used for fetching and pushing
          repositories over http:// or https://, as well as by
          git-imap-send if the curl version is >= 7.34.0. If you do
index 4927379184cf9edb7ebc883c5ef40accea130232..54ede18bbb5fd8885fdfee321255093db8a3bbf6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,20 @@ all::
 # Import tree-wide shared Makefile behavior and libraries
 include shared.mak
 
+# == Makefile defines ==
+#
+# These defines change the behavior of the Makefile itself, but have
+# no impact on what it builds:
+#
 # Define V=1 to have a more verbose compile.
 #
+# == Portability and optional library defines ==
+#
+# These defines indicate what Git can expect from the OS, what
+# libraries are available etc. Much of this is auto-detected in
+# config.mak.uname, or in configure.ac when using the optional "make
+# configure && ./configure" (see INSTALL).
+#
 # Define SHELL_PATH to a POSIX shell if your /bin/sh is broken.
 #
 # Define SANE_TOOL_PATH to a colon-separated list of paths to prepend
@@ -30,68 +42,8 @@ include shared.mak
 #
 # Define NO_OPENSSL environment variable if you do not have OpenSSL.
 #
-# Define USE_LIBPCRE if you have and want to use libpcre. Various
-# commands such as log and grep offer runtime options to use
-# Perl-compatible regular expressions instead of standard or extended
-# POSIX regular expressions.
-#
-# Only libpcre version 2 is supported. USE_LIBPCRE2 is a synonym for
-# USE_LIBPCRE, support for the old USE_LIBPCRE1 has been removed.
-#
-# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
-# in /foo/bar/include and /foo/bar/lib directories.
-#
 # Define HAVE_ALLOCA_H if you have working alloca(3) defined in that header.
 #
-# Define NO_CURL if you do not have libcurl installed.  git-http-fetch and
-# git-http-push are not built, and you cannot use http:// and https://
-# transports (neither smart nor dumb).
-#
-# Define CURLDIR=/foo/bar if your curl header and library files are in
-# /foo/bar/include and /foo/bar/lib directories.
-#
-# Define CURL_CONFIG to curl's configuration program that prints information
-# about the library (e.g., its version number).  The default is 'curl-config'.
-#
-# Define CURL_LDFLAGS to specify flags that you need to link when using libcurl,
-# if you do not want to rely on the libraries provided by CURL_CONFIG.  The
-# default value is a result of `curl-config --libs`.  An example value for
-# CURL_LDFLAGS is as follows:
-#
-#     CURL_LDFLAGS=-lcurl
-#
-# Define NO_EXPAT if you do not have expat installed.  git-http-push is
-# not built, and you cannot push using http:// and https:// transports (dumb).
-#
-# Define EXPATDIR=/foo/bar if your expat header and library files are in
-# /foo/bar/include and /foo/bar/lib directories.
-#
-# Define EXPAT_NEEDS_XMLPARSE_H if you have an old version of expat (e.g.,
-# 1.1 or 1.2) that provides xmlparse.h instead of expat.h.
-#
-# Define NO_GETTEXT if you don't want Git output to be translated.
-# A translated Git requires GNU libintl or another gettext implementation,
-# plus libintl-perl at runtime.
-#
-# Define USE_GETTEXT_SCHEME and set it to 'fallthrough', if you don't trust
-# the installed gettext translation of the shell scripts output.
-#
-# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
-# trust the langinfo.h's nl_langinfo(CODESET) function to return the
-# current character set. GNU and Solaris have a nl_langinfo(CODESET),
-# FreeBSD can use either, but MinGW and some others need to use
-# libcharset.h's locale_charset() instead.
-#
-# Define CHARSET_LIB to the library you need to link with in order to
-# use locale_charset() function.  On some platforms this needs to set to
-# -lcharset, on others to -liconv .
-#
-# Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't
-# need -lintl when linking.
-#
-# Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt
-# doesn't support GNU extensions like --check and --statistics
-#
 # Define HAVE_PATHS_H if you have paths.h and want to use the default PATH
 # it specifies.
 #
@@ -152,39 +104,6 @@ include shared.mak
 # and do not want to use Apple's CommonCrypto library.  This allows you
 # to provide your own OpenSSL library, for example from MacPorts.
 #
-# Define BLK_SHA1 environment variable to make use of the bundled
-# optimized C SHA1 routine.
-#
-# Define DC_SHA1 to unconditionally enable the collision-detecting sha1
-# algorithm. This is slower, but may detect attempted collision attacks.
-# Takes priority over other *_SHA1 knobs.
-#
-# Define DC_SHA1_EXTERNAL in addition to DC_SHA1 if you want to build / link
-# git with the external SHA1 collision-detect library.
-# Without this option, i.e. the default behavior is to build git with its
-# own built-in code (or submodule).
-#
-# Define DC_SHA1_SUBMODULE in addition to DC_SHA1 to use the
-# sha1collisiondetection shipped as a submodule instead of the
-# non-submodule copy in sha1dc/. This is an experimental option used
-# by the git project to migrate to using sha1collisiondetection as a
-# submodule.
-#
-# Define OPENSSL_SHA1 environment variable when running make to link
-# with the SHA1 routine from openssl library.
-#
-# Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed
-# in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO
-# wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined.
-#
-# Define BLK_SHA256 to use the built-in SHA-256 routines.
-#
-# Define NETTLE_SHA256 to use the SHA-256 routines in libnettle.
-#
-# Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
-#
-# Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
-#
 # Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin).
 #
 # Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin).
@@ -490,6 +409,151 @@ include shared.mak
 # to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
 # that implements the `fsm_os_settings__*()` routines.
 #
+# === Optional library: libintl ===
+#
+# Define NO_GETTEXT if you don't want Git output to be translated.
+# A translated Git requires GNU libintl or another gettext implementation,
+# plus libintl-perl at runtime.
+#
+# Define USE_GETTEXT_SCHEME and set it to 'fallthrough', if you don't trust
+# the installed gettext translation of the shell scripts output.
+#
+# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
+# trust the langinfo.h's nl_langinfo(CODESET) function to return the
+# current character set. GNU and Solaris have a nl_langinfo(CODESET),
+# FreeBSD can use either, but MinGW and some others need to use
+# libcharset.h's locale_charset() instead.
+#
+# Define CHARSET_LIB to the library you need to link with in order to
+# use locale_charset() function.  On some platforms this needs to set to
+# -lcharset, on others to -liconv .
+#
+# Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't
+# need -lintl when linking.
+#
+# Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt
+# doesn't support GNU extensions like --check and --statistics
+#
+# === Optional library: libexpat ===
+#
+# Define NO_EXPAT if you do not have expat installed.  git-http-push is
+# not built, and you cannot push using http:// and https:// transports (dumb).
+#
+# Define EXPATDIR=/foo/bar if your expat header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+#
+# Define EXPAT_NEEDS_XMLPARSE_H if you have an old version of expat (e.g.,
+# 1.1 or 1.2) that provides xmlparse.h instead of expat.h.
+
+# === Optional library: libcurl ===
+#
+# Define NO_CURL if you do not have libcurl installed.  git-http-fetch and
+# git-http-push are not built, and you cannot use http:// and https://
+# transports (neither smart nor dumb).
+#
+# Define CURLDIR=/foo/bar if your curl header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+#
+# Define CURL_CONFIG to curl's configuration program that prints information
+# about the library (e.g., its version number).  The default is 'curl-config'.
+#
+# Define CURL_LDFLAGS to specify flags that you need to link when using libcurl,
+# if you do not want to rely on the libraries provided by CURL_CONFIG.  The
+# default value is a result of `curl-config --libs`.  An example value for
+# CURL_LDFLAGS is as follows:
+#
+#     CURL_LDFLAGS=-lcurl
+#
+# === Optional library: libpcre2 ===
+#
+# Define USE_LIBPCRE if you have and want to use libpcre. Various
+# commands such as log and grep offer runtime options to use
+# Perl-compatible regular expressions instead of standard or extended
+# POSIX regular expressions.
+#
+# Only libpcre version 2 is supported. USE_LIBPCRE2 is a synonym for
+# USE_LIBPCRE, support for the old USE_LIBPCRE1 has been removed.
+#
+# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
+# in /foo/bar/include and /foo/bar/lib directories.
+#
+# == SHA-1 and SHA-256 defines ==
+#
+# === SHA-1 backend ===
+#
+# ==== Security ====
+#
+# Due to the SHAttered (https://shattered.io) attack vector on SHA-1
+# it's strongly recommended to use the sha1collisiondetection
+# counter-cryptanalysis library for SHA-1 hashing.
+#
+# If you know that you can trust the repository contents, or where
+# potential SHA-1 attacks are otherwise mitigated the other backends
+# listed in "SHA-1 implementations" are faster than
+# sha1collisiondetection.
+#
+# ==== Default SHA-1 backend ====
+#
+# If no *_SHA1 backend is picked, the first supported one listed in
+# "SHA-1 implementations" will be picked.
+#
+# ==== Options common to all SHA-1 implementations ====
+#
+# Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed
+# in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO
+# wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined.
+#
+# ==== SHA-1 implementations ====
+#
+# Define OPENSSL_SHA1 to link to the SHA-1 routines from the OpenSSL
+# library.
+#
+# Define BLK_SHA1 to make use of optimized C SHA-1 routines bundled
+# with git (in the block-sha1/ directory).
+#
+# Define NO_APPLE_COMMON_CRYPTO on OSX to opt-out of using the
+# "APPLE_COMMON_CRYPTO" backend for SHA-1, which is currently the
+# default on that OS. On macOS 01.4 (Tiger) or older,
+# NO_APPLE_COMMON_CRYPTO is defined by default.
+#
+# If don't enable any of the *_SHA1 settings in this section, Git will
+# default to its built-in sha1collisiondetection library, which is a
+# collision-detecting sha1 This is slower, but may detect attempted
+# collision attacks.
+#
+# ==== Options for the sha1collisiondetection library ====
+#
+# Define DC_SHA1_EXTERNAL if you want to build / link
+# git with the external SHA1 collision-detect library.
+# Without this option, i.e. the default behavior is to build git with its
+# own built-in code (or submodule).
+#
+# Define DC_SHA1_SUBMODULE to use the
+# sha1collisiondetection shipped as a submodule instead of the
+# non-submodule copy in sha1dc/. This is an experimental option used
+# by the git project to migrate to using sha1collisiondetection as a
+# submodule.
+#
+# === SHA-256 backend ===
+#
+# ==== Security ====
+#
+# Unlike SHA-1 the SHA-256 algorithm does not suffer from any known
+# vulnerabilities, so any implementation will do.
+#
+# ==== SHA-256 implementations ====
+#
+# Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
+#
+# Define NETTLE_SHA256 to use the SHA-256 routines in libnettle.
+#
+# Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
+#
+# If don't enable any of the *_SHA256 settings in this section, Git
+# will default to its built-in sha256 implementation.
+#
+# == DEVELOPER defines ==
+#
 # Define DEVELOPER to enable more compiler warnings. Compiler version
 # and family are auto detected, but could be overridden by defining
 # COMPILER_FEATURES (see config.mak.dev). You can still set
@@ -723,6 +787,7 @@ TEST_BUILTINS_OBJS += test-advise.o
 TEST_BUILTINS_OBJS += test-bitmap.o
 TEST_BUILTINS_OBJS += test-bloom.o
 TEST_BUILTINS_OBJS += test-bundle-uri.o
+TEST_BUILTINS_OBJS += test-cache-tree.o
 TEST_BUILTINS_OBJS += test-chmtime.o
 TEST_BUILTINS_OBJS += test-config.o
 TEST_BUILTINS_OBJS += test-crontab.o
@@ -1826,7 +1891,6 @@ ifdef APPLE_COMMON_CRYPTO
        COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
        BASIC_CFLAGS += -DSHA1_APPLE
 else
-       DC_SHA1 := YesPlease
        BASIC_CFLAGS += -DSHA1_DC
        LIB_OBJS += sha1dc_git.o
 ifdef DC_SHA1_EXTERNAL
@@ -2989,7 +3053,6 @@ GIT-BUILD-OPTIONS: FORCE
        @echo NO_REGEX=\''$(subst ','\'',$(subst ','\'',$(NO_REGEX)))'\' >>$@+
        @echo NO_UNIX_SOCKETS=\''$(subst ','\'',$(subst ','\'',$(NO_UNIX_SOCKETS)))'\' >>$@+
        @echo PAGER_ENV=\''$(subst ','\'',$(subst ','\'',$(PAGER_ENV)))'\' >>$@+
-       @echo DC_SHA1=\''$(subst ','\'',$(subst ','\'',$(DC_SHA1)))'\' >>$@+
        @echo SANITIZE_LEAK=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_LEAK)))'\' >>$@+
        @echo SANITIZE_ADDRESS=\''$(subst ','\'',$(subst ','\'',$(SANITIZE_ADDRESS)))'\' >>$@+
        @echo X=\'$(X)\' >>$@+
index f4cbe460b978447ba10bbb3e71b4faee1015d56d..45c6652444b6c12183cc43b38c3bc864b74e028b 100644 (file)
@@ -249,6 +249,10 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
        if (opts.debug_unpack)
                opts.fn = debug_merge;
 
+       /* If we're going to prime_cache_tree later, skip cache tree update */
+       if (nr_trees == 1 && !opts.prefix)
+               opts.skip_cache_tree_update = 1;
+
        cache_tree_free(&active_cache_tree);
        for (i = 0; i < nr_trees; i++) {
                struct tree *tree = trees[i];
index 10e23f9ee1fc4baea34152c23ea8ab5459986ae5..65eb1b8bd22b4119908abe700cfd3a6d143289f1 100644 (file)
@@ -32,7 +32,6 @@ static int write_bitmaps = -1;
 static int use_delta_islands;
 static int run_update_server_info = 1;
 static char *packdir, *packtmp_name, *packtmp;
-static char *cruft_expiration;
 
 static const char *const git_repack_usage[] = {
        N_("git repack [<options>]"),
@@ -150,7 +149,8 @@ static void remove_redundant_pack(const char *dir_name, const char *base_name)
 }
 
 static void prepare_pack_objects(struct child_process *cmd,
-                                const struct pack_objects_args *args)
+                                const struct pack_objects_args *args,
+                                const char *out)
 {
        strvec_push(&cmd->args, "pack-objects");
        if (args->window)
@@ -173,7 +173,7 @@ static void prepare_pack_objects(struct child_process *cmd,
                strvec_push(&cmd->args,  "--quiet");
        if (delta_base_offset)
                strvec_push(&cmd->args,  "--delta-base-offset");
-       strvec_push(&cmd->args, packtmp);
+       strvec_push(&cmd->args, out);
        cmd->git_cmd = 1;
        cmd->out = -1;
 }
@@ -241,7 +241,7 @@ static void repack_promisor_objects(const struct pack_objects_args *args,
        FILE *out;
        struct strbuf line = STRBUF_INIT;
 
-       prepare_pack_objects(&cmd, args);
+       prepare_pack_objects(&cmd, args, packtmp);
        cmd.in = -1;
 
        /*
@@ -657,7 +657,9 @@ static void remove_redundant_bitmaps(struct string_list *include,
 }
 
 static int write_cruft_pack(const struct pack_objects_args *args,
+                           const char *destination,
                            const char *pack_prefix,
+                           const char *cruft_expiration,
                            struct string_list *names,
                            struct string_list *existing_packs,
                            struct string_list *existing_kept_packs)
@@ -667,8 +669,10 @@ static int write_cruft_pack(const struct pack_objects_args *args,
        struct string_list_item *item;
        FILE *in, *out;
        int ret;
+       const char *scratch;
+       int local = skip_prefix(destination, packdir, &scratch);
 
-       prepare_pack_objects(&cmd, args);
+       prepare_pack_objects(&cmd, args, destination);
 
        strvec_push(&cmd.args, "--cruft");
        if (cruft_expiration)
@@ -693,6 +697,10 @@ static int write_cruft_pack(const struct pack_objects_args *args,
         * By the time it is read here, it contains only the pack(s)
         * that were just written, which is exactly the set of packs we
         * want to consider kept.
+        *
+        * If `--expire-to` is given, the double-use served by `names`
+        * ensures that the pack written to `--expire-to` excludes any
+        * objects contained in the cruft pack.
         */
        in = xfdopen(cmd.in, "w");
        for_each_string_list_item(item, names)
@@ -710,9 +718,14 @@ static int write_cruft_pack(const struct pack_objects_args *args,
                if (line.len != the_hash_algo->hexsz)
                        die(_("repack: Expecting full hex object ID lines only "
                              "from pack-objects."));
-
-               item = string_list_append(names, line.buf);
-               item->util = populate_pack_exts(line.buf);
+               /*
+                * avoid putting packs written outside of the repository in the
+                * list of names
+                */
+               if (local) {
+                       item = string_list_append(names, line.buf);
+                       item->util = populate_pack_exts(line.buf);
+               }
        }
        fclose(out);
 
@@ -744,6 +757,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        struct pack_objects_args cruft_po_args = {NULL};
        int geometric_factor = 0;
        int write_midx = 0;
+       const char *cruft_expiration = NULL;
+       const char *expire_to = NULL;
 
        struct option builtin_repack_options[] = {
                OPT_BIT('a', NULL, &pack_everything,
@@ -793,6 +808,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                            N_("find a geometric progression with factor <N>")),
                OPT_BOOL('m', "write-midx", &write_midx,
                           N_("write a multi-pack index of the resulting packs")),
+               OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
+                          N_("pack prefix to store a pack containing pruned objects")),
                OPT_END()
        };
 
@@ -858,7 +875,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                split_pack_geometry(geometry, geometric_factor);
        }
 
-       prepare_pack_objects(&cmd, &po_args);
+       prepare_pack_objects(&cmd, &po_args, packtmp);
 
        show_progress = !po_args.quiet && isatty(2);
 
@@ -984,11 +1001,45 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
                cruft_po_args.local = po_args.local;
                cruft_po_args.quiet = po_args.quiet;
 
-               ret = write_cruft_pack(&cruft_po_args, pack_prefix, &names,
+               ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
+                                      cruft_expiration, &names,
                                       &existing_nonkept_packs,
                                       &existing_kept_packs);
                if (ret)
                        return ret;
+
+               if (delete_redundant && expire_to) {
+                       /*
+                        * If `--expire-to` is given with `-d`, it's possible
+                        * that we're about to prune some objects. With cruft
+                        * packs, pruning is implicit: any objects from existing
+                        * packs that weren't picked up by new packs are removed
+                        * when their packs are deleted.
+                        *
+                        * Generate an additional cruft pack, with one twist:
+                        * `names` now includes the name of the cruft pack
+                        * written in the previous step. So the contents of
+                        * _this_ cruft pack exclude everything contained in the
+                        * existing cruft pack (that is, all of the unreachable
+                        * objects which are no older than
+                        * `--cruft-expiration`).
+                        *
+                        * To make this work, cruft_expiration must become NULL
+                        * so that this cruft pack doesn't actually prune any
+                        * objects. If it were non-NULL, this call would always
+                        * generate an empty pack (since every object not in the
+                        * cruft pack generated above will have an mtime older
+                        * than the expiration).
+                        */
+                       ret = write_cruft_pack(&cruft_po_args, expire_to,
+                                              pack_prefix,
+                                              NULL,
+                                              &names,
+                                              &existing_nonkept_packs,
+                                              &existing_kept_packs);
+                       if (ret)
+                               return ret;
+               }
        }
 
        string_list_sort(&names);
index fdce6f8c85670c8b2b0e20304336debba3190408..ab0277748240c0d74e92a5bb5e0105af956d88a6 100644 (file)
@@ -73,9 +73,11 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
        case HARD:
                opts.update = 1;
                opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+               opts.skip_cache_tree_update = 1;
                break;
        case MIXED:
                opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
+               opts.skip_cache_tree_update = 1;
                /* but opts.update=0, so working tree not updated */
                break;
        default:
index 1808e3b1ce1d1c12428511bac6cba5182991ce36..24d20a5d648d74596d57bddb29597e4766cf275f 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -260,7 +260,7 @@ macos-latest)
        else
                MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)"
                MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks"
-               MAKEFLAGS="$MAKEFLAGS DC_SHA1=YesPlease NO_OPENSSL=NoThanks"
+               MAKEFLAGS="$MAKEFLAGS NO_OPENSSL=NoThanks"
        fi
        ;;
 esac
index 3957e4cf8cd5be6e2524b50a51032d6a0b811aaa..2f6e0197ffa489ccc14b0665cdf78dba43b39e3e 100644 (file)
@@ -1025,7 +1025,6 @@ set(NO_PERL )
 set(NO_PTHREADS )
 set(NO_PYTHON )
 set(PAGER_ENV "LESS=FRX LV=-c")
-set(DC_SHA1 YesPlease)
 set(RUNTIME_PREFIX true)
 set(NO_GETTEXT )
 
@@ -1061,7 +1060,6 @@ file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PERL='${NO_PERL}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PTHREADS='${NO_PTHREADS}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_UNIX_SOCKETS='${NO_UNIX_SOCKETS}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PAGER_ENV='${PAGER_ENV}'\n")
-file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "DC_SHA1='${DC_SHA1}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "X='${EXE_EXTENSION}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_GETTEXT='${NO_GETTEXT}'\n")
 file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PREFIX}'\n")
diff --git a/reset.c b/reset.c
index e3383a93343e3df16ee9eda6ee7886a49e980a1a..5ded23611f3f7316e2327872a54474ce6e4f6200 100644 (file)
--- a/reset.c
+++ b/reset.c
@@ -128,6 +128,7 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
        unpack_tree_opts.update = 1;
        unpack_tree_opts.merge = 1;
        unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+       unpack_tree_opts.skip_cache_tree_update = 1;
        init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
        if (reset_hard)
                unpack_tree_opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
index 0760e78936e4f147fc3170d4a7ba75b7e6e88ab5..c6b399658345aafc3f182cdb76a868c97d8b0c62 100644 (file)
@@ -1865,30 +1865,15 @@ void repo_init_revisions(struct repository *r,
                         struct rev_info *revs,
                         const char *prefix)
 {
-       memset(revs, 0, sizeof(*revs));
+       struct rev_info blank = REV_INFO_INIT;
+       memcpy(revs, &blank, sizeof(*revs));
 
        revs->repo = r;
-       revs->abbrev = DEFAULT_ABBREV;
-       revs->simplify_history = 1;
        revs->pruning.repo = r;
-       revs->pruning.flags.recursive = 1;
-       revs->pruning.flags.quick = 1;
        revs->pruning.add_remove = file_add_remove;
        revs->pruning.change = file_change;
        revs->pruning.change_fn_data = revs;
-       revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
-       revs->dense = 1;
        revs->prefix = prefix;
-       revs->max_age = -1;
-       revs->max_age_as_filter = -1;
-       revs->min_age = -1;
-       revs->skip_count = -1;
-       revs->max_count = -1;
-       revs->max_parents = -1;
-       revs->expand_tabs_in_log = -1;
-
-       revs->commit_format = CMIT_FMT_DEFAULT;
-       revs->expand_tabs_in_log_default = 8;
 
        grep_init(&revs->grep_filter, revs->repo);
        revs->grep_filter.status_only = 1;
index afe1b77985faf5caeea507dad6639441013587c2..8493a3f3b939eb40e1e73b4a0a9ee5728c1aafe7 100644 (file)
@@ -357,7 +357,23 @@ struct rev_info {
  * called before release_revisions() the "struct rev_info" can be left
  * uninitialized.
  */
-#define REV_INFO_INIT { 0 }
+#define REV_INFO_INIT { \
+       .abbrev = DEFAULT_ABBREV, \
+       .simplify_history = 1, \
+       .pruning.flags.recursive = 1, \
+       .pruning.flags.quick = 1, \
+       .sort_order = REV_SORT_IN_GRAPH_ORDER, \
+       .dense = 1, \
+       .max_age = -1, \
+       .max_age_as_filter = -1, \
+       .min_age = -1, \
+       .skip_count = -1, \
+       .max_count = -1, \
+       .max_parents = -1, \
+       .expand_tabs_in_log = -1, \
+       .commit_format = CMIT_FMT_DEFAULT, \
+       .expand_tabs_in_log_default = 8, \
+}
 
 /**
  * Initialize a rev_info structure with default values. The third parameter may
index f0f1af4d4784b4ad7536a0a3de2857ab1dc8ca27..a46f3ad2e33761c310c2d01e0dd68069559044bd 100644 (file)
@@ -3748,6 +3748,7 @@ static int do_reset(struct repository *r,
        unpack_tree_opts.merge = 1;
        unpack_tree_opts.update = 1;
        unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+       unpack_tree_opts.skip_cache_tree_update = 1;
        init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
 
        if (repo_read_index_unmerged(r)) {
@@ -4128,11 +4129,14 @@ static int write_update_refs_state(struct string_list *refs_to_oids)
        struct string_list_item *item;
        char *path;
 
-       if (!refs_to_oids->nr)
-               return 0;
-
        path = rebase_path_update_refs(the_repository->gitdir);
 
+       if (!refs_to_oids->nr) {
+               if (unlink(path) && errno != ENOENT)
+                       result = error_errno(_("could not unlink: %s"), path);
+               goto cleanup;
+       }
+
        if (safe_create_leading_directories(path)) {
                result = error(_("unable to create leading directories of %s"),
                               path);
index 41e1c3fd3f787e04d6e4fa9eb7c56b617f1c5fa5..60e3ce84395ceaa70648a828ea1610a7fe9705a6 100644 (file)
@@ -17,6 +17,7 @@ void git_SHA1DCInit(SHA1_CTX *);
 void git_SHA1DCFinal(unsigned char [20], SHA1_CTX *);
 void git_SHA1DCUpdate(SHA1_CTX *ctx, const void *data, unsigned long len);
 
+#define platform_SHA_IS_SHA1DC /* used by "test-tool sha1-is-sha1dc" */
 #define platform_SHA_CTX SHA1_CTX
 #define platform_SHA1_Init git_SHA1DCInit
 #define platform_SHA1_Update git_SHA1DCUpdate
index e4a54ce19433dd0cdd553996762af642ace0d9b8..8c269dab803fa9a06a0e31ff42b6a20ec1983dbc 100644 (file)
@@ -493,24 +493,42 @@ void clear_skip_worktree_from_present_files(struct index_state *istate)
        int dir_found = 1;
 
        int i;
+       int path_count[2] = {0, 0};
+       int restarted = 0;
 
        if (!core_apply_sparse_checkout ||
            sparse_expect_files_outside_of_patterns)
                return;
 
+       trace2_region_enter("index", "clear_skip_worktree_from_present_files",
+                           istate->repo);
 restart:
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
 
-               if (ce_skip_worktree(ce) &&
-                   path_found(ce->name, &last_dirname, &dir_len, &dir_found)) {
-                       if (S_ISSPARSEDIR(ce->ce_mode)) {
-                               ensure_full_index(istate);
-                               goto restart;
+               if (ce_skip_worktree(ce)) {
+                       path_count[restarted]++;
+                       if (path_found(ce->name, &last_dirname, &dir_len, &dir_found)) {
+                               if (S_ISSPARSEDIR(ce->ce_mode)) {
+                                       if (restarted)
+                                               BUG("ensure-full-index did not fully flatten?");
+                                       ensure_full_index(istate);
+                                       restarted = 1;
+                                       goto restart;
+                               }
+                               ce->ce_flags &= ~CE_SKIP_WORKTREE;
                        }
-                       ce->ce_flags &= ~CE_SKIP_WORKTREE;
                }
        }
+
+       if (path_count[0])
+               trace2_data_intmax("index", istate->repo,
+                                  "sparse_path_count", path_count[0]);
+       if (restarted)
+               trace2_data_intmax("index", istate->repo,
+                                  "sparse_path_count_full", path_count[1]);
+       trace2_region_leave("index", "clear_skip_worktree_from_present_files",
+                           istate->repo);
 }
 
 /*
diff --git a/t/helper/test-cache-tree.c b/t/helper/test-cache-tree.c
new file mode 100644 (file)
index 0000000..93051b2
--- /dev/null
@@ -0,0 +1,64 @@
+#include "test-tool.h"
+#include "cache.h"
+#include "tree.h"
+#include "cache-tree.h"
+#include "parse-options.h"
+
+static char const * const test_cache_tree_usage[] = {
+       N_("test-tool cache-tree <options> (control|prime|update)"),
+       NULL
+};
+
+int cmd__cache_tree(int argc, const char **argv)
+{
+       struct object_id oid;
+       struct tree *tree;
+       int empty = 0;
+       int invalidate_qty = 0;
+       int i;
+
+       struct option options[] = {
+               OPT_BOOL(0, "empty", &empty,
+                        N_("clear the cache tree before each iteration")),
+               OPT_INTEGER_F(0, "invalidate", &invalidate_qty,
+                             N_("number of entries in the cache tree to invalidate (default 0)"),
+                             PARSE_OPT_NONEG),
+               OPT_END()
+       };
+
+       setup_git_directory();
+
+       argc = parse_options(argc, argv, NULL, options, test_cache_tree_usage, 0);
+
+       if (read_cache() < 0)
+               die(_("unable to read index file"));
+
+       oidcpy(&oid, &the_index.cache_tree->oid);
+       tree = parse_tree_indirect(&oid);
+       if (!tree)
+               die(_("not a tree object: %s"), oid_to_hex(&oid));
+
+       if (empty) {
+               /* clear the cache tree & allocate a new one */
+               cache_tree_free(&the_index.cache_tree);
+               the_index.cache_tree = cache_tree();
+       } else if (invalidate_qty) {
+               /* invalidate the specified number of unique paths */
+               float f_interval = (float)the_index.cache_nr / invalidate_qty;
+               int interval = f_interval < 1.0 ? 1 : (int)f_interval;
+               for (i = 0; i < invalidate_qty && i * interval < the_index.cache_nr; i++)
+                       cache_tree_invalidate_path(&the_index, the_index.cache[i * interval]->name);
+       }
+
+       if (argc != 1)
+               usage_with_options(test_cache_tree_usage, options);
+       else if (!strcmp(argv[0], "prime"))
+               prime_cache_tree(the_repository, &the_index, tree);
+       else if (!strcmp(argv[0], "update"))
+               cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+       /* use "control" subcommand to specify no-op */
+       else if (!!strcmp(argv[0], "control"))
+               die(_("Unhandled subcommand '%s'"), argv[0]);
+
+       return 0;
+}
index d860c387c3846d69b7bd63a144ede2f93da60886..71fe5c61455a89eddd6363a87e3c4eb7968f09b6 100644 (file)
@@ -5,3 +5,11 @@ int cmd__sha1(int ac, const char **av)
 {
        return cmd_hash_impl(ac, av, GIT_HASH_SHA1);
 }
+
+int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED)
+{
+#ifdef platform_SHA_IS_SHA1DC
+       return 0;
+#endif
+       return 1;
+}
index 01cda9358df01f50de95a93c8aee795696da377d..7eb1a26a305b89c3d45954a2d41c2f3ad5f82196 100644 (file)
@@ -14,6 +14,7 @@ static struct test_cmd cmds[] = {
        { "bitmap", cmd__bitmap },
        { "bloom", cmd__bloom },
        { "bundle-uri", cmd__bundle_uri },
+       { "cache-tree", cmd__cache_tree },
        { "chmtime", cmd__chmtime },
        { "config", cmd__config },
        { "crontab", cmd__crontab },
@@ -73,6 +74,7 @@ static struct test_cmd cmds[] = {
        { "scrap-cache-tree", cmd__scrap_cache_tree },
        { "serve-v2", cmd__serve_v2 },
        { "sha1", cmd__sha1 },
+       { "sha1-is-sha1dc", cmd__sha1_is_sha1dc },
        { "sha256", cmd__sha256 },
        { "sigchain", cmd__sigchain },
        { "simple-ipc", cmd__simple_ipc },
index ca2948066fd64ec4743e498fffd06829c2cfce2b..da7cd6351a6ea32a222f91229874016226e066de 100644 (file)
@@ -8,6 +8,7 @@ int cmd__advise_if_enabled(int argc, const char **argv);
 int cmd__bitmap(int argc, const char **argv);
 int cmd__bloom(int argc, const char **argv);
 int cmd__bundle_uri(int argc, const char **argv);
+int cmd__cache_tree(int argc, const char **argv);
 int cmd__chmtime(int argc, const char **argv);
 int cmd__config(int argc, const char **argv);
 int cmd__crontab(int argc, const char **argv);
@@ -66,6 +67,7 @@ int cmd__run_command(int argc, const char **argv);
 int cmd__scrap_cache_tree(int argc, const char **argv);
 int cmd__serve_v2(int argc, const char **argv);
 int cmd__sha1(int argc, const char **argv);
+int cmd__sha1_is_sha1dc(int argc, const char **argv);
 int cmd__oid_array(int argc, const char **argv);
 int cmd__sha256(int argc, const char **argv);
 int cmd__sigchain(int argc, const char **argv);
index c481c012d2fc17a7944f308c2d6ef68acb284dee..325566e18ebc7fa7359d079935d6d7f81cd4dc54 100755 (executable)
@@ -49,6 +49,14 @@ test_perf "read-tree br_base br_ballast ($nr_files)" '
        git read-tree -n -m br_base br_ballast
 '
 
+test_perf "read-tree br_ballast_plus_1 ($nr_files)" '
+       # Run read-tree 100 times for clearer performance results & comparisons
+       for i in  $(test_seq 100)
+       do
+               git read-tree -n -m br_ballast_plus_1 || return 1
+       done
+'
+
 test_perf "switch between br_base br_ballast ($nr_files)" '
        git checkout -q br_base &&
        git checkout -q br_ballast
diff --git a/t/perf/p0090-cache-tree.sh b/t/perf/p0090-cache-tree.sh
new file mode 100755 (executable)
index 0000000..a8eabca
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+test_description="Tests performance of cache tree update operations"
+
+. ./perf-lib.sh
+
+test_perf_large_repo
+test_checkout_worktree
+
+count=100
+
+test_expect_success 'setup cache tree' '
+       git write-tree
+'
+
+test_cache_tree () {
+       test_perf "$1, $3" "
+               for i in \$(test_seq $count)
+               do
+                       test-tool cache-tree $4 $2
+               done
+       "
+}
+
+test_cache_tree_update_functions () {
+       test_cache_tree 'no-op' 'control' "$1" "$2"
+       test_cache_tree 'prime_cache_tree' 'prime' "$1" "$2"
+       test_cache_tree 'cache_tree_update' 'update' "$1" "$2"
+}
+
+test_cache_tree_update_functions "clean" ""
+test_cache_tree_update_functions "invalidate 2" "--invalidate 2"
+test_cache_tree_update_functions "invalidate 50" "--invalidate 50"
+test_cache_tree_update_functions "empty" "--empty"
+
+test_done
diff --git a/t/perf/p7102-reset.sh b/t/perf/p7102-reset.sh
new file mode 100755 (executable)
index 0000000..9b039e8
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+test_description='performance of reset'
+. ./perf-lib.sh
+
+test_perf_default_repo
+test_checkout_worktree
+
+test_perf 'reset --hard with change in tree' '
+       base=$(git rev-parse HEAD) &&
+       test_commit --no-tag A &&
+       new=$(git rev-parse HEAD) &&
+
+       for i in $(test_seq 10)
+       do
+               git reset --hard $new &&
+               git reset --hard $base || return $?
+       done
+'
+
+test_done
index 9ad76080aa49d46d03e2bb805d039e6a88d87e5c..53240476896d8e80a969f1b9b448fd01b45fa711 100755 (executable)
@@ -6,9 +6,11 @@ TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 TEST_DATA="$TEST_DIRECTORY/t0013"
 
-if test -z "$DC_SHA1"
+test_lazy_prereq SHA1_IS_SHA1DC 'test-tool sha1-is-sha1dc'
+
+if ! test_have_prereq SHA1_IS_SHA1DC
 then
-       skip_all='skipping sha1 collision tests, DC_SHA1 not set'
+       skip_all='skipping sha1 collision tests, not using sha1collisiondetection'
        test_done
 fi
 
index 7b5423eebdafa4f35b90ebe6194683e59e8bb46c..e2411f6a9bd93bad152360b6997bb9785d55ef18 100755 (executable)
@@ -130,7 +130,8 @@ World
 EOF
 
 test_expect_success 'run_command runs in parallel with more jobs available than tasks' '
-       test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+       test-tool run-command run-command-parallel 5 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+       test_must_be_empty out &&
        test_cmp expect actual
 '
 
@@ -141,7 +142,8 @@ test_expect_success 'run_command runs ungrouped in parallel with more jobs avail
 '
 
 test_expect_success 'run_command runs in parallel with as many jobs as tasks' '
-       test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+       test-tool run-command run-command-parallel 4 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+       test_must_be_empty out &&
        test_cmp expect actual
 '
 
@@ -152,7 +154,8 @@ test_expect_success 'run_command runs ungrouped in parallel with as many jobs as
 '
 
 test_expect_success 'run_command runs in parallel with more tasks than jobs available' '
-       test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+       test-tool run-command run-command-parallel 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+       test_must_be_empty out &&
        test_cmp expect actual
 '
 
@@ -172,7 +175,8 @@ asking for a quick stop
 EOF
 
 test_expect_success 'run_command is asked to abort gracefully' '
-       test-tool run-command run-command-abort 3 false 2>actual &&
+       test-tool run-command run-command-abort 3 false >out 2>actual &&
+       test_must_be_empty out &&
        test_cmp expect actual
 '
 
@@ -187,7 +191,8 @@ no further jobs available
 EOF
 
 test_expect_success 'run_command outputs ' '
-       test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" 2>actual &&
+       test-tool run-command run-command-no-jobs 3 sh -c "printf \"%s\n%s\n\" Hello World" >out 2>actual &&
+       test_must_be_empty out &&
        test_cmp expect actual
 '
 
index a9953b6a71c360a0c39d058ba61f9ff026ec04bf..da539716359614f6d91cd1db896b3981e1805d6d 100755 (executable)
@@ -19,7 +19,7 @@ test_expect_success 'read-tree in partial clone prefetches in one batch' '
        git -C server config uploadpack.allowfilter 1 &&
        git -C server config uploadpack.allowanysha1inwant 1 &&
        git clone --bare --filter=blob:none "file://$(pwd)/server" client &&
-       GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE &&
+       GIT_TRACE_PACKET="$(pwd)/trace" git -C client read-tree $TREE $TREE &&
 
        # "done" marks the end of negotiation (once per fetch). Expect that
        # only one fetch occurs.
index 43fcb7c0bfc85e3d29455ec37cfbf437e00238a9..2ef3579fa7c23db5055c41e68438d39871bcf6e9 100755 (executable)
@@ -95,7 +95,7 @@ test_expect_success 'git hook run -- out-of-repo runs excluded' '
 test_expect_success 'git -c core.hooksPath=<PATH> hook run' '
        mkdir my-hooks &&
        write_script my-hooks/test-hook <<-\EOF &&
-       echo Hook ran $1 >>actual
+       echo Hook ran $1
        EOF
 
        cat >expect <<-\EOF &&
index 4f5abb5ad25e9d39fc85d4d20a4ab1d4905b61e2..462cefd25df3efd51b06023523530b3d97d3d3a9 100755 (executable)
@@ -1964,6 +1964,113 @@ test_expect_success 'respect user edits to update-ref steps' '
        test_cmp_rev HEAD refs/heads/no-conflict-branch
 '
 
+test_expect_success '--update-refs: all update-ref lines removed' '
+       git checkout -b test-refs-not-removed no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git branch -f tip &&
+
+       test_commit test-refs-not-removed &&
+       git commit --amend --fixup first &&
+
+       git rev-parse first second third tip no-conflict-branch >expect-oids &&
+
+       (
+               set_cat_todo_editor &&
+               test_must_fail git rebase -i --update-refs base >todo.raw &&
+               sed -e "/^update-ref/d" <todo.raw >todo
+       ) &&
+       (
+               set_replace_editor todo &&
+               git rebase -i --update-refs base
+       ) &&
+
+       # Ensure refs are not deleted and their OIDs have not changed
+       git rev-parse first second third tip no-conflict-branch >actual-oids &&
+       test_cmp expect-oids actual-oids
+'
+
+test_expect_success '--update-refs: all update-ref lines removed, then some re-added' '
+       git checkout -b test-refs-not-removed2 no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git branch -f tip &&
+
+       test_commit test-refs-not-removed2 &&
+       git commit --amend --fixup first &&
+
+       git rev-parse first second third >expect-oids &&
+
+       (
+               set_cat_todo_editor &&
+               test_must_fail git rebase -i \
+                       --autosquash --update-refs \
+                       base >todo.raw &&
+               sed -e "/^update-ref/d" <todo.raw >todo
+       ) &&
+
+       # Add a break to the end of the todo so we can edit later
+       echo "break" >>todo &&
+
+       (
+               set_replace_editor todo &&
+               git rebase -i --autosquash --update-refs base &&
+               echo "update-ref refs/heads/tip" >todo &&
+               git rebase --edit-todo &&
+               git rebase --continue
+       ) &&
+
+       # Ensure first/second/third are unchanged, but tip is updated
+       git rev-parse first second third >actual-oids &&
+       test_cmp expect-oids actual-oids &&
+       test_cmp_rev HEAD tip
+'
+
+test_expect_success '--update-refs: --edit-todo with no update-ref lines' '
+       git checkout -b test-refs-not-removed3 no-conflict-branch &&
+       git branch -f base HEAD~4 &&
+       git branch -f first HEAD~3 &&
+       git branch -f second HEAD~3 &&
+       git branch -f third HEAD~1 &&
+       git branch -f tip &&
+
+       test_commit test-refs-not-removed3 &&
+       git commit --amend --fixup first &&
+
+       git rev-parse first second third tip no-conflict-branch >expect-oids &&
+
+       (
+               set_cat_todo_editor &&
+               test_must_fail git rebase -i \
+                       --autosquash --update-refs \
+                       base >todo.raw &&
+               sed -e "/^update-ref/d" <todo.raw >todo
+       ) &&
+
+       # Add a break to the beginning of the todo so we can resume with no
+       # update-ref lines
+       echo "break" >todo.new &&
+       cat todo >>todo.new &&
+
+       (
+               set_replace_editor todo.new &&
+               git rebase -i --autosquash --update-refs base &&
+
+               # Make no changes when editing so update-refs is still empty
+               cat todo >todo.new &&
+               git rebase --edit-todo &&
+               git rebase --continue
+       ) &&
+
+       # Ensure refs are not deleted and their OIDs have not changed
+       git rev-parse first second third tip no-conflict-branch >actual-oids &&
+       test_cmp expect-oids actual-oids
+'
+
 test_expect_success '--update-refs: check failed ref update' '
        git checkout -B update-refs-error no-conflict-branch &&
        git branch -f base HEAD~4 &&
index 75da8acf8f436f5a50908f8b3a9e3fe194d1d440..b9546ef8e5e5cd3a734228c4d65ffdb59f568684 100755 (executable)
@@ -178,6 +178,7 @@ test_expect_success "submodule.recurse option triggers recursive fetch" '
 '
 
 test_expect_success "fetch --recurse-submodules -j2 has the same output behaviour" '
+       test_when_finished "rm -f trace.out" &&
        add_submodule_commits &&
        (
                cd downstream &&
@@ -705,15 +706,22 @@ test_expect_success "'fetch.recurseSubmodules=on-demand' works also without .git
 
 test_expect_success 'fetching submodules respects parallel settings' '
        git config fetch.recurseSubmodules true &&
+       test_when_finished "rm -f downstream/trace.out" &&
        (
                cd downstream &&
                GIT_TRACE=$(pwd)/trace.out git fetch &&
                grep "1 tasks" trace.out &&
+               >trace.out &&
+
                GIT_TRACE=$(pwd)/trace.out git fetch --jobs 7 &&
                grep "7 tasks" trace.out &&
+               >trace.out &&
+
                git config submodule.fetchJobs 8 &&
                GIT_TRACE=$(pwd)/trace.out git fetch &&
                grep "8 tasks" trace.out &&
+               >trace.out &&
+
                GIT_TRACE=$(pwd)/trace.out git fetch --jobs 9 &&
                grep "9 tasks" trace.out &&
                >trace.out &&
index 8c37bceb336344f9b10878faf9cabf933dcb8ea2..d72cef88264ec3dff713b12253df7a6dd5a4724e 100755 (executable)
@@ -60,8 +60,8 @@ test_expect_success 'checking the commit' '
 
 test_expect_success 'mv --dry-run does not move file' '
        git mv -n path0/COPYING MOVED &&
-       test -f path0/COPYING &&
-       test ! -f MOVED
+       test_path_is_file path0/COPYING &&
+       test_path_is_missing MOVED
 '
 
 test_expect_success 'checking -k on non-existing file' '
@@ -71,25 +71,25 @@ test_expect_success 'checking -k on non-existing file' '
 test_expect_success 'checking -k on untracked file' '
        >untracked1 &&
        git mv -k untracked1 path0 &&
-       test -f untracked1 &&
-       test ! -f path0/untracked1
+       test_path_is_file untracked1 &&
+       test_path_is_missing path0/untracked1
 '
 
 test_expect_success 'checking -k on multiple untracked files' '
        >untracked2 &&
        git mv -k untracked1 untracked2 path0 &&
-       test -f untracked1 &&
-       test -f untracked2 &&
-       test ! -f path0/untracked1 &&
-       test ! -f path0/untracked2
+       test_path_is_file untracked1 &&
+       test_path_is_file untracked2 &&
+       test_path_is_missing path0/untracked1 &&
+       test_path_is_missing path0/untracked2
 '
 
 test_expect_success 'checking -f on untracked file with existing target' '
        >path0/untracked1 &&
        test_must_fail git mv -f untracked1 path0 &&
-       test ! -f .git/index.lock &&
-       test -f untracked1 &&
-       test -f path0/untracked1
+       test_path_is_missing .git/index.lock &&
+       test_path_is_file untracked1 &&
+       test_path_is_file path0/untracked1
 '
 
 # clean up the mess in case bad things happen
@@ -215,8 +215,8 @@ test_expect_success 'absolute pathname' '
                git add sub/file &&
 
                git mv sub "$(pwd)/in" &&
-               ! test -d sub &&
-               test -d in &&
+               test_path_is_missing sub &&
+               test_path_is_dir in &&
                git ls-files --error-unmatch in/file
        )
 '
@@ -234,8 +234,8 @@ test_expect_success 'absolute pathname outside should fail' '
                git add sub/file &&
 
                test_must_fail git mv sub "$out/out" &&
-               test -d sub &&
-               ! test -d ../in &&
+               test_path_is_dir sub &&
+               test_path_is_missing ../in &&
                git ls-files --error-unmatch sub/file
        )
 '
@@ -295,8 +295,8 @@ test_expect_success 'git mv should overwrite symlink to a file' '
        git add moved &&
        test_must_fail git mv moved symlink &&
        git mv -f moved symlink &&
-       ! test -e moved &&
-       test -f symlink &&
+       test_path_is_missing moved &&
+       test_path_is_file symlink &&
        test "$(cat symlink)" = 1 &&
        git update-index --refresh &&
        git diff-files --quiet
@@ -312,13 +312,13 @@ test_expect_success 'git mv should overwrite file with a symlink' '
        git add moved &&
        test_must_fail git mv symlink moved &&
        git mv -f symlink moved &&
-       ! test -e symlink &&
+       test_path_is_missing symlink &&
        git update-index --refresh &&
        git diff-files --quiet
 '
 
 test_expect_success SYMLINKS 'check moved symlink' '
-       test -h moved
+       test_path_is_symlink moved
 '
 
 rm -f moved symlink
@@ -352,7 +352,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and no .gitm
        ) &&
        mkdir mod &&
        git mv sub mod/sub &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
@@ -372,7 +372,7 @@ test_expect_success 'git mv moves a submodule with a .git directory and .gitmodu
        ) &&
        mkdir mod &&
        git mv sub mod/sub &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        echo mod/sub >expected &&
@@ -389,7 +389,7 @@ test_expect_success 'git mv moves a submodule with gitfile' '
        entry="$(git ls-files --stage sub | cut -f 1)" &&
        mkdir mod &&
        git -C mod mv ../sub/ . &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        echo mod/sub >expected &&
@@ -408,7 +408,7 @@ test_expect_success 'mv does not complain when no .gitmodules file is found' '
        mkdir mod &&
        git mv sub mod/sub 2>actual.err &&
        test_must_be_empty actual.err &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
@@ -423,13 +423,13 @@ test_expect_success 'mv will error out on a modified .gitmodules file unless sta
        entry="$(git ls-files --stage sub | cut -f 1)" &&
        mkdir mod &&
        test_must_fail git mv sub mod/sub 2>actual.err &&
-       test -s actual.err &&
-       test -e sub &&
+       test_file_not_empty actual.err &&
+       test_path_exists sub &&
        git diff-files --quiet -- sub &&
        git add .gitmodules &&
        git mv sub mod/sub 2>actual.err &&
        test_must_be_empty actual.err &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
@@ -447,7 +447,7 @@ test_expect_success 'mv issues a warning when section is not found in .gitmodule
        mkdir mod &&
        git mv sub mod/sub 2>actual.err &&
        test_cmp expect.err actual.err &&
-       ! test -e sub &&
+       test_path_is_missing sub &&
        test "$entry" = "$(git ls-files --stage mod/sub | cut -f 1)" &&
        git -C mod/sub status &&
        git update-index --refresh &&
@@ -460,7 +460,7 @@ test_expect_success 'mv --dry-run does not touch the submodule or .gitmodules' '
        git submodule update &&
        mkdir mod &&
        git mv -n sub mod/sub 2>actual.err &&
-       test -f sub/.git &&
+       test_path_is_file sub/.git &&
        git diff-index --exit-code HEAD &&
        git update-index --refresh &&
        git diff-files --quiet -- sub .gitmodules
@@ -474,10 +474,10 @@ test_expect_success 'checking out a commit before submodule moved needs manual u
        git status -s sub2 >actual &&
        echo "?? sub2/" >expected &&
        test_cmp expected actual &&
-       ! test -f sub/.git &&
-       test -f sub2/.git &&
+       test_path_is_missing sub/.git &&
+       test_path_is_file sub2/.git &&
        git submodule update &&
-       test -f sub/.git &&
+       test_path_is_file sub/.git &&
        rm -rf sub2 &&
        git diff-index --exit-code HEAD &&
        git update-index --refresh &&
index 5be483bf887cc60a1c967196ccfa7584f363bc6e..c630e0d52da2e0671004ddba47b2d8f5b363eb00 100755 (executable)
@@ -543,4 +543,125 @@ test_expect_success '-n overrides repack.updateServerInfo=true' '
        test_server_info_missing
 '
 
+test_expect_success '--expire-to stores pruned objects (now)' '
+       git init expire-to-now &&
+       (
+               cd expire-to-now &&
+
+               git branch -M main &&
+
+               test_commit base &&
+
+               git checkout -b cruft &&
+               test_commit --no-tag cruft &&
+
+               git rev-list --objects --no-object-names main..cruft >moved.raw &&
+               sort moved.raw >moved.want &&
+
+               git rev-list --all --objects --no-object-names >expect.raw &&
+               sort expect.raw >expect &&
+
+               git checkout main &&
+               git branch -D cruft &&
+               git reflog expire --all --expire=all &&
+
+               git init --bare expired.git &&
+               git repack -d \
+                       --cruft --cruft-expiration="now" \
+                       --expire-to="expired.git/objects/pack/pack" &&
+
+               expired="$(ls expired.git/objects/pack/pack-*.idx)" &&
+               test_path_is_file "${expired%.idx}.mtimes" &&
+
+               # Since the `--cruft-expiration` is "now", the effective
+               # behavior is to move _all_ unreachable objects out to
+               # the location in `--expire-to`.
+               git show-index <$expired >expired.raw &&
+               cut -d" " -f2 expired.raw | sort >expired.objects &&
+               git rev-list --all --objects --no-object-names \
+                       >remaining.objects &&
+
+               # ...in other words, the combined contents of this
+               # repository and expired.git should be the same as the
+               # set of objects we started with.
+               cat expired.objects remaining.objects | sort >actual &&
+               test_cmp expect actual &&
+
+               # The "moved" objects (i.e., those in expired.git)
+               # should be the same as the cruft objects which were
+               # expired in the previous step.
+               test_cmp moved.want expired.objects
+       )
+'
+
+test_expect_success '--expire-to stores pruned objects (5.minutes.ago)' '
+       git init expire-to-5.minutes.ago &&
+       (
+               cd expire-to-5.minutes.ago &&
+
+               git branch -M main &&
+
+               test_commit base &&
+
+               # Create two classes of unreachable objects, one which
+               # is older than 5 minutes (stale), and another which is
+               # newer (recent).
+               for kind in stale recent
+               do
+                       git checkout -b $kind main &&
+                       test_commit --no-tag $kind || return 1
+               done &&
+
+               git rev-list --objects --no-object-names main..stale >in &&
+               stale="$(git pack-objects $objdir/pack/pack <in)" &&
+               mtime="$(test-tool chmtime --get =-600 $objdir/pack/pack-$stale.pack)" &&
+
+               # expect holds the set of objects we expect to find in
+               # this repository after repacking
+               git rev-list --objects --no-object-names recent >expect.raw &&
+               sort expect.raw >expect &&
+
+               # moved.want holds the set of objects we expect to find
+               # in expired.git
+               git rev-list --objects --no-object-names main..stale >out &&
+               sort out >moved.want &&
+
+               git checkout main &&
+               git branch -D stale recent &&
+               git reflog expire --all --expire=all &&
+               git prune-packed &&
+
+               git init --bare expired.git &&
+               git repack -d \
+                       --cruft --cruft-expiration=5.minutes.ago \
+                       --expire-to="expired.git/objects/pack/pack" &&
+
+               # Some of the remaining objects in this repository are
+               # unreachable, so use `cat-file --batch-all-objects`
+               # instead of `rev-list` to get their names
+               git cat-file --batch-all-objects --batch-check="%(objectname)" \
+                       >remaining.objects &&
+               sort remaining.objects >actual &&
+               test_cmp expect actual &&
+
+               (
+                       cd expired.git &&
+
+                       expired="$(ls objects/pack/pack-*.mtimes)" &&
+                       test-tool pack-mtimes $(basename $expired) >out &&
+                       cut -d" " -f1 out | sort >../moved.got &&
+
+                       # Ensure that there are as many objects with the
+                       # expected mtime as were moved to expired.git.
+                       #
+                       # In other words, ensure that the recorded
+                       # mtimes of any moved objects was written
+                       # correctly.
+                       grep " $mtime$" out >matching &&
+                       test_line_count = $(wc -l <../moved.want) matching
+               ) &&
+               test_cmp moved.want moved.got
+       )
+'
+
 test_done
index bae812156c4fedb8e296e422d4cb6a8af1a2dada..8a762aa0772eb4f7e107da6807092fe0a2be1a61 100644 (file)
@@ -2043,7 +2043,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
                if (!ret) {
                        if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
                                cache_tree_verify(the_repository, &o->result);
-                       if (!cache_tree_fully_valid(o->result.cache_tree))
+                       if (!o->skip_cache_tree_update &&
+                           !cache_tree_fully_valid(o->result.cache_tree))
                                cache_tree_update(&o->result,
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
index efb9edfbb2717b4739247ecdd58a104e1d44cfd2..6ab0d74c84dc5ca3004e8b3b160dde98d1805e5d 100644 (file)
@@ -71,7 +71,8 @@ struct unpack_trees_options {
                     quiet,
                     exiting_early,
                     show_all_errors,
-                    dry_run;
+                    dry_run,
+                    skip_cache_tree_update;
        enum unpack_trees_reset_type reset;
        const char *prefix;
        int cache_bottom;