Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f82e430
odb: fix subtle logic to check whether an alternate is usable
pks-t Nov 3, 2025
0820a4b
odb: introduce `odb_source_new()`
pks-t Nov 3, 2025
c2da110
odb: adjust naming to free object sources
pks-t Nov 3, 2025
0cc12de
object-file: move `fetch_if_missing`
pks-t Nov 3, 2025
ece43d9
object-file: introduce `struct odb_source_loose`
pks-t Nov 3, 2025
90a93f9
object-file: move loose object cache into loose source
pks-t Nov 3, 2025
be659c9
object-file: hide internals when we need to reprepare loose sources
pks-t Nov 3, 2025
376016e
object-file: move loose object map into loose source
pks-t Nov 3, 2025
ff7ad5c
object-file: read objects via the loose object source
pks-t Nov 3, 2025
05130c6
object-file: rename `has_loose_object()`
pks-t Nov 3, 2025
f2bd88a
object-file: refactor freshening of objects
pks-t Nov 3, 2025
bfb1b2b
object-file: rename `write_object_file()`
pks-t Nov 3, 2025
3e5e360
object-file: refactor writing objects via a stream
pks-t Nov 3, 2025
e031fa1
replay: use die_for_incompatible_opt2() for option validation
edith007 Nov 5, 2025
15cd4ef
replay: make atomic ref updates the default behavior
edith007 Nov 5, 2025
336ac90
replay: add replay.refAction config option
edith007 Nov 5, 2025
46207a5
doc: clarify server behavior for invalid 'want' lines in HTTP protocol
QueenJcloud Nov 5, 2025
42ed046
attr: avoid recursion when expanding attribute macros
peff Nov 11, 2025
4580bcd
osxkeychain: avoid incorrectly skipping store operation
KojiNakamaru Nov 14, 2025
df90ecc
doc: commit: link to git-status(1) on all format options
LemmingAvalanche Nov 14, 2025
66c78e0
object-file: disallow adding submodules of different hash algo
bk2204 Nov 15, 2025
6fe288b
read-cache: drop submodule check from add_to_cache()
peff Nov 15, 2025
878fef8
t/unit-tests: add UTF-8 width tests for CJK chars
jiangxin Nov 15, 2025
7a03a10
builtin/repo: fix table alignment for UTF-8 characters
jiangxin Nov 15, 2025
54f7817
Merge branch 'jk/attr-macroexpand-wo-recursion'
gitster Nov 24, 2025
d91d79f
Merge branch 'bc/submodule-force-same-hash'
gitster Nov 24, 2025
9370a6b
Merge branch 'sa/replay-atomic-ref-updates'
gitster Nov 24, 2025
05ce3ab
Merge branch 'qj/doc-http-bad-want-response'
gitster Nov 24, 2025
a545103
Merge branch 'ps/object-source-loose'
gitster Nov 24, 2025
aa934e0
Merge branch 'kh/doc-commit-extra-references'
gitster Nov 24, 2025
861312b
Merge branch 'kn/osxkeychain-idempotent-store-fix'
gitster Nov 24, 2025
a5d5c50
Merge branch 'jx/repo-struct-utf8width-fix'
gitster Nov 24, 2025
6ab38b7
The third batch
gitster Nov 24, 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
33 changes: 32 additions & 1 deletion Documentation/RelNotes/2.53.0.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ UI, Workflows & Features
* "git maintenance" command learned "is-needed" subcommand to tell if
it is necessary to perform various maintenance tasks.

* "git replay" (experimental) learned to perform ref updates itself
in a transaction by default, instead of emitting where each refs
should point at and leaving the actual update to another command.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
Expand All @@ -22,10 +26,37 @@ Performance, Internal Implementation, Development Support etc.
changes, disable rename/copy detection to skip more expensive
processing whose result will be discarded anyway.

* A part of code paths that deals with loose objects has been cleaned
up.


Fixes since v2.51
Fixes since v2.52
-----------------

* Ever since we added whitespace rules for this project, we misspelt
an entry, which has been corrected.
(merge 358e94dc70 jc/gitattributes-whitespace-no-indent-fix later to maint).

* The code to expand attribute macros has been rewritten to avoid
recursion to avoid running out of stack space in an uncontrolled
way.
(merge 42ed046866 jk/attr-macroexpand-wo-recursion later to maint).

* Adding a repository that uses a different hash function is a no-no,
but "git submodule add" did nt prevent it, which has been corrected.
(merge 6fe288bfbc bc/submodule-force-same-hash later to maint).

* An earlier check added to osx keychain credential helper to avoid
storing the credential itself supplied was overeager and rejected
credential material supplied by other helper backends that it would
have wanted to store, which has been corrected.
(merge 4580bcd235 kn/osxkeychain-idempotent-store-fix later to maint).

* The "git repo structure" subcommand tried to align its output but
mixed up byte count and display column width, which has been
corrected.
(merge 7a03a10a3a jx/repo-struct-utf8width-fix later to maint).

* Other code cleanup, docfix, build fix, etc.
(merge 46207a54cc qj/doc-http-bad-want-response later to maint).
(merge df90eccd93 kh/doc-commit-extra-references later to maint).
11 changes: 11 additions & 0 deletions Documentation/config/replay.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
replay.refAction::
Specifies the default mode for handling reference updates in
`git replay`. The value can be:
+
--
* `update`: Update refs directly using an atomic transaction (default behavior).
* `print`: Output update-ref commands for pipeline use.
--
+
This setting can be overridden with the `--ref-action` command-line option.
When not configured, `git replay` defaults to `update` mode.
10 changes: 6 additions & 4 deletions Documentation/git-commit.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -146,20 +146,22 @@ See linkgit:git-rebase[1] for details.
linkgit:git-status[1] for details. Implies `--dry-run`.

`--branch`::
Show the branch and tracking info even in short-format.
Show the branch and tracking info even in short-format. See
linkgit:git-status[1] for details.

`--porcelain`::
When doing a dry-run, give the output in a porcelain-ready
format. See linkgit:git-status[1] for details. Implies
`--dry-run`.

`--long`::
When doing a dry-run, give the output in the long-format.
Implies `--dry-run`.
When doing a dry-run, give the output in the long-format. This
is the default output of linkgit:git-status[1]. Implies
`--dry-run`.

`-z`::
`--null`::
When showing `short` or `porcelain` status output, print the
When showing `short` or `porcelain` linkgit:git-status[1] output, print the
filename verbatim and terminate the entries with _NUL_, instead of _LF_.
If no format is given, implies the `--porcelain` output format.
Without the `-z` option, filenames with "unusual" characters are
Expand Down
63 changes: 41 additions & 22 deletions Documentation/git-replay.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t
SYNOPSIS
--------
[verse]
(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) [--ref-action[=<mode>]] <revision-range>...

DESCRIPTION
-----------

Takes ranges of commits and replays them onto a new location. Leaves
the working tree and the index untouched, and updates no references.
The output of this command is meant to be used as input to
`git update-ref --stdin`, which would update the relevant branches
the working tree and the index untouched. By default, updates the
relevant references using an atomic transaction (all refs update or
none). Use `--ref-action=print` to avoid automatic ref updates and
instead get update commands that can be piped to `git update-ref --stdin`
(see the OUTPUT section below).

THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
Expand All @@ -29,18 +30,29 @@ OPTIONS
Starting point at which to create the new commits. May be any
valid commit, and not just an existing branch name.
+
When `--onto` is specified, the update-ref command(s) in the output will
update the branch(es) in the revision range to point at the new
commits, similar to the way how `git rebase --update-refs` updates
multiple branches in the affected range.
When `--onto` is specified, the branch(es) in the revision range will be
updated to point at the new commits, similar to the way `git rebase --update-refs`
updates multiple branches in the affected range.

--advance <branch>::
Starting point at which to create the new commits; must be a
branch name.
+
When `--advance` is specified, the update-ref command(s) in the output
will update the branch passed as an argument to `--advance` to point at
the new commits (in other words, this mimics a cherry-pick operation).
The history is replayed on top of the <branch> and <branch> is updated to
point at the tip of the resulting history. This is different from `--onto`,
which uses the target only as a starting point without updating it.

--ref-action[=<mode>]::
Control how references are updated. The mode can be:
+
--
* `update` (default): Update refs directly using an atomic transaction.
All refs are updated or none are (all-or-nothing behavior).
* `print`: Output update-ref commands for pipeline use. This is the
traditional behavior where output can be piped to `git update-ref --stdin`.
--
+
The default mode can be configured via the `replay.refAction` configuration variable.

<revision-range>::
Range of commits to replay. More than one <revision-range> can
Expand All @@ -54,8 +66,11 @@ include::rev-list-options.adoc[]
OUTPUT
------

When there are no conflicts, the output of this command is usable as
input to `git update-ref --stdin`. It is of the form:
By default, or with `--ref-action=update`, this command produces no output on
success, as refs are updated directly using an atomic transaction.

When using `--ref-action=print`, the output is usable as input to
`git update-ref --stdin`. It is of the form:

update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
Expand All @@ -81,40 +96,44 @@ To simply rebase `mybranch` onto `target`:

------------
$ git replay --onto target origin/main..mybranch
------------

The refs are updated atomically and no output is produced on success.

To see what would be updated without actually updating:

------------
$ git replay --ref-action=print --onto target origin/main..mybranch
update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
------------

To cherry-pick the commits from mybranch onto target:

------------
$ git replay --advance target origin/main..mybranch
update refs/heads/target ${NEW_target_HASH} ${OLD_target_HASH}
------------

Note that the first two examples replay the exact same commits and on
top of the exact same new base, they only differ in that the first
provides instructions to make mybranch point at the new commits and
the second provides instructions to make target point at them.
updates mybranch to point at the new commits and the second updates
target to point at them.

What if you have a stack of branches, one depending upon another, and
you'd really like to rebase the whole set?

------------
$ git replay --contained --onto origin/main origin/main..tipbranch
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}
------------

All three branches (`branch1`, `branch2`, and `tipbranch`) are updated
atomically.

When calling `git replay`, one does not need to specify a range of
commits to replay using the syntax `A..B`; any range expression will
do:

------------
$ git replay --onto origin/main ^base branch1 branch2 branch3
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
------------

This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
Expand Down
3 changes: 2 additions & 1 deletion Documentation/gitprotocol-http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,8 @@ If no "want" objects are received, send an error:
TODO: Define error if no "want" lines are requested.

If any "want" object is not reachable, send an error:
TODO: Define error if an invalid "want" is requested.
When a Git server receives an invalid or malformed `want` line, it
responds with an error message that includes the offending object name.

Create an empty list, `s_common`.

Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1525,6 +1525,7 @@ CLAR_TEST_SUITES += u-string-list
CLAR_TEST_SUITES += u-strvec
CLAR_TEST_SUITES += u-trailer
CLAR_TEST_SUITES += u-urlmatch-normalization
CLAR_TEST_SUITES += u-utf8-width
CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o
Expand Down
50 changes: 34 additions & 16 deletions attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1064,24 +1064,52 @@ static int path_matches(const char *pathname, int pathlen,
pattern, prefix, pat->patternlen);
}

static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
struct attr_state_queue {
const struct attr_state **items;
size_t alloc, nr;
};

static void attr_state_queue_push(struct attr_state_queue *t,
const struct match_attr *a)
{
for (size_t i = 0; i < a->num_attr; i++) {
ALLOC_GROW(t->items, t->nr + 1, t->alloc);
t->items[t->nr++] = &a->state[i];
}
}

static const struct attr_state *attr_state_queue_pop(struct attr_state_queue *t)
{
return t->nr ? t->items[--t->nr] : NULL;
}

static void attr_state_queue_release(struct attr_state_queue *t)
{
free(t->items);
}

static int fill_one(struct all_attrs_item *all_attrs,
const struct match_attr *a, int rem)
{
size_t i;
struct attr_state_queue todo = { 0 };
const struct attr_state *state;

for (i = a->num_attr; rem > 0 && i > 0; i--) {
const struct git_attr *attr = a->state[i - 1].attr;
attr_state_queue_push(&todo, a);
while (rem > 0 && (state = attr_state_queue_pop(&todo))) {
const struct git_attr *attr = state->attr;
const char **n = &(all_attrs[attr->attr_nr].value);
const char *v = a->state[i - 1].setto;
const char *v = state->setto;

if (*n == ATTR__UNKNOWN) {
const struct all_attrs_item *item =
&all_attrs[attr->attr_nr];
*n = v;
rem--;
rem = macroexpand_one(all_attrs, attr->attr_nr, rem);
if (item->macro && item->value == ATTR__TRUE)
attr_state_queue_push(&todo, item->macro);
}
}
attr_state_queue_release(&todo);
return rem;
}

Expand All @@ -1106,16 +1134,6 @@ static int fill(const char *path, int pathlen, int basename_offset,
return rem;
}

static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem)
{
const struct all_attrs_item *item = &all_attrs[nr];

if (item->macro && item->value == ATTR__TRUE)
return fill_one(all_attrs, item->macro, rem);
else
return rem;
}

/*
* Marks the attributes which are macros based on the attribute stack.
* This prevents having to search through the attribute stack each time
Expand Down
4 changes: 2 additions & 2 deletions builtin/pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -1715,7 +1715,7 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
*/
struct odb_source *source = the_repository->objects->sources->next;
for (; source; source = source->next)
if (has_loose_object(source, oid))
if (odb_source_loose_has_object(source, oid))
return 0;
}

Expand Down Expand Up @@ -3976,7 +3976,7 @@ static void add_cruft_object_entry(const struct object_id *oid, enum object_type
int found = 0;

for (; !found && source; source = source->next)
if (has_loose_object(source, oid))
if (odb_source_loose_has_object(source, oid))
found = 1;

/*
Expand Down
Loading