Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
064468e
sparse-checkout: remove use of the_repository
derrickstolee Sep 12, 2025
2520efd
sparse-checkout: add basics of 'clean' command
derrickstolee Sep 12, 2025
a8077c1
sparse-checkout: match some 'clean' behavior
derrickstolee Sep 12, 2025
1588e83
dir: add generic "walk all files" helper
derrickstolee Sep 12, 2025
5b5a7f5
sparse-checkout: add --verbose option to 'clean'
derrickstolee Sep 12, 2025
66c11bd
sparse-index: point users to new 'clean' action
derrickstolee Sep 12, 2025
592d2a9
t: expand tests around sparse merges and clean
derrickstolee Sep 12, 2025
5f91b2c
Merge branch 'ps/rust-balloon' into ps/ci-rust
gitster Oct 7, 2025
1562d9a
Merge branch 'ps/gitlab-ci-windows-improvements' into ps/ci-rust
gitster Oct 7, 2025
db67409
doc: git-tag: stop focusing on GPG signed tags
chriscool Oct 13, 2025
e204a16
lib-gpg: allow tests with GPGSM or GPGSSH prereq first
chriscool Oct 13, 2025
132e566
t9350: properly count annotated tags
chriscool Oct 13, 2025
31f375c
fast-export: handle all kinds of tag signatures
chriscool Oct 13, 2025
d8ce08a
fast-import: add '--signed-tags=<mode>' option
chriscool Oct 13, 2025
0de14fe
ci: deduplicate calls to `apt-get update`
pks-t Oct 15, 2025
e75cd05
ci: check formatting of our Rust code
pks-t Oct 15, 2025
03f3900
rust/varint: add safety comments
pks-t Oct 15, 2025
4b44c46
ci: check for common Rust mistakes via Clippy
pks-t Oct 15, 2025
1b43384
ci: verify minimum supported Rust version
pks-t Oct 15, 2025
e509b5b
rust: support for Windows
pks-t Oct 15, 2025
c32aa72
sparse-index: improve advice message instructions
derrickstolee Oct 20, 2025
54ac380
Merge branch 'ds/sparse-checkout-clean'
gitster Oct 28, 2025
3deb97f
Merge branch 'cc/fast-import-strip-signed-tags'
gitster Oct 28, 2025
fe95c55
Merge branch 'ps/ci-rust'
gitster Oct 28, 2025
57da342
The 25th batch
gitster Oct 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,21 @@ jobs:
- run: ci/install-dependencies.sh
- run: ci/run-static-analysis.sh
- run: ci/check-directional-formatting.bash
rust-analysis:
needs: ci-config
if: needs.ci-config.outputs.enabled == 'yes'
env:
jobname: RustAnalysis
CI_JOB_IMAGE: ubuntu:rolling
runs-on: ubuntu-latest
container: ubuntu:rolling
concurrency:
group: rust-analysis-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v4
- run: ci/install-dependencies.sh
- run: ci/run-rust-checks.sh
sparse:
needs: ci-config
if: needs.ci-config.outputs.enabled == 'yes'
Expand Down
13 changes: 12 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ test:mingw64:
- saas-windows-medium-amd64
before_script:
- *windows_before_script
- choco install -y git meson ninja
- choco install -y git meson ninja rust-ms
- Import-Module $env:ChocolateyInstall\helpers\chocolateyProfile.psm1
- refreshenv

Expand Down Expand Up @@ -212,6 +212,17 @@ static-analysis:
- ./ci/run-static-analysis.sh
- ./ci/check-directional-formatting.bash

rust-analysis:
image: ubuntu:rolling
stage: analyze
needs: [ ]
variables:
jobname: RustAnalysis
before_script:
- ./ci/install-dependencies.sh
script:
- ./ci/run-rust-checks.sh

check-whitespace:
image: ubuntu:latest
stage: analyze
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "gitcore"
version = "0.1.0"
edition = "2018"
rust-version = "1.49.0"

[lib]
crate-type = ["staticlib"]
Expand Down
9 changes: 9 additions & 0 deletions Documentation/RelNotes/2.52.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ UI, Workflows & Features

* Show 'P'ipe command in "git add -p".

* "git sparse-checkout" subcommand learned a new "clean" action to
prune otherwise unused working-tree files that are outside the
areas of interest.

* "git fast-import" is taught to handle signed tags, just like it
recently learned to handle signed commits, in different ways.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand Down Expand Up @@ -137,6 +144,8 @@ Performance, Internal Implementation, Development Support etc.
* Build procedure for a few credential helpers (in contrib/) have
been updated.

* CI improvements to handle the recent Rust integration better.


Fixes since v2.51
-----------------
Expand Down
5 changes: 5 additions & 0 deletions Documentation/git-fast-import.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ fast-import stream! This option is enabled automatically for
remote-helpers that use the `import` capability, as they are
already trusted to run their own code.

--signed-tags=(verbatim|warn-verbatim|warn-strip|strip|abort)::
Specify how to handle signed tags. Behaves in the same way
as the same option in linkgit:git-fast-export[1], except that
default is 'verbatim' (instead of 'abort').

--signed-commits=(verbatim|warn-verbatim|warn-strip|strip|abort)::
Specify how to handle signed commits. Behaves in the same way
as the same option in linkgit:git-fast-export[1], except that
Expand Down
33 changes: 32 additions & 1 deletion Documentation/git-sparse-checkout.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ git-sparse-checkout - Reduce your working tree to a subset of tracked files
SYNOPSIS
--------
[verse]
'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules) [<options>]
'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules | clean) [<options>]


DESCRIPTION
Expand Down Expand Up @@ -111,6 +111,37 @@ flags, with the same meaning as the flags from the `set` command, in order
to change which sparsity mode you are using without needing to also respecify
all sparsity paths.

'clean'::
Opportunistically remove files outside of the sparse-checkout
definition. This command requires cone mode to use recursive
directory matches to determine which files should be removed. A
file is considered for removal if it is contained within a tracked
directory that is outside of the sparse-checkout definition.
+
Some special cases, such as merge conflicts or modified files outside of
the sparse-checkout definition could lead to keeping files that would
otherwise be removed. Resolve conflicts, stage modifications, and use
`git sparse-checkout reapply` in conjunction with `git sparse-checkout
clean` to resolve these cases.
+
This command can be used to be sure the sparse index works efficiently,
though it does not require enabling the sparse index feature via the
`index.sparse=true` configuration.
+
To prevent accidental deletion of worktree files, the `clean` subcommand
will not delete any files without the `-f` or `--force` option, unless
the `clean.requireForce` config option is set to `false`.
+
The `--dry-run` option will list the directories that would be removed
without deleting them. Running in this mode can be helpful to predict the
behavior of the clean comand or to determine which kinds of files are left
in the sparse directories.
+
The `--verbose` option will list every file within the directories that
are considered for removal. This option is helpful to determine if those
files are actually important or perhaps to explain why the directory is
still present despite the current sparse-checkout.

'disable'::
Disable the `core.sparseCheckout` config setting, and restore the
working directory to include all files.
Expand Down
48 changes: 33 additions & 15 deletions Documentation/git-tag.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ git-tag(1)

NAME
----
git-tag - Create, list, delete or verify a tag object signed with GPG
git-tag - Create, list, delete or verify tags


SYNOPSIS
Expand Down Expand Up @@ -38,15 +38,17 @@ and `-a`, `-s`, and `-u <key-id>` are absent, `-a` is implied.
Otherwise, a tag reference that points directly at the given object
(i.e., a lightweight tag) is created.

A GnuPG signed tag object will be created when `-s` or `-u
<key-id>` is used. When `-u <key-id>` is not used, the
committer identity for the current user is used to find the
GnuPG key for signing. The configuration variable `gpg.program`
is used to specify custom GnuPG binary.
A cryptographically signed tag object will be created when `-s` or
`-u <key-id>` is used. The signing backend (GPG, X.509, SSH, etc.) is
controlled by the `gpg.format` configuration variable, defaulting to
OpenPGP. When `-u <key-id>` is not used, the committer identity for
the current user is used to find the key for signing. The
configuration variable `gpg.program` is used to specify a custom
signing binary.

Tag objects (created with `-a`, `-s`, or `-u`) are called "annotated"
tags; they contain a creation date, the tagger name and e-mail, a
tagging message, and an optional GnuPG signature. Whereas a
tagging message, and an optional cryptographic signature. Whereas a
"lightweight" tag is simply a name for an object (usually a commit
object).

Expand All @@ -64,18 +66,23 @@ OPTIONS

`-s`::
`--sign`::
Make a GPG-signed tag, using the default e-mail address's key.
The default behavior of tag GPG-signing is controlled by `tag.gpgSign`
configuration variable if it exists, or disabled otherwise.
See linkgit:git-config[1].
Make a cryptographically signed tag, using the default signing
key. The signing backend used depends on the `gpg.format`
configuration variable. The default key is determined by the
backend. For GPG, it's based on the committer's email address,
while for SSH it may be a specific key file or agent
identity. See linkgit:git-config[1].

`--no-sign`::
Override `tag.gpgSign` configuration variable that is
set to force each and every tag to be signed.

`-u <key-id>`::
`--local-user=<key-id>`::
Make a GPG-signed tag, using the given key.
Make a cryptographically signed tag using the given key. The
format of the <key-id> and the backend used depend on the
`gpg.format` configuration variable. See
linkgit:git-config[1].

`-f`::
`--force`::
Expand All @@ -87,7 +94,7 @@ OPTIONS

`-v`::
`--verify`::
Verify the GPG signature of the given tag names.
Verify the cryptographic signature of the given tags.

`-n<num>`::
_<num>_ specifies how many lines from the annotation, if any,
Expand Down Expand Up @@ -235,12 +242,23 @@ it in the repository configuration as follows:

-------------------------------------
[user]
signingKey = <gpg-key-id>
signingKey = <key-id>
-------------------------------------

The signing backend can be chosen via the `gpg.format` configuration
variable, which defaults to `openpgp`. See linkgit:git-config[1]
for a list of other supported formats.

The path to the program used for each signing backend can be specified
with the `gpg.<format>.program` configuration variable. For the
`openpgp` backend, `gpg.program` can be used as a synonym for
`gpg.openpgp.program`. See linkgit:git-config[1] for details.

`pager.tag` is only respected when listing tags, i.e., when `-l` is
used or implied. The default is to use a pager.
See linkgit:git-config[1].

See linkgit:git-config[1] for more details and other configuration
variables.

DISCUSSION
----------
Expand Down
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -927,10 +927,17 @@ export PYTHON_PATH
TEST_SHELL_PATH = $(SHELL_PATH)

LIB_FILE = libgit.a

ifdef DEBUG
RUST_LIB = target/debug/libgitcore.a
RUST_TARGET_DIR = target/debug
else
RUST_LIB = target/release/libgitcore.a
RUST_TARGET_DIR = target/release
endif

ifeq ($(uname_S),Windows)
RUST_LIB = $(RUST_TARGET_DIR)/gitcore.lib
else
RUST_LIB = $(RUST_TARGET_DIR)/libgitcore.a
endif

GITLIBS = common-main.o $(LIB_FILE)
Expand Down Expand Up @@ -1556,6 +1563,9 @@ ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
ifdef WITH_RUST
BASIC_CFLAGS += -DWITH_RUST
GITLIBS += $(RUST_LIB)
ifeq ($(uname_S),Windows)
EXTLIBS += -luserenv
endif
endif

ifdef SANITIZE
Expand Down
7 changes: 3 additions & 4 deletions builtin/fast-export.c
Original file line number Diff line number Diff line change
Expand Up @@ -931,9 +931,8 @@ static void handle_tag(const char *name, struct tag *tag)

/* handle signed tags */
if (message) {
const char *signature = strstr(message,
"\n-----BEGIN PGP SIGNATURE-----\n");
if (signature)
size_t sig_offset = parse_signed_buffer(message, message_size);
if (sig_offset < message_size)
switch (signed_tag_mode) {
case SIGN_ABORT:
die("encountered signed tag %s; use "
Expand All @@ -950,7 +949,7 @@ static void handle_tag(const char *name, struct tag *tag)
oid_to_hex(&tag->object.oid));
/* fallthru */
case SIGN_STRIP:
message_size = signature + 1 - message;
message_size = sig_offset;
break;
}
}
Expand Down
43 changes: 43 additions & 0 deletions builtin/fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ static int global_argc;
static const char **global_argv;
static const char *global_prefix;

static enum sign_mode signed_tag_mode = SIGN_VERBATIM;
static enum sign_mode signed_commit_mode = SIGN_VERBATIM;

/* Memory pools */
Expand Down Expand Up @@ -2963,6 +2964,43 @@ static void parse_new_commit(const char *arg)
b->last_commit = object_count_by_type[OBJ_COMMIT];
}

static void handle_tag_signature(struct strbuf *msg, const char *name)
{
size_t sig_offset = parse_signed_buffer(msg->buf, msg->len);

/* If there is no signature, there is nothing to do. */
if (sig_offset >= msg->len)
return;

switch (signed_tag_mode) {

/* First, modes that don't change anything */
case SIGN_ABORT:
die(_("encountered signed tag; use "
"--signed-tags=<mode> to handle it"));
case SIGN_WARN_VERBATIM:
warning(_("importing a tag signature verbatim for tag '%s'"), name);
/* fallthru */
case SIGN_VERBATIM:
/* Nothing to do, the signature will be put into the imported tag. */
break;

/* Second, modes that remove the signature */
case SIGN_WARN_STRIP:
warning(_("stripping a tag signature for tag '%s'"), name);
/* fallthru */
case SIGN_STRIP:
/* Truncate the buffer to remove the signature */
strbuf_setlen(msg, sig_offset);
break;

/* Third, BUG */
default:
BUG("invalid signed_tag_mode value %d from tag '%s'",
signed_tag_mode, name);
}
}

static void parse_new_tag(const char *arg)
{
static struct strbuf msg = STRBUF_INIT;
Expand Down Expand Up @@ -3026,6 +3064,8 @@ static void parse_new_tag(const char *arg)
/* tag payload/message */
parse_data(&msg, 0, NULL);

handle_tag_signature(&msg, t->name);

/* build the tag object */
strbuf_reset(&new_data);

Expand Down Expand Up @@ -3546,6 +3586,9 @@ static int parse_one_option(const char *option)
} else if (skip_prefix(option, "signed-commits=", &option)) {
if (parse_sign_mode(option, &signed_commit_mode))
usagef(_("unknown --signed-commits mode '%s'"), option);
} else if (skip_prefix(option, "signed-tags=", &option)) {
if (parse_sign_mode(option, &signed_tag_mode))
usagef(_("unknown --signed-tags mode '%s'"), option);
} else if (!strcmp(option, "quiet")) {
show_stats = 0;
quiet = 1;
Expand Down
Loading