summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml42
-rw-r--r--Documentation/CodingGuidelines4
-rw-r--r--Documentation/RelNotes/2.27.0.txt49
-rw-r--r--Documentation/config/credential.txt10
-rw-r--r--Documentation/git-credential-store.txt4
-rw-r--r--Documentation/git-credential.txt34
-rw-r--r--Documentation/git-merge.txt4
-rw-r--r--Documentation/git-rebase.txt2
-rw-r--r--Documentation/git-restore.txt11
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/gitcredentials.txt42
-rw-r--r--Documentation/gitfaq.txt18
-rw-r--r--bloom.c4
-rw-r--r--bloom.h2
-rw-r--r--builtin/am.c3
-rw-r--r--builtin/branch.c2
-rw-r--r--builtin/checkout.c20
-rw-r--r--builtin/commit.c3
-rw-r--r--builtin/fetch.c11
-rw-r--r--builtin/for-each-ref.c2
-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.c9
-rw-r--r--builtin/repack.c1
-rw-r--r--builtin/rev-parse.c1
-rw-r--r--builtin/tag.c2
-rwxr-xr-xci/config/allow-refs.sample26
-rw-r--r--commit-graph.c23
-rw-r--r--commit.c16
-rw-r--r--commit.h50
-rw-r--r--credential-store.c4
-rw-r--r--credential.h8
-rw-r--r--environment.c1
-rw-r--r--fetch-pack.c3
-rw-r--r--git.c1
-rw-r--r--list-objects-filter.c3
-rw-r--r--pack-bitmap.c72
-rw-r--r--ref-filter.c13
-rw-r--r--ref-filter.h2
-rw-r--r--run-command.c13
-rw-r--r--run-command.h5
-rw-r--r--send-pack.c1
-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/t0000-basic.sh7
-rwxr-xr-xt/t0095-bloom.sh2
-rwxr-xr-xt/t0302-credential-store.sh91
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh12
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh8
-rwxr-xr-xt/t2070-restore.sh11
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rw-r--r--t/t4018/markdown-heading-indented6
-rw-r--r--t/t4018/markdown-heading-non-headings17
-rwxr-xr-xt/t4216-log-bloom.sh2
-rwxr-xr-xt/t6113-rev-list-bitmap-filters.sh21
-rwxr-xr-xt/t6300-for-each-ref.sh94
-rw-r--r--t/test-lib.sh18
-rw-r--r--unpack-trees.c34
-rw-r--r--upload-pack.c1
-rw-r--r--userdiff.c3
64 files changed, 739 insertions, 249 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 390ceece52..a89e8dcfbc 100644
--- a/Documentation/CodingGuidelines
+++ b/Documentation/CodingGuidelines
@@ -95,10 +95,6 @@ For shell scripts specifically (not exhaustive):
- We use Arithmetic Expansion $(( ... )).
- - Inside Arithmetic Expansion, spell shell variables with $ in front
- of them, as some shells do not grok $((x)) while accepting $(($x))
- just fine (e.g. dash older than 0.5.4).
-
- We do not use Process Substitution <(list) or >(list).
- Do not write control structures on a single line with semicolon.
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.txt
index 9c7041eb08..2a8c6e8f28 100644
--- a/Documentation/RelNotes/2.27.0.txt
+++ b/Documentation/RelNotes/2.27.0.txt
@@ -99,6 +99,15 @@ UI, Workflows & Features
* The approxidate parser learns to parse seconds with fraction and
ignore fractional part.
+ * The userdiff patterns for Markdown documents have been added.
+
+ * The sparse-checkout patterns have been forbidden from excluding all
+ paths, leaving an empty working tree, for a long time. This
+ limitation has been lifted.
+
+ * "git restore --staged --worktree" now defaults to take the contents
+ out of "HEAD", instead of erring out.
+
Performance, Internal Implementation, Development Support etc.
@@ -372,6 +381,45 @@ Fixes since v2.26
correctly honor the core.sharedRepository settings and some were
left read-write.
+ * In error messages that "git switch" mentions its option to create a
+ new branch, "-b/-B" options were shown, where "-c/-C" options
+ should be, which has been corrected.
+ (merge 7c16ef7577 dl/switch-c-option-in-error-message later to maint).
+
+ * With the recent tightening of the code that is used to parse
+ various parts of a URL for use in the credential subsystem, a
+ hand-edited credential-store file causes the credential helper to
+ die, which is a bit too harsh to the users. Demote the error
+ behaviour to just ignore and keep using well-formed lines instead.
+ (merge c03859a665 cb/credential-store-ignore-bogus-lines later to maint).
+
+ * The samples in the credential documentation has been updated to
+ make it clear that we depict what would appear in the .git/config
+ file, by adding appropriate quotes as needed..
+ (merge 177681a07e jk/credential-sample-update later to maint).
+
+ * "git branch" and other "for-each-ref" variants accepted multiple
+ --sort=<key> options in the increasing order of precedence, but it
+ had a few breakages around "--ignore-case" handling, and tie-breaking
+ with the refname, which have been fixed.
+ (merge 7c5045fc18 jk/for-each-ref-multi-key-sort-fix later to maint).
+
+ * The coding guideline for shell scripts instructed to refer to a
+ variable with dollar-sign inside arithmetic expansion to work
+ around a bug in old versions of dash, which is a thing of the past.
+ Now we are not forbidden from writing $((var+1)).
+ (merge 32b5fe7f0e jk/arith-expansion-coding-guidelines later to maint).
+
+ * The <stdlib.h> header on NetBSD brings in its own definition of
+ hmac() function (eek), which conflicts with our own and unrelated
+ function with the same name. Our function has been renamed to work
+ around the issue.
+ (merge 3013118eb8 cb/avoid-colliding-with-netbsd-hmac later to maint).
+
+ * The basic test did not honor $TEST_SHELL_PATH setting, which has
+ been corrected.
+ (merge 0555e4af58 cb/t0000-use-the-configured-shell 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).
@@ -399,3 +447,4 @@ Fixes since v2.26
(merge 4d9378bfad eb/gitweb-more-trailers later to maint).
(merge bdccbf7047 mt/doc-worktree-ref later to maint).
(merge ce9baf234f dl/push-recurse-submodules-fix later to maint).
+ (merge 4153274052 bc/doc-credential-helper-value later to maint).
diff --git a/Documentation/config/credential.txt b/Documentation/config/credential.txt
index 60fb3189e1..9d01641c28 100644
--- a/Documentation/config/credential.txt
+++ b/Documentation/config/credential.txt
@@ -1,9 +1,13 @@
credential.helper::
Specify an external helper to be called when a username or
password credential is needed; the helper may consult external
- storage to avoid prompting the user for the credentials. Note
- that multiple helpers may be defined. See linkgit:gitcredentials[7]
- for details.
+ storage to avoid prompting the user for the credentials. This is
+ normally the name of a credential helper with possible
+ arguments, but may also be an absolute path with arguments or, if
+ preceded by `!`, shell commands.
++
+Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
+for details and examples.
credential.useHttpPath::
When acquiring credentials, consider the "path" component of an http
diff --git a/Documentation/git-credential-store.txt b/Documentation/git-credential-store.txt
index 693dd9d9d7..76b0798856 100644
--- a/Documentation/git-credential-store.txt
+++ b/Documentation/git-credential-store.txt
@@ -94,6 +94,10 @@ stored on its own line as a URL like:
https://user:pass@example.com
------------------------------
+No other kinds of lines (e.g. empty lines or comment lines) are
+allowed in the file, even though some may be silently ignored. Do
+not view or edit the file with editors.
+
When Git needs authentication for a particular URL context,
credential-store will consider that context a pattern to match against
each entry in the credentials file. If the protocol, hostname, and
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/git-merge.txt b/Documentation/git-merge.txt
index ec06b2f8c2..3819fadac1 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -106,12 +106,12 @@ commit or stash your changes before running 'git merge'.
`MERGE_HEAD` is present unless `MERGE_AUTOSTASH` is also present in
which case 'git merge --abort' applies the stash entry to the worktree
whereas 'git reset --merge' will save the stashed changes in the stash
-reflog.
+list.
--quit::
Forget about the current merge in progress. Leave the index
and the working tree as-is. If `MERGE_AUTOSTASH` is present, the
- stash entry will be saved to the stash reflog.
+ stash entry will be saved to the stash list.
--continue::
After a 'git merge' stops due to conflicts you can conclude the
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index 794f2f39f1..4624cfd288 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -257,7 +257,7 @@ See also INCOMPATIBLE OPTIONS below.
Abort the rebase operation but HEAD is not reset back to the
original branch. The index and working tree are also left
unchanged as a result. If a temporary stash entry was created
- using --autostash, it will be saved to the stash reflog.
+ using --autostash, it will be saved to the stash list.
--apply:
Use applying strategies to rebase (calling `git-am`
diff --git a/Documentation/git-restore.txt b/Documentation/git-restore.txt
index 8e3b339802..84c6c40010 100644
--- a/Documentation/git-restore.txt
+++ b/Documentation/git-restore.txt
@@ -22,9 +22,8 @@ The command can also be used to restore the content in the index with
`--staged`, or restore both the working tree and the index with
`--staged --worktree`.
-By default, the restore sources for working tree and the index are the
-index and `HEAD` respectively. `--source` could be used to specify a
-commit as the restore source.
+By default, if `--staged` is given, the contents are restored from `HEAD`,
+otherwise from the index. Use `--source` to restore from a different commit.
See "Reset, restore and revert" in linkgit:git[1] for the differences
between the three commands.
@@ -39,10 +38,8 @@ OPTIONS
tree. It is common to specify the source tree by naming a
commit, branch or tag associated with it.
+
-If not specified, the default restore source for the working tree is
-the index, and the default restore source for the index is
-`HEAD`. When both `--staged` and `--worktree` are specified,
-`--source` must also be specified.
+If not specified, the contents are restored from `HEAD` if `--staged` is
+given, otherwise from the index.
-p::
--patch::
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 508fe713c4..2d0a03715b 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -824,6 +824,8 @@ patterns are available:
- `java` suitable for source code in the Java language.
+- `markdown` suitable for Markdown documents.
+
- `matlab` suitable for source code in the MATLAB and Octave languages.
- `objc` suitable for source code in the Objective-C language.
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 1814d2d23c..9e481aec85 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -216,20 +216,26 @@ Here are some example specifications:
----------------------------------------------------
# run "git credential-foo"
-foo
+[credential]
+ helper = foo
# same as above, but pass an argument to the helper
-foo --bar=baz
+[credential]
+ helper = "foo --bar=baz"
# the arguments are parsed by the shell, so use shell
# quoting if necessary
-foo --bar="whitespace arg"
+[credential]
+ helper = "foo --bar='whitespace arg'"
# you can also use an absolute path, which will not use the git wrapper
-/path/to/my/helper --with-arguments
+[credential]
+ helper = "/path/to/my/helper --with-arguments"
# or you can specify your own shell snippet
-!f() { echo "password=`cat $HOME/.secret`"; }; f
+[credential "https://example.com"]
+ username = your_user
+ helper = "!f() { test \"$1\" = get && echo \"password=$(cat $HOME/.secret)\"; }; f"
----------------------------------------------------
Generally speaking, rule (3) above is the simplest for users to specify.
@@ -262,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/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/branch.c b/builtin/branch.c
index 176e524a94..accb61b1aa 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -737,7 +737,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
*/
if (!sorting)
sorting = ref_default_sorting();
- sorting->ignore_case = icase;
+ ref_sorting_icase_all(sorting, icase);
print_ref_list(&filter, sorting, &format);
print_columns(&output, colopts, NULL);
string_list_clear(&output, 0);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0b18591ffa..e9d111bb83 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1544,6 +1544,9 @@ static struct option *add_checkout_path_options(struct checkout_opts *opts,
return newopts;
}
+/* create-branch option (either b or c) */
+static char cb_option = 'b';
+
static int checkout_main(int argc, const char **argv, const char *prefix,
struct checkout_opts *opts, struct option *options,
const char * const usagestr[])
@@ -1586,7 +1589,8 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
}
if ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)
- die(_("-b, -B and --orphan are mutually exclusive"));
+ die(_("-%c, -%c and --orphan are mutually exclusive"),
+ cb_option, toupper(cb_option));
if (opts->overlay_mode == 1 && opts->patch_mode)
die(_("-p and --overlay are mutually exclusive"));
@@ -1605,16 +1609,16 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
BUG("these flags should be non-negative by now");
/*
- * convenient shortcut: "git restore --staged" equals
- * "git restore --staged --source HEAD"
+ * convenient shortcut: "git restore --staged [--worktree]" equals
+ * "git restore --staged [--worktree] --source HEAD"
*/
- if (!opts->from_treeish && opts->checkout_index && !opts->checkout_worktree)
+ if (!opts->from_treeish && opts->checkout_index)
opts->from_treeish = "HEAD";
/*
* From here on, new_branch will contain the branch to be checked out,
* and new_branch_force and new_orphan_branch will tell us which one of
- * -b/-B/--orphan is being used.
+ * -b/-B/-c/-C/--orphan is being used.
*/
if (opts->new_branch_force)
opts->new_branch = opts->new_branch_force;
@@ -1622,7 +1626,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
if (opts->new_orphan_branch)
opts->new_branch = opts->new_orphan_branch;
- /* --track without -b/-B/--orphan should DWIM */
+ /* --track without -c/-C/-b/-B/--orphan should DWIM */
if (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {
const char *argv0 = argv[0];
if (!argc || !strcmp(argv0, "--"))
@@ -1631,7 +1635,7 @@ static int checkout_main(int argc, const char **argv, const char *prefix,
skip_prefix(argv0, "remotes/", &argv0);
argv0 = strchr(argv0, '/');
if (!argv0 || !argv0[1])
- die(_("missing branch name; try -b"));
+ die(_("missing branch name; try -%c"), cb_option);
opts->new_branch = argv0 + 1;
}
@@ -1822,6 +1826,8 @@ int cmd_switch(int argc, const char **argv, const char *prefix)
options = add_common_options(&opts, options);
options = add_common_switch_branch_options(&opts, options);
+ cb_option = 'c';
+
ret = checkout_main(argc, argv, prefix, &opts,
options, switch_branch_usage);
FREE_AND_NULL(options);
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/for-each-ref.c b/builtin/for-each-ref.c
index 465153e853..57489e4eab 100644
--- a/builtin/for-each-ref.c
+++ b/builtin/for-each-ref.c
@@ -70,7 +70,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
if (!sorting)
sorting = ref_default_sorting();
- sorting->ignore_case = icase;
+ ref_sorting_icase_all(sorting, icase);
filter.ignore_case = icase;
filter.name_patterns = argv;
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 a00f91c1a0..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>"),
@@ -418,7 +419,7 @@ static int copy_to_sideband(int in, int out, void *arg)
return 0;
}
-static void hmac(unsigned char *out,
+static void hmac_hash(unsigned char *out,
const char *key_in, size_t key_len,
const char *text, size_t text_len)
{
@@ -463,10 +464,10 @@ static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
unsigned char hash[GIT_MAX_RAWSZ];
strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
- hmac(hash, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
+ hmac_hash(hash, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
strbuf_release(&buf);
- /* RFC 2104 5. HMAC-SHA1-80 */
+ /* RFC 2104 5. HMAC-SHA1 or HMAC-SHA256 */
strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, (int)the_hash_algo->hexsz, hash_to_hex(hash));
return strbuf_detach(&buf, NULL);
}
@@ -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/tag.c b/builtin/tag.c
index b93b7365f4..5cbd80dc3e 100644
--- a/builtin/tag.c
+++ b/builtin/tag.c
@@ -485,7 +485,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
}
if (!sorting)
sorting = ref_default_sorting();
- sorting->ignore_case = icase;
+ ref_sorting_icase_all(sorting, icase);
filter.ignore_case = icase;
if (cmdmode == 'l') {
int ret;
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 aa3adb912f..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)
{
@@ -281,8 +282,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
if (data + graph_size - chunk_lookup <
GRAPH_CHUNKLOOKUP_WIDTH) {
error(_("commit-graph chunk lookup table entry missing; file may be incomplete"));
- free(graph);
- return NULL;
+ goto free_and_return;
}
chunk_id = get_be32(chunk_lookup + 0);
@@ -293,8 +293,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
if (chunk_offset > graph_size - the_hash_algo->rawsz) {
error(_("commit-graph improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
(uint32_t)chunk_offset);
- free(graph);
- return NULL;
+ goto free_and_return;
}
switch (chunk_id) {
@@ -361,8 +360,7 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
if (chunk_repeated) {
error(_("commit-graph chunk id %08x appears multiple times"), chunk_id);
- free(graph);
- return NULL;
+ goto free_and_return;
}
if (last_chunk_id == GRAPH_CHUNKID_OIDLOOKUP)
@@ -381,17 +379,20 @@ struct commit_graph *parse_commit_graph(void *graph_map, size_t graph_size)
/* We need both the bloom chunks to exist together. Else ignore the data */
graph->chunk_bloom_indexes = NULL;
graph->chunk_bloom_data = NULL;
- graph->bloom_filter_settings = NULL;
+ FREE_AND_NULL(graph->bloom_filter_settings);
}
hashcpy(graph->oid.hash, graph->data + graph->data_len - graph->hash_len);
- if (verify_commit_graph_lite(graph)) {
- free(graph);
- return NULL;
- }
+ if (verify_commit_graph_lite(graph))
+ goto free_and_return;
return graph;
+
+free_and_return:
+ free(graph->bloom_filter_settings);
+ free(graph);
+ return NULL;
}
static struct commit_graph *load_commit_graph_one(const char *graph_file,
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-store.c b/credential-store.c
index c010497cb2..294e771681 100644
--- a/credential-store.c
+++ b/credential-store.c
@@ -24,8 +24,8 @@ static int parse_credential_file(const char *fn,
}
while (strbuf_getline_lf(&line, fh) != EOF) {
- credential_from_url(&entry, line.buf);
- if (entry.username && entry.password &&
+ if (!credential_from_url_gently(&entry, line.buf, 1) &&
+ entry.username && entry.password &&
credential_match(c, &entry)) {
found_credential = 1;
if (match_cb) {
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.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/ref-filter.c b/ref-filter.c
index 35776838f4..bf7b70299b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2295,7 +2295,7 @@ static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, stru
if (va->value < vb->value)
cmp = -1;
else if (va->value == vb->value)
- cmp = cmp_fn(a->refname, b->refname);
+ cmp = 0;
else
cmp = 1;
}
@@ -2314,7 +2314,16 @@ static int compare_refs(const void *a_, const void *b_, void *ref_sorting)
if (cmp)
return cmp;
}
- return 0;
+ s = ref_sorting;
+ return s && s->ignore_case ?
+ strcasecmp(a->refname, b->refname) :
+ strcmp(a->refname, b->refname);
+}
+
+void ref_sorting_icase_all(struct ref_sorting *sorting, int flag)
+{
+ for (; sorting; sorting = sorting->next)
+ sorting->ignore_case = !!flag;
}
void ref_array_sort(struct ref_sorting *sorting, struct ref_array *array)
diff --git a/ref-filter.h b/ref-filter.h
index 64330e9601..8ecc33cdfa 100644
--- a/ref-filter.h
+++ b/ref-filter.h
@@ -114,6 +114,8 @@ void ref_array_clear(struct ref_array *array);
int verify_ref_format(struct ref_format *format);
/* Sort the given ref_array as per the ref_sorting provided */
void ref_array_sort(struct ref_sorting *sort, struct ref_array *array);
+/* Set the ignore_case flag for all elements of a sorting list */
+void ref_sorting_icase_all(struct ref_sorting *sorting, int flag);
/* Based on the given format and quote_style, fill the strbuf */
int format_ref_array_item(struct ref_array_item *info,
const struct ref_format *format,
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/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/t0000-basic.sh b/t/t0000-basic.sh
index f58f3deaa8..2ff176cd5d 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -77,9 +77,7 @@ _run_sub_test_lib_test_common () {
# the sub-test.
sane_unset HARNESS_ACTIVE &&
cd "$name" &&
- cat >"$name.sh" <<-EOF &&
- #!$SHELL_PATH
-
+ write_script "$name.sh" "$TEST_SHELL_PATH" <<-EOF &&
test_description='$descr (run in sub test-lib)
This is run in a sub test-lib so that we do not get incorrect
@@ -94,7 +92,6 @@ _run_sub_test_lib_test_common () {
. "\$TEST_DIRECTORY"/test-lib.sh
EOF
cat >>"$name.sh" &&
- chmod +x "$name.sh" &&
export TEST_DIRECTORY &&
TEST_OUTPUT_DIRECTORY=$(pwd) &&
export TEST_OUTPUT_DIRECTORY &&
@@ -103,7 +100,7 @@ _run_sub_test_lib_test_common () {
then
./"$name.sh" "$@" >out 2>err
else
- ! ./"$name.sh" "$@" >out 2>err
+ ! ./"$name.sh" "$@" >out 2>err
fi
)
}
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/t0302-credential-store.sh b/t/t0302-credential-store.sh
index d6b54e8c65..716bf1af9f 100755
--- a/t/t0302-credential-store.sh
+++ b/t/t0302-credential-store.sh
@@ -107,7 +107,6 @@ test_expect_success 'store: if both xdg and home files exist, only store in home
test_must_be_empty "$HOME/.config/git/credentials"
'
-
test_expect_success 'erase: erase matching credentials from both xdg and home files' '
echo "https://home-user:home-pass@example.com" >"$HOME/.git-credentials" &&
mkdir -p "$HOME/.config/git" &&
@@ -120,4 +119,94 @@ test_expect_success 'erase: erase matching credentials from both xdg and home fi
test_must_be_empty "$HOME/.config/git/credentials"
'
+invalid_credential_test() {
+ test_expect_success "get: ignore credentials without $1 as invalid" '
+ echo "$2" >"$HOME/.git-credentials" &&
+ check fill store <<-\EOF
+ protocol=https
+ host=example.com
+ --
+ protocol=https
+ host=example.com
+ username=askpass-username
+ password=askpass-password
+ --
+ askpass: Username for '\''https://example.com'\'':
+ askpass: Password for '\''https://askpass-username@example.com'\'':
+ --
+ EOF
+ '
+}
+
+invalid_credential_test "scheme" ://user:pass@example.com
+invalid_credential_test "valid host/path" https://user:pass@
+invalid_credential_test "username/password" https://pass@example.com
+
+test_expect_success 'get: credentials with DOS line endings are invalid' '
+ printf "https://user:pass@example.com\r\n" >"$HOME/.git-credentials" &&
+ check fill store <<-\EOF
+ protocol=https
+ host=example.com
+ --
+ protocol=https
+ host=example.com
+ username=askpass-username
+ password=askpass-password
+ --
+ askpass: Username for '\''https://example.com'\'':
+ askpass: Password for '\''https://askpass-username@example.com'\'':
+ --
+ EOF
+'
+
+test_expect_success 'get: credentials with path and DOS line endings are valid' '
+ printf "https://user:pass@example.com/repo.git\r\n" >"$HOME/.git-credentials" &&
+ check fill store <<-\EOF
+ url=https://example.com/repo.git
+ --
+ protocol=https
+ host=example.com
+ username=user
+ password=pass
+ --
+ EOF
+'
+
+test_expect_success 'get: credentials with DOS line endings are invalid if path is relevant' '
+ printf "https://user:pass@example.com/repo.git\r\n" >"$HOME/.git-credentials" &&
+ test_config credential.useHttpPath true &&
+ check fill store <<-\EOF
+ url=https://example.com/repo.git
+ --
+ protocol=https
+ host=example.com
+ path=repo.git
+ username=askpass-username
+ password=askpass-password
+ --
+ askpass: Username for '\''https://example.com/repo.git'\'':
+ askpass: Password for '\''https://askpass-username@example.com/repo.git'\'':
+ --
+ EOF
+'
+
+test_expect_success 'get: store file can contain empty/bogus lines' '
+ echo "" >"$HOME/.git-credentials" &&
+ q_to_tab <<-\CREDENTIAL >>"$HOME/.git-credentials" &&
+ #comment
+ Q
+ https://user:pass@example.com
+ CREDENTIAL
+ check fill store <<-\EOF
+ protocol=https
+ host=example.com
+ --
+ protocol=https
+ host=example.com
+ username=user
+ password=pass
+ --
+ EOF
+'
+
test_done
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 63223e13bd..140f459977 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -74,13 +74,19 @@ test_expect_success 'read-tree --no-sparse-checkout with empty .git/info/sparse-
test_expect_success 'read-tree with empty .git/info/sparse-checkout' '
git config core.sparsecheckout true &&
echo >.git/info/sparse-checkout &&
- read_tree_u_must_fail -m -u HEAD &&
+ read_tree_u_must_succeed -m -u HEAD &&
git ls-files --stage >result &&
test_cmp expected result &&
git ls-files -t >result &&
+ cat >expected.swt <<-\EOF &&
+ S init.t
+ S sub/added
+ S sub/addedtoo
+ S subsub/added
+ EOF
test_cmp expected.swt result &&
- test -f init.t &&
- test -f sub/added
+ ! test -f init.t &&
+ ! test -f sub/added
'
test_expect_success 'match directories with trailing slash' '
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index dee99eeec3..88cdde255c 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -106,10 +106,8 @@ test_expect_success 'set enables config' '
cd empty-config &&
test_commit test file &&
test_path_is_missing .git/config.worktree &&
- test_must_fail git sparse-checkout set nothing &&
+ git sparse-checkout set nothing &&
test_path_is_file .git/config.worktree &&
- test_must_fail git config core.sparseCheckout &&
- git sparse-checkout set "/*" &&
test_cmp_config true core.sparseCheckout
)
'
@@ -302,8 +300,8 @@ test_expect_success 'revert to old sparse-checkout on empty update' '
echo >file &&
git add file &&
git commit -m "test" &&
- test_must_fail git sparse-checkout set nothing 2>err &&
- test_i18ngrep "Sparse checkout leaves no entry on working directory" err &&
+ git sparse-checkout set nothing 2>err &&
+ test_i18ngrep ! "Sparse checkout leaves no entry on working directory" err &&
test_i18ngrep ! ".git/index.lock" err &&
git sparse-checkout set file
)
diff --git a/t/t2070-restore.sh b/t/t2070-restore.sh
index 076d0df7fc..89e5a142c9 100755
--- a/t/t2070-restore.sh
+++ b/t/t2070-restore.sh
@@ -69,6 +69,17 @@ test_expect_success 'restore --staged uses HEAD as source' '
test_cmp expected actual
'
+test_expect_success 'restore --worktree --staged uses HEAD as source' '
+ test_when_finished git reset --hard &&
+ git show HEAD:./first.t >expected &&
+ echo dirty >>first.t &&
+ git add first.t &&
+ git restore --worktree --staged first.t &&
+ git show :./first.t >actual &&
+ test_cmp expected actual &&
+ test_cmp expected first.t
+'
+
test_expect_success 'restore --ignore-unmerged ignores unmerged entries' '
git init unmerged &&
(
diff --git a/t/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index 02255a08bf..9d07797579 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -38,6 +38,7 @@ diffpatterns="
golang
html
java
+ markdown
matlab
objc
pascal
diff --git a/t/t4018/markdown-heading-indented b/t/t4018/markdown-heading-indented
new file mode 100644
index 0000000000..1991c2bd45
--- /dev/null
+++ b/t/t4018/markdown-heading-indented
@@ -0,0 +1,6 @@
+Indented headings are allowed, as long as the indent is no more than 3 spaces.
+
+ ### RIGHT
+
+- something
+- ChangeMe
diff --git a/t/t4018/markdown-heading-non-headings b/t/t4018/markdown-heading-non-headings
new file mode 100644
index 0000000000..c479c1a3f1
--- /dev/null
+++ b/t/t4018/markdown-heading-non-headings
@@ -0,0 +1,17 @@
+Headings can be right next to other lines of the file:
+# RIGHT
+Indents of four or more spaces make a code block:
+
+ # code comment, not heading
+
+If there's no space after the final hash, it's not a heading:
+
+#hashtag
+
+Sequences of more than 6 hashes don't make a heading:
+
+####### over-enthusiastic heading
+
+So the detected heading should be right up at the start of this file.
+
+ChangeMe
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/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/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index b3c1092338..da59fadc5d 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -650,17 +650,59 @@ test_atom refs/tags/signed-long contents "subject line
body contents
$sig"
-sort >expected <<EOF
-$(git rev-parse refs/tags/bogo) <committer@example.com> refs/tags/bogo
-$(git rev-parse refs/tags/master) <committer@example.com> refs/tags/master
-EOF
+test_expect_success 'set up multiple-sort tags' '
+ for when in 100000 200000
+ do
+ for email in user1 user2
+ do
+ for ref in ref1 ref2
+ do
+ GIT_COMMITTER_DATE="@$when +0000" \
+ GIT_COMMITTER_EMAIL="$email@example.com" \
+ git tag -m "tag $ref-$when-$email" \
+ multi-$ref-$when-$email || return 1
+ done
+ done
+ done
+'
test_expect_success 'Verify sort with multiple keys' '
- git for-each-ref --format="%(objectname) %(taggeremail) %(refname)" --sort=objectname --sort=taggeremail \
- refs/tags/bogo refs/tags/master > actual &&
+ cat >expected <<-\EOF &&
+ 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
+ 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
+ 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
+ 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
+ 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
+ EOF
+ git for-each-ref \
+ --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
+ --sort=-refname \
+ --sort=taggeremail \
+ --sort=taggerdate \
+ "refs/tags/multi-*" >actual &&
test_cmp expected actual
'
+test_expect_success 'equivalent sorts fall back on refname' '
+ cat >expected <<-\EOF &&
+ 100000 <user1@example.com> refs/tags/multi-ref1-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref1-100000-user2
+ 100000 <user1@example.com> refs/tags/multi-ref2-100000-user1
+ 100000 <user2@example.com> refs/tags/multi-ref2-100000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref1-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref1-200000-user2
+ 200000 <user1@example.com> refs/tags/multi-ref2-200000-user1
+ 200000 <user2@example.com> refs/tags/multi-ref2-200000-user2
+ EOF
+ git for-each-ref \
+ --format="%(taggerdate:unix) %(taggeremail) %(refname)" \
+ --sort=taggerdate \
+ "refs/tags/multi-*" >actual &&
+ test_cmp expected actual
+'
test_expect_success 'do not dereference NULL upon %(HEAD) on unborn branch' '
test_when_finished "git checkout master" &&
@@ -895,4 +937,44 @@ test_expect_success 'for-each-ref --ignore-case ignores case' '
test_cmp expect actual
'
+test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '
+ # name refs numerically to avoid case-insensitive filesystem conflicts
+ nr=0 &&
+ for email in a A b B
+ do
+ for subject in a A b B
+ do
+ GIT_COMMITTER_EMAIL="$email@example.com" \
+ git tag -m "tag $subject" icase-$(printf %02d $nr) &&
+ nr=$((nr+1))||
+ return 1
+ done
+ done &&
+ git for-each-ref --ignore-case \
+ --format="%(taggeremail) %(subject) %(refname)" \
+ --sort=refname \
+ --sort=subject \
+ --sort=taggeremail \
+ refs/tags/icase-* >actual &&
+ cat >expect <<-\EOF &&
+ <a@example.com> tag a refs/tags/icase-00
+ <a@example.com> tag A refs/tags/icase-01
+ <A@example.com> tag a refs/tags/icase-04
+ <A@example.com> tag A refs/tags/icase-05
+ <a@example.com> tag b refs/tags/icase-02
+ <a@example.com> tag B refs/tags/icase-03
+ <A@example.com> tag b refs/tags/icase-06
+ <A@example.com> tag B refs/tags/icase-07
+ <b@example.com> tag a refs/tags/icase-08
+ <b@example.com> tag A refs/tags/icase-09
+ <B@example.com> tag a refs/tags/icase-12
+ <B@example.com> tag A refs/tags/icase-13
+ <b@example.com> tag b refs/tags/icase-10
+ <b@example.com> tag B refs/tags/icase-11
+ <B@example.com> tag b refs/tags/icase-14
+ <B@example.com> tag B refs/tags/icase-15
+ EOF
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 1b221951a8..baf94546da 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -677,14 +677,16 @@ die () {
file_lineno () {
test -z "$GIT_TEST_FRAMEWORK_SELFTEST" && test -n "$BASH" || return 0
- local i
- for i in ${!BASH_SOURCE[*]}
- do
- case $i,"${BASH_SOURCE[$i]##*/}" in
- 0,t[0-9]*.sh) echo "t/${BASH_SOURCE[$i]}:$LINENO: ${1+$1: }"; return;;
- *,t[0-9]*.sh) echo "t/${BASH_SOURCE[$i]}:${BASH_LINENO[$(($i-1))]}: ${1+$1: }"; return;;
- esac
- done
+ eval '
+ local i
+ for i in ${!BASH_SOURCE[*]}
+ do
+ case $i,"${BASH_SOURCE[$i]##*/}" in
+ 0,t[0-9]*.sh) echo "t/${BASH_SOURCE[$i]}:$LINENO: ${1+$1: }"; return;;
+ *,t[0-9]*.sh) echo "t/${BASH_SOURCE[$i]}:${BASH_LINENO[$(($i-1))]}: ${1+$1: }"; return;;
+ esac
+ done
+ '
}
GIT_EXIT_OK=
diff --git a/unpack-trees.c b/unpack-trees.c
index 6bbf58d28e..1fe3764f2b 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -1677,8 +1677,6 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
}
if (!o->skip_sparse_checkout) {
- int empty_worktree = 1;
-
/*
* Sparse checkout loop #2: set NEW_SKIP_WORKTREE on entries not in loop #1
* If they will have NEW_SKIP_WORKTREE, also set CE_SKIP_WORKTREE
@@ -1706,19 +1704,6 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
if (apply_sparse_checkout(&o->result, ce, o))
ret = 1;
-
- if (!ce_skip_worktree(ce))
- empty_worktree = 0;
- }
- /*
- * Sparse checkout is meant to narrow down checkout area
- * but it does not make sense to narrow down to empty working
- * tree. This is usually a mistake in sparse checkout rules.
- * Do not allow users to do that.
- */
- if (o->result.cache_nr && empty_worktree) {
- ret = unpack_failed(o, "Sparse checkout leaves no entry on working directory");
- goto done;
}
if (ret == 1) {
/*
@@ -1779,7 +1764,7 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
{
enum update_sparsity_result ret = UPDATE_SPARSITY_SUCCESS;
struct pattern_list pl;
- int i, empty_worktree;
+ int i;
unsigned old_show_all_errors;
int free_pattern_list = 0;
@@ -1810,7 +1795,6 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
/* Then loop over entries and update/remove as needed */
ret = UPDATE_SPARSITY_SUCCESS;
- empty_worktree = 1;
for (i = 0; i < o->src_index->cache_nr; i++) {
struct cache_entry *ce = o->src_index->cache[i];
@@ -1824,28 +1808,12 @@ enum update_sparsity_result update_sparsity(struct unpack_trees_options *o)
if (apply_sparse_checkout(o->src_index, ce, o))
ret = UPDATE_SPARSITY_WARNINGS;
-
- if (!ce_skip_worktree(ce))
- empty_worktree = 0;
- }
-
- /*
- * Sparse checkout is meant to narrow down checkout area
- * but it does not make sense to narrow down to empty working
- * tree. This is usually a mistake in sparse checkout rules.
- * Do not allow users to do that.
- */
- if (o->src_index->cache_nr && empty_worktree) {
- unpack_failed(o, "Sparse checkout leaves no entry on working directory");
- ret = UPDATE_SPARSITY_INDEX_UPDATE_FAILURES;
- goto done;
}
skip_sparse_checkout:
if (check_updates(o, o->src_index))
ret = UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES;
-done:
display_warning_msgs(o);
o->show_all_errors = old_show_all_errors;
if (free_pattern_list)
diff --git a/upload-pack.c b/upload-pack.c
index 902d0ad5e1..613a960624 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)
diff --git a/userdiff.c b/userdiff.c
index 30ab42df8e..1df884ef0b 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -79,6 +79,9 @@ PATTERNS("java",
"|[-+0-9.e]+[fFlL]?|0[xXbB]?[0-9a-fA-F]+[lL]?"
"|[-+*/<>%&^|=!]="
"|--|\\+\\+|<<=?|>>>?=?|&&|\\|\\|"),
+PATTERNS("markdown",
+ "^ {0,3}#{1,6}[ \t].*",
+ "[^<>= \t]+"),
PATTERNS("matlab",
/*
* Octave pattern is mostly the same as matlab, except that '%%%' and