summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml42
-rw-r--r--Documentation/CodingGuidelines12
-rw-r--r--Documentation/RelNotes/2.27.0.txt24
-rw-r--r--Documentation/git-bugreport.txt1
-rw-r--r--Documentation/git-credential.txt34
-rw-r--r--Documentation/gitcredentials.txt26
-rw-r--r--Documentation/gitfaq.txt18
-rw-r--r--bloom.c4
-rw-r--r--bloom.h2
-rw-r--r--bugreport.c52
-rw-r--r--builtin/am.c3
-rw-r--r--builtin/commit.c3
-rw-r--r--builtin/fetch.c11
-rw-r--r--builtin/merge.c3
-rw-r--r--builtin/pack-objects.c1
-rw-r--r--builtin/prune.c1
-rw-r--r--builtin/rebase.c3
-rw-r--r--builtin/receive-pack.c3
-rw-r--r--builtin/repack.c1
-rw-r--r--builtin/rev-parse.c1
-rw-r--r--builtin/submodule--helper.c32
-rwxr-xr-xci/config/allow-refs.sample26
-rw-r--r--commit-graph.c1
-rw-r--r--commit.c16
-rw-r--r--commit.h50
-rw-r--r--credential.h8
-rw-r--r--environment.c1
-rw-r--r--fetch-pack.c3
-rwxr-xr-xgit-bisect.sh2
-rwxr-xr-xgit-submodule.sh22
-rw-r--r--git.c1
-rw-r--r--list-objects-filter.c3
-rw-r--r--pack-bitmap.c72
-rw-r--r--run-command.c13
-rw-r--r--run-command.h5
-rw-r--r--send-pack.c1
-rw-r--r--sequencer.c7
-rw-r--r--shallow.c36
-rw-r--r--shallow.h81
-rw-r--r--t/helper/test-bloom.c2
-rwxr-xr-xt/perf/p5310-pack-bitmaps.sh10
-rwxr-xr-xt/t0091-bugreport.sh15
-rwxr-xr-xt/t0095-bloom.sh2
-rwxr-xr-xt/t3415-rebase-autosquash.sh16
-rwxr-xr-xt/t4216-log-bloom.sh2
-rwxr-xr-xt/t5616-partial-clone.sh7
-rwxr-xr-xt/t6030-bisect-porcelain.sh7
-rwxr-xr-xt/t6113-rev-list-bitmap-filters.sh21
-rw-r--r--unpack-trees.c10
-rw-r--r--upload-pack.c35
50 files changed, 570 insertions, 182 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index fd4df939b5..802a4bf7cd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -6,7 +6,39 @@ env:
DEVELOPER: 1
jobs:
+ ci-config:
+ runs-on: ubuntu-latest
+ outputs:
+ enabled: ${{ steps.check-ref.outputs.enabled }}
+ steps:
+ - name: try to clone ci-config branch
+ continue-on-error: true
+ run: |
+ git -c protocol.version=2 clone \
+ --no-tags \
+ --single-branch \
+ -b ci-config \
+ --depth 1 \
+ --no-checkout \
+ --filter=blob:none \
+ https://github.com/${{ github.repository }} \
+ config-repo &&
+ cd config-repo &&
+ git checkout HEAD -- ci/config
+ - id: check-ref
+ name: check whether CI is enabled for ref
+ run: |
+ enabled=yes
+ if test -x config-repo/ci/config/allow-ref &&
+ ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+ then
+ enabled=no
+ fi
+ echo "::set-output name=enabled::$enabled"
+
windows-build:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
runs-on: windows-latest
steps:
- uses: actions/checkout@v1
@@ -70,6 +102,8 @@ jobs:
name: failed-tests-windows
path: ${{env.FAILED_TEST_ARTIFACTS}}
vs-build:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
env:
MSYSTEM: MINGW64
NO_PERL: 1
@@ -154,6 +188,8 @@ jobs:
${{matrix.nr}} 10 t[0-9]*.sh)
"@
regular:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
strategy:
matrix:
vector:
@@ -189,6 +225,8 @@ jobs:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
dockerized:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
strategy:
matrix:
vector:
@@ -213,6 +251,8 @@ jobs:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
static-analysis:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
env:
jobname: StaticAnalysis
runs-on: ubuntu-latest
@@ -221,6 +261,8 @@ jobs:
- run: ci/install-dependencies.sh
- run: ci/run-static-analysis.sh
documentation:
+ needs: ci-config
+ if: needs.ci-config.outputs.enabled == 'yes'
env:
jobname: Documentation
runs-on: ubuntu-latest
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
index a89e8dcfbc..227f46ae40 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -232,6 +232,18 @@ For C programs:
while( condition )
func (bar+1);
+ - Do not explicitly compare an integral value with constant 0 or '\0',
+ or a pointer value with constant NULL. For instance, to validate that
+ counted array <ptr, cnt> is initialized but has no elements, write:
+
+ if (!ptr || cnt)
+ BUG("empty array expected");
+
+ and not:
+
+ if (ptr == NULL || cnt != 0);
+ BUG("empty array expected");
+
- We avoid using braces unnecessarily. I.e.
if (bla) {
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.txt
index 2a8c6e8f28..b398961c8a 100644
--- a/Documentation/RelNotes/2.27.0.txt
+++ b/Documentation/RelNotes/2.27.0.txt
@@ -161,6 +161,12 @@ Performance, Internal Implementation, Development Support etc.
* The "bugreport" tool has been added.
+ * The object walk with object filter "--filter=tree:0" can now take
+ advantage of the pack bitmap when available.
+
+ * Instead of always building all branches at GitHub via Actions,
+ users can specify which branches to build.
+
Fixes since v2.26
-----------------
@@ -420,6 +426,24 @@ Fixes since v2.26
been corrected.
(merge 0555e4af58 cb/t0000-use-the-configured-shell later to maint).
+ * Minor in-code comments and documentation updates around credential
+ API.
+ (merge 1aed817f99 cb/credential-doc-fixes later to maint).
+
+ * Teach "am", "commit", "merge" and "rebase", when they are run with
+ the "--quiet" option, to pass "--quiet" down to "gc --auto".
+ (merge 7c3e9e8cfb jc/auto-gc-quiet later to maint).
+
+ * The code to skip unmerged paths in the index when sparse checkout
+ is in use would have made out-of-bound access of the in-core index
+ when the last path was unmerged, which has been corrected.
+
+ * Serving a "git fetch" client over "git://" and "ssh://" protocols
+ using the on-wire protocol version 2 was buggy on the server end
+ when the client needs to make a follow-up request to
+ e.g. auto-follow tags.
+ (merge 08450ef791 cc/upload-pack-v2-fetch-fix later to maint).
+
* Other code cleanup, docfix, build fix, etc.
(merge 564956f358 jc/maintain-doc later to maint).
(merge 7422b2a0a1 sg/commit-slab-clarify-peek later to maint).
diff --git a/Documentation/git-bugreport.txt b/Documentation/git-bugreport.txt
index 643d1b2884..7fe9aef34e 100644
--- a/Documentation/git-bugreport.txt
+++ b/Documentation/git-bugreport.txt
@@ -28,6 +28,7 @@ The following information is captured automatically:
- 'git version --build-options'
- uname sysname, release, version, and machine strings
- Compiler-specific info string
+ - A list of enabled hooks
This tool is invoked via the typical Git setup process, which means that in some
cases, it might not be able to launch - for example, if a relevant config file
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index 6f0c7ca80f..8d990e92fd 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -103,17 +103,20 @@ INPUT/OUTPUT FORMAT
`git credential` reads and/or writes (depending on the action used)
credential information in its standard input/output. This information
can correspond either to keys for which `git credential` will obtain
-the login/password information (e.g. host, protocol, path), or to the
-actual credential data to be obtained (login/password).
+the login information (e.g. host, protocol, path), or to the actual
+credential data to be obtained (username/password).
The credential is split into a set of named attributes, with one
-attribute per line. Each attribute is
-specified by a key-value pair, separated by an `=` (equals) sign,
-followed by a newline. The key may contain any bytes except `=`,
-newline, or NUL. The value may contain any bytes except newline or NUL.
+attribute per line. Each attribute is specified by a key-value pair,
+separated by an `=` (equals) sign, followed by a newline.
+
+The key may contain any bytes except `=`, newline, or NUL. The value may
+contain any bytes except newline or NUL.
+
In both cases, all bytes are treated as-is (i.e., there is no quoting,
and one cannot transmit a value with newline or NUL in it). The list of
attributes is terminated by a blank line or end-of-file.
+
Git understands the following attributes:
`protocol`::
@@ -123,7 +126,8 @@ Git understands the following attributes:
`host`::
- The remote hostname for a network credential.
+ The remote hostname for a network credential. This includes
+ the port number if one was specified (e.g., "example.com:8088").
`path`::
@@ -134,7 +138,7 @@ Git understands the following attributes:
`username`::
The credential's username, if we already have one (e.g., from a
- URL, from the user, or from a previously run helper).
+ URL, the configuration, the user, or from a previously run helper).
`password`::
@@ -146,8 +150,12 @@ Git understands the following attributes:
value is parsed as a URL and treated as if its constituent parts
were read (e.g., `url=https://example.com` would behave as if
`protocol=https` and `host=example.com` had been provided). This
- can help callers avoid parsing URLs themselves. Note that any
- components which are missing from the URL (e.g., there is no
- username in the example above) will be set to empty; if you want
- to provide a URL and override some attributes, provide the URL
- attribute first, followed by any overrides.
+ can help callers avoid parsing URLs themselves.
+
+ Note that specifying a protocol is mandatory and if the URL
+ doesn't specify a hostname (e.g., "cert:///path/to/file") the
+ credential will contain a hostname attribute whose value is an
+ empty string.
+
+ Components which are missing from the URL (e.g., there is no
+ username in the example above) will be left unset.
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 0d0f7149bd..9e481aec85 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -268,16 +268,26 @@ For a `get` operation, the helper should produce a list of attributes on
stdout in the same format (see linkgit:git-credential[1] for common
attributes). A helper is free to produce a subset, or even no values at
all if it has nothing useful to provide. Any provided attributes will
-overwrite those already known about by Git. If a helper outputs a
-`quit` attribute with a value of `true` or `1`, no further helpers will
-be consulted, nor will the user be prompted (if no credential has been
-provided, the operation will then fail).
+overwrite those already known about by Git's credential subsystem.
+
+While it is possible to override all attributes, well behaving helpers
+should refrain from doing so for any attribute other than username and
+password.
+
+If a helper outputs a `quit` attribute with a value of `true` or `1`,
+no further helpers will be consulted, nor will the user be prompted
+(if no credential has been provided, the operation will then fail).
+
+Similarly, no more helpers will be consulted once both username and
+password had been provided.
For a `store` or `erase` operation, the helper's output is ignored.
-If it fails to perform the requested operation, it may complain to
-stderr to inform the user. If it does not support the requested
-operation (e.g., a read-only store), it should silently ignore the
-request.
+
+If a helper fails to perform the requested operation or needs to notify
+the user of a potential issue, it may write to stderr.
+
+If it does not support the requested operation (e.g., a read-only store),
+it should silently ignore the request.
If a helper receives any other operation, it should silently ignore the
request. This leaves room for future operations to be added (older
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 1cf83df118..370d62dae4 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -223,6 +223,24 @@ a file checked into the repository which is a template or set of defaults which
can then be copied alongside and modified as appropriate. This second, modified
file is usually ignored to prevent accidentally committing it.
+[[files-in-.gitignore-are-tracked]]
+I asked Git to ignore various files, yet they are still tracked::
+ A `gitignore` file ensures that certain file(s) which are not
+ tracked by Git remain untracked. However, sometimes particular
+ file(s) may have been tracked before adding them into the
+ `.gitignore`, hence they still remain tracked. To untrack and
+ ignore files/patterns, use `git rm --cached <file/pattern>`
+ and add a pattern to `.gitignore` that matches the <file>.
+ See linkgit:gitignore[5] for details.
+
+[[fetching-and-pulling]]
+How do I know if I want to do a fetch or a pull?::
+ A fetch stores a copy of the latest changes from the remote
+ repository, without modifying the working tree or current branch.
+ You can then at your leisure inspect, merge, rebase on top of, or
+ ignore the upstream changes. A pull consists of a fetch followed
+ immediately by either a merge or rebase. See linkgit:git-pull[1].
+
Hooks
-----
diff --git a/bloom.c b/bloom.c
index dd9bab9bbd..ee025e0c61 100644
--- a/bloom.c
+++ b/bloom.c
@@ -9,7 +9,7 @@
define_commit_slab(bloom_filter_slab, struct bloom_filter);
-struct bloom_filter_slab bloom_filters;
+static struct bloom_filter_slab bloom_filters;
struct pathmap_hash_entry {
struct hashmap_entry entry;
@@ -273,4 +273,4 @@ int bloom_filter_contains(const struct bloom_filter *filter,
}
return 1;
-} \ No newline at end of file
+}
diff --git a/bloom.h b/bloom.h
index b935186425..e0e59e0754 100644
--- a/bloom.h
+++ b/bloom.h
@@ -87,4 +87,4 @@ int bloom_filter_contains(const struct bloom_filter *filter,
const struct bloom_key *key,
const struct bloom_filter_settings *settings);
-#endif \ No newline at end of file
+#endif
diff --git a/bugreport.c b/bugreport.c
index acacca8fef..aa8a489c35 100644
--- a/bugreport.c
+++ b/bugreport.c
@@ -3,6 +3,8 @@
#include "strbuf.h"
#include "help.h"
#include "compat/compiler.h"
+#include "run-command.h"
+
static void get_system_info(struct strbuf *sys_info)
{
@@ -31,6 +33,53 @@ static void get_system_info(struct strbuf *sys_info)
get_libc_info(sys_info);
}
+static void get_populated_hooks(struct strbuf *hook_info, int nongit)
+{
+ /*
+ * NEEDSWORK: Doesn't look like there is a list of all possible hooks;
+ * so below is a transcription of `git help hooks`. Later, this should
+ * be replaced with some programmatically generated list (generated from
+ * doc or else taken from some library which tells us about all the
+ * hooks)
+ */
+ static const char *hook[] = {
+ "applypatch-msg",
+ "pre-applypatch",
+ "post-applypatch",
+ "pre-commit",
+ "pre-merge-commit",
+ "prepare-commit-msg",
+ "commit-msg",
+ "post-commit",
+ "pre-rebase",
+ "post-checkout",
+ "post-merge",
+ "pre-push",
+ "pre-receive",
+ "update",
+ "post-receive",
+ "post-update",
+ "push-to-checkout",
+ "pre-auto-gc",
+ "post-rewrite",
+ "sendemail-validate",
+ "fsmonitor-watchman",
+ "p4-pre-submit",
+ "post-index-change",
+ };
+ int i;
+
+ if (nongit) {
+ strbuf_addstr(hook_info,
+ _("not run from a git repository - no hooks to show\n"));
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hook); i++)
+ if (find_hook(hook[i]))
+ strbuf_addf(hook_info, "%s\n", hook[i]);
+}
+
static const char * const bugreport_usage[] = {
N_("git bugreport [-o|--output-directory <file>] [-s|--suffix <format>]"),
NULL
@@ -114,6 +163,9 @@ int cmd_main(int argc, const char **argv)
get_header(&buffer, _("System Info"));
get_system_info(&buffer);
+ get_header(&buffer, _("Enabled Hooks"));
+ get_populated_hooks(&buffer, nongit_ok);
+
/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
report = open(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
diff --git a/builtin/am.c b/builtin/am.c
index e3dfd93c25..69e50de018 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1691,7 +1691,6 @@ static int do_interactive(struct am_state *state)
*/
static void am_run(struct am_state *state, int resume)
{
- const char *argv_gc_auto[] = {"gc", "--auto", NULL};
struct strbuf sb = STRBUF_INIT;
unlink(am_path(state, "dirtyindex"));
@@ -1796,7 +1795,7 @@ next:
if (!state->rebasing) {
am_destroy(state);
close_object_store(the_repository->objects);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(state->quiet);
}
}
diff --git a/builtin/commit.c b/builtin/commit.c
index a73de0a4c5..d1b7396052 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -1494,7 +1494,6 @@ static int git_commit_config(const char *k, const char *v, void *cb)
int cmd_commit(int argc, const char **argv, const char *prefix)
{
- const char *argv_gc_auto[] = {"gc", "--auto", NULL};
static struct wt_status s;
static struct option builtin_commit_options[] = {
OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
@@ -1703,7 +1702,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
git_test_write_commit_graph_or_die();
repo_rerere(the_repository, 0);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(quiet);
run_commit_hook(use_editor, get_index_file(), "post-commit", NULL);
if (amend && !no_post_rewrite) {
commit_post_rewrite(the_repository, current_head, &oid);
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 3ae52c015d..b5788c16bf 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -27,6 +27,7 @@
#include "branch.h"
#include "promisor-remote.h"
#include "commit-graph.h"
+#include "shallow.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -1752,7 +1753,6 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
struct remote *remote = NULL;
int result = 0;
int prune_tags_ok = 1;
- struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
packet_trace_identity("fetch");
@@ -1879,13 +1879,8 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
close_object_store(the_repository->objects);
- if (enable_auto_gc) {
- argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
- if (verbosity < 0)
- argv_array_push(&argv_gc_auto, "--quiet");
- run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);
- argv_array_clear(&argv_gc_auto);
- }
+ if (enable_auto_gc)
+ run_auto_gc(verbosity < 0);
return result;
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 923e32acf1..ca6a5dc4bf 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -450,7 +450,6 @@ static void finish(struct commit *head_commit,
if (verbosity >= 0 && !merge_msg.len)
printf(_("No merge message -- not updating HEAD\n"));
else {
- const char *argv_gc_auto[] = { "gc", "--auto", NULL };
update_ref(reflog_message.buf, "HEAD", new_head, head,
0, UPDATE_REFS_DIE_ON_ERR);
/*
@@ -458,7 +457,7 @@ static void finish(struct commit *head_commit,
* user should see them.
*/
close_object_store(the_repository->objects);
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(verbosity < 0);
}
}
if (new_head && show_diffstat) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 03b85f5166..c5b433a23f 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -34,6 +34,7 @@
#include "dir.h"
#include "midx.h"
#include "trace2.h"
+#include "shallow.h"
#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
#define SIZE(obj) oe_size(&to_pack, obj)
diff --git a/builtin/prune.c b/builtin/prune.c
index fd9acc7222..02c6ab7cba 100644
--- a/builtin/prune.c
+++ b/builtin/prune.c
@@ -8,6 +8,7 @@
#include "progress.h"
#include "prune-packed.h"
#include "object-store.h"
+#include "shallow.h"
static const char * const prune_usage[] = {
N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"),
diff --git a/builtin/rebase.c b/builtin/rebase.c
index ca6aa0dc7a..37ba76ac3d 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -722,7 +722,6 @@ static int rebase_write_basic_state(struct rebase_options *opts)
static int finish_rebase(struct rebase_options *opts)
{
struct strbuf dir = STRBUF_INIT;
- const char *argv_gc_auto[] = { "gc", "--auto", NULL };
int ret = 0;
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);
@@ -732,7 +731,7 @@ static int finish_rebase(struct rebase_options *opts)
* We ignore errors in 'gc --auto', since the
* user should see them.
*/
- run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+ run_auto_gc(!(opts->flags & (REBASE_NO_QUIET|REBASE_VERBOSE)));
if (opts->type == REBASE_MERGE) {
struct replay_opts replay = REPLAY_OPTS_INIT;
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index d37ab776b3..ea3d0f01af 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -28,6 +28,7 @@
#include "protocol.h"
#include "commit-reach.h"
#include "worktree.h"
+#include "shallow.h"
static const char * const receive_pack_usage[] = {
N_("git receive-pack <git-dir>"),
@@ -876,7 +877,7 @@ static void refuse_unconfigured_deny_delete_current(void)
static int command_singleton_iterator(void *cb_data, struct object_id *oid);
static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
{
- struct lock_file shallow_lock = LOCK_INIT;
+ struct shallow_lock shallow_lock = SHALLOW_LOCK_INIT;
struct oid_array extra = OID_ARRAY_INIT;
struct check_connected_options opt = CHECK_CONNECTED_INIT;
uint32_t mask = 1 << (cmd->index % 32);
diff --git a/builtin/repack.c b/builtin/repack.c
index 1b686ee9ce..df287739d9 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -13,6 +13,7 @@
#include "prune-packed.h"
#include "object-store.h"
#include "promisor-remote.h"
+#include "shallow.h"
static int delta_base_offset = 1;
static int pack_kept_objects = -1;
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 06056434ed..669dd2fd6f 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -16,6 +16,7 @@
#include "split-index.h"
#include "submodule.h"
#include "commit-reach.h"
+#include "shallow.h"
#define DO_REVS 1
#define DO_NOREV 2
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 1a4b391c88..46c03d2a12 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -2246,6 +2246,37 @@ static int module_config(int argc, const char **argv, const char *prefix)
usage_with_options(git_submodule_helper_usage, module_config_options);
}
+static int module_set_url(int argc, const char **argv, const char *prefix)
+{
+ int quiet = 0;
+ const char *newurl;
+ const char *path;
+ char *config_name;
+
+ struct option options[] = {
+ OPT__QUIET(&quiet, N_("Suppress output for setting url of a submodule")),
+ OPT_END()
+ };
+ const char *const usage[] = {
+ N_("git submodule--helper set-url [--quiet] <path> <newurl>"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+ if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
+ usage_with_options(usage, options);
+
+ config_name = xstrfmt("submodule.%s.url", path);
+
+ config_set_in_gitmodules_file_gently(config_name, newurl);
+ sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+
+ free(config_name);
+
+ return 0;
+}
+
#define SUPPORT_SUPER_PREFIX (1<<0)
struct cmd_struct {
@@ -2276,6 +2307,7 @@ static struct cmd_struct commands[] = {
{"is-active", is_active, 0},
{"check-name", check_name, 0},
{"config", module_config, 0},
+ {"set-url", module_set_url, 0},
};
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --git a/ci/config/allow-refs.sample b/ci/config/allow-refs.sample
new file mode 100755
index 0000000000..f157f1945a
--- /dev/null
+++ b/ci/config/allow-refs.sample
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Sample script for enabling/disabling GitHub Actions CI runs on
+# particular refs. By default, CI is run for all branches pushed to
+# GitHub. You can override this by dropping the ".sample" from the script,
+# editing it, committing, and pushing the result to the "ci-config" branch of
+# your repository:
+#
+# git checkout -b ci-config
+# cp allow-refs.sample allow-refs
+# $EDITOR allow-refs
+# git commit -am "implement my ci preferences"
+# git push
+#
+# This script will then be run when any refs are pushed to that repository. It
+# gets the fully qualified refname as the first argument, and should exit with
+# success only for refs for which you want to run CI.
+
+case "$1" in
+# allow one-off tests by pushing to "for-ci" or "for-ci/mybranch"
+refs/heads/for-ci*) true ;;
+# always build your integration branch
+refs/heads/my-integration-branch) true ;;
+# don't build any other branches or tags
+*) false ;;
+esac
diff --git a/commit-graph.c b/commit-graph.c
index 5ea0c8e15c..e3420ddcbf 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -18,6 +18,7 @@
#include "progress.h"
#include "bloom.h"
#include "commit-slab.h"
+#include "shallow.h"
void git_test_write_commit_graph_or_die(void)
{
diff --git a/commit.c b/commit.c
index c7099daeac..87686a7055 100644
--- a/commit.c
+++ b/commit.c
@@ -20,6 +20,7 @@
#include "refs.h"
#include "commit-reach.h"
#include "run-command.h"
+#include "shallow.h"
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
@@ -110,7 +111,7 @@ static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
return commit_graft_table[index]->oid.hash;
}
-static int commit_graft_pos(struct repository *r, const unsigned char *sha1)
+int commit_graft_pos(struct repository *r, const unsigned char *sha1)
{
return sha1_pos(sha1, r->parsed_objects->grafts,
r->parsed_objects->grafts_nr,
@@ -245,19 +246,6 @@ int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
return ret;
}
-int unregister_shallow(const struct object_id *oid)
-{
- int pos = commit_graft_pos(the_repository, oid->hash);
- if (pos < 0)
- return -1;
- if (pos + 1 < the_repository->parsed_objects->grafts_nr)
- MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
- the_repository->parsed_objects->grafts + pos + 1,
- the_repository->parsed_objects->grafts_nr - pos - 1);
- the_repository->parsed_objects->grafts_nr--;
- return 0;
-}
-
struct commit_buffer {
void *buffer;
unsigned long size;
diff --git a/commit.h b/commit.h
index ab91d21131..1b2dea5d85 100644
--- a/commit.h
+++ b/commit.h
@@ -236,6 +236,8 @@ struct commit_graft {
typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
struct commit_graft *read_graft_line(struct strbuf *line);
+/* commit_graft_pos returns an index into r->parsed_objects->grafts. */
+int commit_graft_pos(struct repository *r, const unsigned char *sha1);
int register_commit_graft(struct repository *r, struct commit_graft *, int);
void prepare_commit_graft(struct repository *r);
struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
@@ -247,55 +249,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit);
struct oid_array;
struct ref;
-int register_shallow(struct repository *r, const struct object_id *oid);
-int unregister_shallow(const struct object_id *oid);
-int commit_shallow_file(struct repository *r, struct lock_file *lk);
-void rollback_shallow_file(struct repository *r, struct lock_file *lk);
int for_each_commit_graft(each_commit_graft_fn, void *);
-int is_repository_shallow(struct repository *r);
-struct commit_list *get_shallow_commits(struct object_array *heads,
- int depth, int shallow_flag, int not_shallow_flag);
-struct commit_list *get_shallow_commits_by_rev_list(
- int ac, const char **av, int shallow_flag, int not_shallow_flag);
-void set_alternate_shallow_file(struct repository *r, const char *path, int override);
-int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
- const struct oid_array *extra);
-void setup_alternate_shallow(struct lock_file *shallow_lock,
- const char **alternate_shallow_file,
- const struct oid_array *extra);
-const char *setup_temporary_shallow(const struct oid_array *extra);
-void advertise_shallow_grafts(int);
-
-/*
- * Initialize with prepare_shallow_info() or zero-initialize (equivalent to
- * prepare_shallow_info with a NULL oid_array).
- */
-struct shallow_info {
- struct oid_array *shallow;
- int *ours, nr_ours;
- int *theirs, nr_theirs;
- struct oid_array *ref;
-
- /* for receive-pack */
- uint32_t **used_shallow;
- int *need_reachability_test;
- int *reachable;
- int *shallow_ref;
- struct commit **commits;
- int nr_commits;
-};
-
-void prepare_shallow_info(struct shallow_info *, struct oid_array *);
-void clear_shallow_info(struct shallow_info *);
-void remove_nonexistent_theirs_shallow(struct shallow_info *);
-void assign_shallow_commits_to_refs(struct shallow_info *info,
- uint32_t **used,
- int *ref_status);
-int delayed_reachability_test(struct shallow_info *si, int c);
-#define PRUNE_SHOW_ONLY 1
-#define PRUNE_QUICK 2
-void prune_shallow(unsigned options);
-extern struct trace_key trace_shallow;
int interactive_add(int argc, const char **argv, const char *prefix, int patch);
int run_add_interactive(const char *revision, const char *patch_mode,
diff --git a/credential.h b/credential.h
index d99ec42b2a..c0e17e3554 100644
--- a/credential.h
+++ b/credential.h
@@ -177,8 +177,8 @@ void credential_write(const struct credential *, FILE *);
* Parse a url into a credential struct, replacing any existing contents.
*
* If the url can't be parsed (e.g., a missing "proto://" component), the
- * resulting credential will be empty but we'll still return success from the
- * "gently" form.
+ * resulting credential will be empty and the function will return an
+ * error (even in the "gently" form).
*
* If we encounter a component which cannot be represented as a credential
* value (e.g., because it contains a newline), the "gently" form will return
@@ -189,7 +189,7 @@ void credential_write(const struct credential *, FILE *);
void credential_from_url(struct credential *, const char *url);
int credential_from_url_gently(struct credential *, const char *url, int quiet);
-int credential_match(const struct credential *have,
- const struct credential *want);
+int credential_match(const struct credential *want,
+ const struct credential *have);
#endif /* CREDENTIAL_H */
diff --git a/environment.c b/environment.c
index 10c9061c43..aaca0e91ac 100644
--- a/environment.c
+++ b/environment.c
@@ -17,6 +17,7 @@
#include "argv-array.h"
#include "object-store.h"
#include "chdir-notify.h"
+#include "shallow.h"
int trust_executable_bit = 1;
int trust_ctime = 1;
diff --git a/fetch-pack.c b/fetch-pack.c
index f73a2ce6cb..7eaa19d7c1 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -22,6 +22,7 @@
#include "connected.h"
#include "fetch-negotiator.h"
#include "fsck.h"
+#include "shallow.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -34,7 +35,7 @@ static int fetch_fsck_objects = -1;
static int transfer_fsck_objects = -1;
static int agent_supported;
static int server_supports_filtering;
-static struct lock_file shallow_lock;
+static struct shallow_lock shallow_lock;
static const char *alternate_shallow_file;
static struct strbuf fsck_msg_types = STRBUF_INIT;
diff --git a/git-bisect.sh b/git-bisect.sh
index efee12b8b1..71b367a944 100755
--- a/git-bisect.sh
+++ b/git-bisect.sh
@@ -209,6 +209,7 @@ bisect_replay () {
test "$#" -eq 1 || die "$(gettext "No logfile given")"
test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
git bisect--helper --bisect-reset || exit
+ oIFS="$IFS" IFS="$IFS$(printf '\015')"
while read git bisect command rev
do
test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
@@ -232,6 +233,7 @@ bisect_replay () {
die "$(gettext "?? what are you talking about?")" ;;
esac
done <"$file"
+ IFS="$oIFS"
bisect_auto_next
}
diff --git a/git-submodule.sh b/git-submodule.sh
index 08e0439df0..39ebdf25b5 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -805,27 +805,7 @@ cmd_set_url() {
shift
done
- if test $# -ne 2
- then
- usage
- fi
-
- # we can't use `git submodule--helper name` here because internally, it
- # hashes the path so a trailing slash could lead to an unintentional no match
- name="$(git submodule--helper list "$1" | cut -f2)"
- if test -z "$name"
- then
- exit 1
- fi
-
- url="$2"
- if test -z "$url"
- then
- exit 1
- fi
-
- git submodule--helper config submodule."$name".url "$url"
- git submodule--helper sync ${GIT_QUIET:+--quiet} "$name"
+ git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper set-url ${GIT_QUIET:+--quiet} -- "$@"
}
#
diff --git a/git.c b/git.c
index 2e4efb4ff0..a2d337eed7 100644
--- a/git.c
+++ b/git.c
@@ -4,6 +4,7 @@
#include "help.h"
#include "run-command.h"
#include "alias.h"
+#include "shallow.h"
#define RUN_SETUP (1<<0)
#define RUN_SETUP_GENTLY (1<<1)
diff --git a/list-objects-filter.c b/list-objects-filter.c
index 1e8d4e763d..0a3ef3cab3 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -663,6 +663,9 @@ struct filter *list_objects_filter__init(
assert((sizeof(s_filters) / sizeof(s_filters[0])) == LOFC__COUNT);
+ if (!filter_options)
+ return NULL;
+
if (filter_options->choice >= LOFC__COUNT)
BUG("invalid list-objects filter choice: %d",
filter_options->choice);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 49a8d10d0c..4077e731e8 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -506,7 +506,8 @@ static int should_include(struct commit *commit, void *_data)
static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
struct rev_info *revs,
struct object_list *roots,
- struct bitmap *seen)
+ struct bitmap *seen,
+ struct list_objects_filter_options *filter)
{
struct bitmap *base = NULL;
int needs_walk = 0;
@@ -599,8 +600,9 @@ static struct bitmap *find_objects(struct bitmap_index *bitmap_git,
show_data.bitmap_git = bitmap_git;
show_data.base = base;
- traverse_commit_list(revs, show_commit, show_object,
- &show_data);
+ traverse_commit_list_filtered(filter, revs,
+ show_commit, show_object,
+ &show_data, NULL);
}
return base;
@@ -715,8 +717,9 @@ static int in_bitmapped_pack(struct bitmap_index *bitmap_git,
return 0;
}
-static struct bitmap *find_tip_blobs(struct bitmap_index *bitmap_git,
- struct object_list *tip_objects)
+static struct bitmap *find_tip_objects(struct bitmap_index *bitmap_git,
+ struct object_list *tip_objects,
+ enum object_type type)
{
struct bitmap *result = bitmap_new();
struct object_list *p;
@@ -724,7 +727,7 @@ static struct bitmap *find_tip_blobs(struct bitmap_index *bitmap_git,
for (p = tip_objects; p; p = p->next) {
int pos;
- if (p->item->type != OBJ_BLOB)
+ if (p->item->type != type)
continue;
pos = bitmap_position(bitmap_git, &p->item->oid);
@@ -737,9 +740,10 @@ static struct bitmap *find_tip_blobs(struct bitmap_index *bitmap_git,
return result;
}
-static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
- struct object_list *tip_objects,
- struct bitmap *to_filter)
+static void filter_bitmap_exclude_type(struct bitmap_index *bitmap_git,
+ struct object_list *tip_objects,
+ struct bitmap *to_filter,
+ enum object_type type)
{
struct eindex *eindex = &bitmap_git->ext_index;
struct bitmap *tips;
@@ -747,18 +751,21 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
eword_t mask;
uint32_t i;
+ if (type != OBJ_BLOB && type != OBJ_TREE)
+ BUG("filter_bitmap_exclude_type: unsupported type '%d'", type);
+
/*
* The non-bitmap version of this filter never removes
- * blobs which the other side specifically asked for,
+ * objects which the other side specifically asked for,
* so we must match that behavior.
*/
- tips = find_tip_blobs(bitmap_git, tip_objects);
+ tips = find_tip_objects(bitmap_git, tip_objects, type);
/*
* We can use the blob type-bitmap to work in whole words
* for the objects that are actually in the bitmapped packfile.
*/
- for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
+ for (i = 0, init_type_iterator(&it, bitmap_git, type);
i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
i++) {
if (i < tips->word_alloc)
@@ -773,7 +780,7 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
*/
for (i = 0; i < eindex->count; i++) {
uint32_t pos = i + bitmap_git->pack->num_objects;
- if (eindex->objects[i]->type == OBJ_BLOB &&
+ if (eindex->objects[i]->type == type &&
bitmap_get(to_filter, pos) &&
!bitmap_get(tips, pos))
bitmap_unset(to_filter, pos);
@@ -782,6 +789,14 @@ static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
bitmap_free(tips);
}
+static void filter_bitmap_blob_none(struct bitmap_index *bitmap_git,
+ struct object_list *tip_objects,
+ struct bitmap *to_filter)
+{
+ filter_bitmap_exclude_type(bitmap_git, tip_objects, to_filter,
+ OBJ_BLOB);
+}
+
static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
uint32_t pos)
{
@@ -820,7 +835,7 @@ static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
eword_t mask;
uint32_t i;
- tips = find_tip_blobs(bitmap_git, tip_objects);
+ tips = find_tip_objects(bitmap_git, tip_objects, OBJ_BLOB);
for (i = 0, init_type_iterator(&it, bitmap_git, OBJ_BLOB);
i < to_filter->word_alloc && ewah_iterator_next(&mask, &it);
@@ -854,6 +869,20 @@ static void filter_bitmap_blob_limit(struct bitmap_index *bitmap_git,
bitmap_free(tips);
}
+static void filter_bitmap_tree_depth(struct bitmap_index *bitmap_git,
+ struct object_list *tip_objects,
+ struct bitmap *to_filter,
+ unsigned long limit)
+{
+ if (limit)
+ BUG("filter_bitmap_tree_depth given non-zero limit");
+
+ filter_bitmap_exclude_type(bitmap_git, tip_objects, to_filter,
+ OBJ_TREE);
+ filter_bitmap_exclude_type(bitmap_git, tip_objects, to_filter,
+ OBJ_BLOB);
+}
+
static int filter_bitmap(struct bitmap_index *bitmap_git,
struct object_list *tip_objects,
struct bitmap *to_filter,
@@ -877,6 +906,15 @@ static int filter_bitmap(struct bitmap_index *bitmap_git,
return 0;
}
+ if (filter->choice == LOFC_TREE_DEPTH &&
+ filter->tree_exclude_depth == 0) {
+ if (bitmap_git)
+ filter_bitmap_tree_depth(bitmap_git, tip_objects,
+ to_filter,
+ filter->tree_exclude_depth);
+ return 0;
+ }
+
/* filter choice not handled */
return -1;
}
@@ -963,7 +1001,8 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
if (haves) {
revs->ignore_missing_links = 1;
- haves_bitmap = find_objects(bitmap_git, revs, haves, NULL);
+ haves_bitmap = find_objects(bitmap_git, revs, haves, NULL,
+ filter);
reset_revision_walk();
revs->ignore_missing_links = 0;
@@ -971,7 +1010,8 @@ struct bitmap_index *prepare_bitmap_walk(struct rev_info *revs,
BUG("failed to perform bitmap walk");
}
- wants_bitmap = find_objects(bitmap_git, revs, wants, haves_bitmap);
+ wants_bitmap = find_objects(bitmap_git, revs, wants, haves_bitmap,
+ filter);
if (!wants_bitmap)
BUG("failed to perform bitmap walk");
diff --git a/run-command.c b/run-command.c
index 0f41af3b55..9b3a57d1e3 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1864,3 +1864,16 @@ int run_processes_parallel_tr2(int n, get_next_task_fn get_next_task,
return result;
}
+
+int run_auto_gc(int quiet)
+{
+ struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
+ int status;
+
+ argv_array_pushl(&argv_gc_auto, "gc", "--auto", NULL);
+ if (quiet)
+ argv_array_push(&argv_gc_auto, "--quiet");
+ status = run_command_v_opt(argv_gc_auto.argv, RUN_GIT_CMD);
+ argv_array_clear(&argv_gc_auto);
+ return status;
+}
diff --git a/run-command.h b/run-command.h
index 0f3cc73ab6..191dfcdafe 100644
--- a/run-command.h
+++ b/run-command.h
@@ -218,6 +218,11 @@ LAST_ARG_MUST_BE_NULL
int run_hook_le(const char *const *env, const char *name, ...);
int run_hook_ve(const char *const *env, const char *name, va_list args);
+/*
+ * Trigger an auto-gc
+ */
+int run_auto_gc(int quiet);
+
#define RUN_COMMAND_NO_STDIN 1
#define RUN_GIT_CMD 2 /*If this is to be git sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
diff --git a/send-pack.c b/send-pack.c
index d1b7edc995..0abee22283 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -15,6 +15,7 @@
#include "oid-array.h"
#include "gpg-interface.h"
#include "cache.h"
+#include "shallow.h"
int option_parse_push_signed(const struct option *opt,
const char *arg, int unset)
diff --git a/sequencer.c b/sequencer.c
index 9d1b3e7d4f..fd7701c88a 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -5385,10 +5385,13 @@ int todo_list_rearrange_squash(struct todo_list *todo_list)
todo_list->items[i].command =
starts_with(subject, "fixup!") ?
TODO_FIXUP : TODO_SQUASH;
- if (next[i2] < 0)
+ if (tail[i2] < 0) {
+ next[i] = next[i2];
next[i2] = i;
- else
+ } else {
+ next[i] = next[tail[i2]];
next[tail[i2]] = i;
+ }
tail[i2] = i;
} else if (!hashmap_get_from_hash(&subject2item,
strhash(subject), subject)) {
diff --git a/shallow.c b/shallow.c
index 321a27670f..b826de9b67 100644
--- a/shallow.c
+++ b/shallow.c
@@ -14,6 +14,7 @@
#include "commit-slab.h"
#include "list-objects.h"
#include "commit-reach.h"
+#include "shallow.h"
void set_alternate_shallow_file(struct repository *r, const char *path, int override)
{
@@ -38,6 +39,19 @@ int register_shallow(struct repository *r, const struct object_id *oid)
return register_commit_graft(r, graft, 0);
}
+int unregister_shallow(const struct object_id *oid)
+{
+ int pos = commit_graft_pos(the_repository, oid->hash);
+ if (pos < 0)
+ return -1;
+ if (pos + 1 < the_repository->parsed_objects->grafts_nr)
+ MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
+ the_repository->parsed_objects->grafts + pos + 1,
+ the_repository->parsed_objects->grafts_nr - pos - 1);
+ the_repository->parsed_objects->grafts_nr--;
+ return 0;
+}
+
int is_repository_shallow(struct repository *r)
{
FILE *fp;
@@ -78,16 +92,16 @@ static void reset_repository_shallow(struct repository *r)
stat_validity_clear(r->parsed_objects->shallow_stat);
}
-int commit_shallow_file(struct repository *r, struct lock_file *lk)
+int commit_shallow_file(struct repository *r, struct shallow_lock *lk)
{
- int res = commit_lock_file(lk);
+ int res = commit_lock_file(&lk->lock);
reset_repository_shallow(r);
return res;
}
-void rollback_shallow_file(struct repository *r, struct lock_file *lk)
+void rollback_shallow_file(struct repository *r, struct shallow_lock *lk)
{
- rollback_lock_file(lk);
+ rollback_lock_file(&lk->lock);
reset_repository_shallow(r);
}
@@ -352,22 +366,22 @@ const char *setup_temporary_shallow(const struct oid_array *extra)
return "";
}
-void setup_alternate_shallow(struct lock_file *shallow_lock,
+void setup_alternate_shallow(struct shallow_lock *shallow_lock,
const char **alternate_shallow_file,
const struct oid_array *extra)
{
struct strbuf sb = STRBUF_INIT;
int fd;
- fd = hold_lock_file_for_update(shallow_lock,
+ fd = hold_lock_file_for_update(&shallow_lock->lock,
git_path_shallow(the_repository),
LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(the_repository);
if (write_shallow_commits(&sb, 0, extra)) {
if (write_in_full(fd, sb.buf, sb.len) < 0)
die_errno("failed to write to %s",
- get_lock_file_path(shallow_lock));
- *alternate_shallow_file = get_lock_file_path(shallow_lock);
+ get_lock_file_path(&shallow_lock->lock));
+ *alternate_shallow_file = get_lock_file_path(&shallow_lock->lock);
} else
/*
* is_repository_shallow() sees empty string as "no
@@ -400,7 +414,7 @@ void advertise_shallow_grafts(int fd)
*/
void prune_shallow(unsigned options)
{
- struct lock_file shallow_lock = LOCK_INIT;
+ struct shallow_lock shallow_lock = SHALLOW_LOCK_INIT;
struct strbuf sb = STRBUF_INIT;
unsigned flags = SEEN_ONLY;
int fd;
@@ -414,14 +428,14 @@ void prune_shallow(unsigned options)
strbuf_release(&sb);
return;
}
- fd = hold_lock_file_for_update(&shallow_lock,
+ fd = hold_lock_file_for_update(&shallow_lock.lock,
git_path_shallow(the_repository),
LOCK_DIE_ON_ERROR);
check_shallow_file_for_update(the_repository);
if (write_shallow_commits_1(&sb, 0, NULL, flags)) {
if (write_in_full(fd, sb.buf, sb.len) < 0)
die_errno("failed to write to %s",
- get_lock_file_path(&shallow_lock));
+ get_lock_file_path(&shallow_lock.lock));
commit_shallow_file(the_repository, &shallow_lock);
} else {
unlink(git_path_shallow(the_repository));
diff --git a/shallow.h b/shallow.h
new file mode 100644
index 0000000000..5b4a96dcd6
--- /dev/null
+++ b/shallow.h
@@ -0,0 +1,81 @@
+#ifndef SHALLOW_H
+#define SHALLOW_H
+
+#include "lockfile.h"
+#include "object.h"
+#include "repository.h"
+#include "strbuf.h"
+
+void set_alternate_shallow_file(struct repository *r, const char *path, int override);
+int register_shallow(struct repository *r, const struct object_id *oid);
+int unregister_shallow(const struct object_id *oid);
+int is_repository_shallow(struct repository *r);
+
+/*
+ * Lock for updating the $GIT_DIR/shallow file.
+ *
+ * Use `commit_shallow_file()` to commit an update, or
+ * `rollback_shallow_file()` to roll it back. In either case, any
+ * in-memory cached information about which commits are shallow will be
+ * appropriately invalidated so that future operations reflect the new
+ * state.
+ */
+struct shallow_lock {
+ struct lock_file lock;
+};
+#define SHALLOW_LOCK_INIT { LOCK_INIT }
+
+/* commit $GIT_DIR/shallow and reset stat-validity checks */
+int commit_shallow_file(struct repository *r, struct shallow_lock *lk);
+/* rollback $GIT_DIR/shallow and reset stat-validity checks */
+void rollback_shallow_file(struct repository *r, struct shallow_lock *lk);
+
+struct commit_list *get_shallow_commits(struct object_array *heads,
+ int depth, int shallow_flag, int not_shallow_flag);
+struct commit_list *get_shallow_commits_by_rev_list(
+ int ac, const char **av, int shallow_flag, int not_shallow_flag);
+int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
+ const struct oid_array *extra);
+
+void setup_alternate_shallow(struct shallow_lock *shallow_lock,
+ const char **alternate_shallow_file,
+ const struct oid_array *extra);
+
+const char *setup_temporary_shallow(const struct oid_array *extra);
+
+void advertise_shallow_grafts(int);
+
+#define PRUNE_SHOW_ONLY 1
+#define PRUNE_QUICK 2
+void prune_shallow(unsigned options);
+
+/*
+ * Initialize with prepare_shallow_info() or zero-initialize (equivalent to
+ * prepare_shallow_info with a NULL oid_array).
+ */
+struct shallow_info {
+ struct oid_array *shallow;
+ int *ours, nr_ours;
+ int *theirs, nr_theirs;
+ struct oid_array *ref;
+
+ /* for receive-pack */
+ uint32_t **used_shallow;
+ int *need_reachability_test;
+ int *reachable;
+ int *shallow_ref;
+ struct commit **commits;
+ int nr_commits;
+};
+
+void prepare_shallow_info(struct shallow_info *, struct oid_array *);
+void clear_shallow_info(struct shallow_info *);
+void remove_nonexistent_theirs_shallow(struct shallow_info *);
+void assign_shallow_commits_to_refs(struct shallow_info *info,
+ uint32_t **used,
+ int *ref_status);
+int delayed_reachability_test(struct shallow_info *si, int c);
+
+extern struct trace_key trace_shallow;
+
+#endif /* SHALLOW_H */
diff --git a/t/helper/test-bloom.c b/t/helper/test-bloom.c
index 77eb27adac..456f5ea7f9 100644
--- a/t/helper/test-bloom.c
+++ b/t/helper/test-bloom.c
@@ -3,7 +3,7 @@
#include "test-tool.h"
#include "commit.h"
-struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+static struct bloom_filter_settings settings = DEFAULT_BLOOM_FILTER_SETTINGS;
static void add_string_to_filter(const char *data, struct bloom_filter *filter) {
struct bloom_key key;
diff --git a/t/perf/p5310-pack-bitmaps.sh b/t/perf/p5310-pack-bitmaps.sh
index 80c53edca7..b3e725f031 100755
--- a/t/perf/p5310-pack-bitmaps.sh
+++ b/t/perf/p5310-pack-bitmaps.sh
@@ -53,6 +53,11 @@ test_perf 'rev-list count with blob:limit=1k' '
--filter=blob:limit=1k >/dev/null
'
+test_perf 'rev-list count with tree:0' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=tree:0 >/dev/null
+'
+
test_perf 'simulated partial clone' '
git pack-objects --stdout --all --filter=blob:none </dev/null >/dev/null
'
@@ -86,4 +91,9 @@ test_perf 'pack to file (partial bitmap)' '
git pack-objects --use-bitmap-index --all pack2b </dev/null >/dev/null
'
+test_perf 'rev-list with tree filter (partial bitmap)' '
+ git rev-list --use-bitmap-index --count --objects --all \
+ --filter=tree:0 >/dev/null
+'
+
test_done
diff --git a/t/t0091-bugreport.sh b/t/t0091-bugreport.sh
index 2e73658a5c..526304ff95 100755
--- a/t/t0091-bugreport.sh
+++ b/t/t0091-bugreport.sh
@@ -57,5 +57,20 @@ test_expect_success 'can create leading directories outside of a git dir' '
nongit git bugreport -o foo/bar/baz
'
+test_expect_success 'indicates populated hooks' '
+ test_when_finished rm git-bugreport-hooks.txt &&
+ test_when_finished rm -fr .git/hooks &&
+ rm -fr .git/hooks &&
+ mkdir .git/hooks &&
+ for hook in applypatch-msg prepare-commit-msg.sample
+ do
+ write_script ".git/hooks/$hook" <<-EOF || return 1
+ echo "hook $hook exists"
+ EOF
+ done &&
+ git bugreport -s hooks &&
+ grep applypatch-msg git-bugreport-hooks.txt &&
+ ! grep prepare-commit-msg git-bugreport-hooks.txt
+'
test_done
diff --git a/t/t0095-bloom.sh b/t/t0095-bloom.sh
index 8f9eef116d..809ec7b0b8 100755
--- a/t/t0095-bloom.sh
+++ b/t/t0095-bloom.sh
@@ -114,4 +114,4 @@ test_expect_success EXPENSIVE 'get bloom filter for commit with 513 changes' '
test_cmp expect actual
'
-test_done \ No newline at end of file
+test_done
diff --git a/t/t3415-rebase-autosquash.sh b/t/t3415-rebase-autosquash.sh
index 093de9005b..7bab6000dc 100755
--- a/t/t3415-rebase-autosquash.sh
+++ b/t/t3415-rebase-autosquash.sh
@@ -424,4 +424,20 @@ test_expect_success 'abort last squash' '
! grep first actual
'
+test_expect_success 'fixup a fixup' '
+ echo 0to-fixup >file0 &&
+ test_tick &&
+ git commit -m "to-fixup" file0 &&
+ test_tick &&
+ git commit --squash HEAD -m X --allow-empty &&
+ test_tick &&
+ git commit --squash HEAD^ -m Y --allow-empty &&
+ test_tick &&
+ git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty &&
+ test_tick &&
+ git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty &&
+ git rebase -ki --autosquash HEAD~5 &&
+ test XZWY = $(git show | tr -cd W-Z)
+'
+
test_done
diff --git a/t/t4216-log-bloom.sh b/t/t4216-log-bloom.sh
index c7011f33e2..21b68dd6c8 100755
--- a/t/t4216-log-bloom.sh
+++ b/t/t4216-log-bloom.sh
@@ -152,4 +152,4 @@ test_expect_success 'Use Bloom filters if they exist in the latest but not all c
test_bloom_filters_used_when_some_filters_are_missing "-- A/B"
'
-test_done \ No newline at end of file
+test_done
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 88002b24af..8a27452a51 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -384,12 +384,11 @@ test_expect_success 'fetch lazy-fetches only to resolve deltas, protocol v2' '
grep "want $(cat hash)" trace
'
-# The following two tests must be in this order, or else
-# the first will not fail. It is important that the srv.bare
-# repository did not have tags during clone, but has tags
+# The following two tests must be in this order. It is important that
+# the srv.bare repository did not have tags during clone, but has tags
# in the fetch.
-test_expect_failure 'verify fetch succeeds when asking for new tags' '
+test_expect_success 'verify fetch succeeds when asking for new tags' '
git clone --filter=blob:none "file://$(pwd)/srv.bare" tag-test &&
for i in I J K
do
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 1313142564..ac31faefa1 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -792,6 +792,13 @@ test_expect_success 'bisect replay with old and new' '
git bisect reset
'
+test_expect_success 'bisect replay with CRLF log' '
+ append_cr <log_to_replay.txt >log_to_replay_crlf.txt &&
+ git bisect replay log_to_replay_crlf.txt >bisect_result_crlf &&
+ grep "$HASH2 is the first new commit" bisect_result_crlf &&
+ git bisect reset
+'
+
test_expect_success 'bisect cannot mix old/new and good/bad' '
git bisect start &&
git bisect bad $HASH4 &&
diff --git a/t/t6113-rev-list-bitmap-filters.sh b/t/t6113-rev-list-bitmap-filters.sh
index 145603f124..2b551e6fd0 100755
--- a/t/t6113-rev-list-bitmap-filters.sh
+++ b/t/t6113-rev-list-bitmap-filters.sh
@@ -53,4 +53,25 @@ test_expect_success 'blob:limit filter with specified blob' '
test_bitmap_traversal expect actual
'
+test_expect_success 'tree:0 filter' '
+ git rev-list --objects --filter=tree:0 HEAD >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=tree:0 HEAD >actual &&
+ test_bitmap_traversal expect actual
+'
+
+test_expect_success 'tree:0 filter with specified blob, tree' '
+ git rev-list --objects --filter=tree:0 HEAD HEAD:two.t >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=tree:0 HEAD HEAD:two.t >actual &&
+ test_bitmap_traversal expect actual
+'
+
+test_expect_success 'tree:1 filter' '
+ git rev-list --objects --filter=tree:1 HEAD >expect &&
+ git rev-list --use-bitmap-index \
+ --objects --filter=tree:1 HEAD >actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/unpack-trees.c b/unpack-trees.c
index 1fe3764f2b..02048dfdac 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -562,11 +562,11 @@ static int warn_conflicted_path(struct index_state *istate,
add_rejected_path(o, WARNING_SPARSE_UNMERGED_FILE, conflicting_path);
- /* Find out how many higher stage entries at same path */
- while (++count < istate->cache_nr &&
- !strcmp(conflicting_path,
- istate->cache[i+count]->name))
- /* do nothing */;
+ /* Find out how many higher stage entries are at same path */
+ while ((++count) + i < istate->cache_nr &&
+ !strcmp(conflicting_path, istate->cache[count + i]->name))
+ ; /* do nothing */
+
return count;
}
diff --git a/upload-pack.c b/upload-pack.c
index 902d0ad5e1..0478bff3e7 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -26,6 +26,7 @@
#include "serve.h"
#include "commit-graph.h"
#include "commit-reach.h"
+#include "shallow.h"
/* Remember to update object flag allocation in object.h */
#define THEY_HAVE (1u << 11)
@@ -68,7 +69,6 @@ static const char *pack_objects_hook;
static int filter_capability_requested;
static int allow_filter;
static int allow_ref_in_want;
-static struct list_objects_filter_options filter_options;
static int allow_sideband_all;
@@ -103,7 +103,8 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data)
}
static void create_pack_file(const struct object_array *have_obj,
- const struct object_array *want_obj)
+ const struct object_array *want_obj,
+ struct list_objects_filter_options *filter_options)
{
struct child_process pack_objects = CHILD_PROCESS_INIT;
char data[8193], progress[128];
@@ -140,9 +141,9 @@ static void create_pack_file(const struct object_array *have_obj,
argv_array_push(&pack_objects.args, "--delta-base-offset");
if (use_include_tag)
argv_array_push(&pack_objects.args, "--include-tag");
- if (filter_options.choice) {
+ if (filter_options->choice) {
const char *spec =
- expand_list_objects_filter_spec(&filter_options);
+ expand_list_objects_filter_spec(filter_options);
if (pack_objects.use_shell) {
struct strbuf buf = STRBUF_INIT;
sq_quote_buf(&buf, spec);
@@ -848,7 +849,9 @@ static int process_deepen_not(const char *line, struct string_list *deepen_not,
return 0;
}
-static void receive_needs(struct packet_reader *reader, struct object_array *want_obj)
+static void receive_needs(struct packet_reader *reader,
+ struct object_array *want_obj,
+ struct list_objects_filter_options *filter_options)
{
struct object_array shallows = OBJECT_ARRAY_INIT;
struct string_list deepen_not = STRING_LIST_INIT_DUP;
@@ -883,8 +886,8 @@ static void receive_needs(struct packet_reader *reader, struct object_array *wan
if (skip_prefix(reader->line, "filter ", &arg)) {
if (!filter_capability_requested)
die("git upload-pack: filtering capability not negotiated");
- list_objects_filter_die_if_populated(&filter_options);
- parse_list_objects_filter(&filter_options, arg);
+ list_objects_filter_die_if_populated(filter_options);
+ parse_list_objects_filter(filter_options, arg);
continue;
}
@@ -1087,11 +1090,14 @@ void upload_pack(struct upload_pack_options *options)
struct string_list symref = STRING_LIST_INIT_DUP;
struct object_array want_obj = OBJECT_ARRAY_INIT;
struct packet_reader reader;
+ struct list_objects_filter_options filter_options;
stateless_rpc = options->stateless_rpc;
timeout = options->timeout;
daemon_mode = options->daemon_mode;
+ memset(&filter_options, 0, sizeof(filter_options));
+
git_config(upload_pack_config, NULL);
head_ref_namespaced(find_symref, &symref);
@@ -1114,12 +1120,14 @@ void upload_pack(struct upload_pack_options *options)
PACKET_READ_CHOMP_NEWLINE |
PACKET_READ_DIE_ON_ERR_PACKET);
- receive_needs(&reader, &want_obj);
+ receive_needs(&reader, &want_obj, &filter_options);
if (want_obj.nr) {
struct object_array have_obj = OBJECT_ARRAY_INIT;
get_common_commits(&reader, &have_obj, &want_obj);
- create_pack_file(&have_obj, &want_obj);
+ create_pack_file(&have_obj, &want_obj, &filter_options);
}
+
+ list_objects_filter_release(&filter_options);
}
struct upload_pack_data {
@@ -1134,6 +1142,8 @@ struct upload_pack_data {
int deepen_rev_list;
int deepen_relative;
+ struct list_objects_filter_options filter_options;
+
struct packet_writer writer;
unsigned stateless_rpc : 1;
@@ -1169,6 +1179,7 @@ static void upload_pack_data_clear(struct upload_pack_data *data)
oid_array_clear(&data->haves);
object_array_clear(&data->shallows);
string_list_clear(&data->deepen_not, 0);
+ list_objects_filter_release(&data->filter_options);
}
static int parse_want(struct packet_writer *writer, const char *line,
@@ -1306,8 +1317,8 @@ static void process_args(struct packet_reader *request,
}
if (allow_filter && skip_prefix(arg, "filter ", &p)) {
- list_objects_filter_die_if_populated(&filter_options);
- parse_list_objects_filter(&filter_options, p);
+ list_objects_filter_die_if_populated(&data->filter_options);
+ parse_list_objects_filter(&data->filter_options, p);
continue;
}
@@ -1514,7 +1525,7 @@ int upload_pack_v2(struct repository *r, struct argv_array *keys,
send_shallow_info(&data, &want_obj);
packet_writer_write(&data.writer, "packfile\n");
- create_pack_file(&have_obj, &want_obj);
+ create_pack_file(&have_obj, &want_obj, &data.filter_options);
state = FETCH_DONE;
break;
case FETCH_DONE: