Commit Graph

82403 Commits (20c0e7c0fb98c217fa676fa78369db4069ba6563)

Author SHA1 Message Date
Junio C Hamano 20c0e7c0fb Sync with 'master' 2026-09-07 09:33:53 -07:00
Junio C Hamano d3bf064487 Merge branch 'jk/submodule-error-leak' into next
The error path in 'git submodule--helper' has been updated to plug a
memory leak when a repository handle could not be obtained,
leveraging an updated idempotent repo_clear().

* jk/submodule-error-leak:
  submodule--helper: free URL when repository setup fails
  repository: make repo_clear() idempotent
2026-09-07 09:33:38 -07:00
Junio C Hamano 8a2a1bb827 Merge branch 'wf/imap-send-draft' into next
The 'git imap-send' command has been taught to take the '--draft'
option to mark uploaded messages as drafts, which helps some email
clients render them properly for editing and sending.

* wf/imap-send-draft:
  imap-send: add --draft to set IMAP \Draft flag
2026-09-07 09:33:38 -07:00
Junio C Hamano e1faacbfe1 Merge branch 'en/no-amend-during-conflicts' into next
Teach 'am', 'revert', and 'rebase' that running 'commit --amend' or a
partial 'commit <paths>' makes no sense during operations that stop
and return control to the user to resolve conflicts left in the
working tree, just like 'cherry-pick' and 'merge' do.

* en/no-amend-during-conflicts:
  commit: refuse partial commits during conflict resolution
  commit: refuse to amend during conflict resolution
  commit: reword the empty-commit rebase amend error
  commit: allow a partial commit when a rebase pick becomes empty
  commit: clarify FROM_REBASE_PICK and is_from_rebase() names
2026-09-07 09:33:37 -07:00
Junio C Hamano 9ceb1bfd64 Merge branch 'mm/lib-httpd-cgi-safe' into next
CGI helper scripts used by HTTP-related test scripts have been updated
to use atomic filesystem operations, preventing race conditions when
Apache handles concurrent requests.

* mm/lib-httpd-cgi-safe:
  t/lib-httpd: document writing concurrency-safe CGI helpers
  t/lib-httpd: make http-429 first-request check atomic
  t/lib-httpd: fix apply-one-time-script race under concurrent requests
2026-09-07 09:33:37 -07:00
Junio C Hamano b8242b093d The 23rd batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-07 09:32:06 -07:00
Junio C Hamano d595003219 Merge branch 'yn/worktree-repair-relative'
The git worktree repair command failed to rewrite the .git file of
a working tree from a relative path to an absolute path when the
command was run in the working tree itself. The
read_gitfile_gently() function was modified to also return whether
the path originally recorded in the file was absolute, and this new
capability is used to correctly detect such mismatches.

* yn/worktree-repair-relative:
  worktree repair: detect relative path in .git file correctly
2026-09-07 09:32:06 -07:00
Junio C Hamano 098d38059e Merge branch 'll/zsh-complete-git-potty-options'
The zsh completion script (in 'contrib/') has been updated to
correctly locate the Git command after global options like '-C' by
properly skipping them, similar to how the bash completion does.

* ll/zsh-complete-git-potty-options:
  completion: zsh: support completion after "git -C <path>"
2026-09-07 09:32:06 -07:00
Junio C Hamano 8043d64be4 Merge branch 'gr/add-e-use-apply-api'
The application of the edited patch in 'git add -e' has been
refactored to use the internal apply API directly, avoiding the need
to spawn a 'git apply' subprocess.

* gr/add-e-use-apply-api:
  builtin/add.c: replace run_command() with direct apply_all_patches() call
2026-09-07 09:32:06 -07:00
Junio C Hamano 7c5e5d7e39 Merge branch 'jc/you-still-use-that'
The instructions for deprecated commands emitted by
you_still_use_that() have been reworded to clarify that the removal
decision is final and to provide more assertive guidance on finding
a replacement.

* jc/you-still-use-that:
  you_still_use_that(): reword the instructions
2026-09-07 09:32:05 -07:00
Junio C Hamano bf7d128b47 Merge branch 'yn/worktree-ambiguous-remote-advice'
'git checkout' and 'git worktree add' makes guesses based on a name
of a remote-tracking branch, but does not give an error when such a
remote-tracking branch cannot be uniquely identified, which has
been corrected.

* yn/worktree-ambiguous-remote-advice:
  worktree add: treat multiple matches with --guess-remote as an error
  worktree add: improve message for ambiguous remote branch name
  checkout: improve message for ambiguous remote branch name
  checkout: extract function to display advice for ambiguous remotes
2026-09-07 09:32:05 -07:00
Junio C Hamano 9ef0ca05bc Merge branch 'kn/reftable-optimize-reloading'
The reftable code has been optimized to avoid an unnecessary
stat/reload of the stack when an addition already holds the
list_file lock, reducing the number of newfstatat syscalls from
linear to constant when writing refs.

* kn/reftable-optimize-reloading:
  reftable/stack: avoid reloading the stack when already locked
  reftable/stack: move list lock to `struct reftable_stack`
  reftable/stack: rename reftable_stack_new_addition()
  reftable/stack: remove `REFTABLE_STACK_NEW_ADDITION_RELOAD`
2026-09-07 09:32:05 -07:00
Junio C Hamano 73a4cd73de Merge branch 'en/midx-missing-pack-fallback' into next
The object lookup machinery has been taught to gracefully recover
when a multi-pack-index points to an owning pack that was removed
during a concurrent geometric repack, and 'git replay' has been
fixed to not segfault when reading such missing objects.

* en/midx-missing-pack-fallback:
  packfile: recover when a multi-pack-index names a removed pack
  mktree: do not use OBJECT_INFO_QUICK when checking objects
  mktree: plug per-tree leak in --batch mode
  replay: fail gracefully when a merge input is unreadable
2026-09-04 07:52:35 -07:00
Junio C Hamano 9826377f2b Merge branch 'jk/rev-info-argv-to-free' into next
The memory ownership of argv elements passed to the revision
machinery has been made more robust by keeping logically "freed"
elements alive until the rev_info struct is released, preventing
use-after-free bugs when options store references to them.

* jk/rev-info-argv-to-free:
  revision: simplify mark_argv_for_free() callers
  revision: hang on to "freed" argv elements
2026-09-04 07:52:34 -07:00
Junio C Hamano 92ae794bfc Merge branch 'tc/replay-linearize' into next
The 'git replay' command has been taught the '--linearize' option to
drop merge commits and linearize the replayed history, mimicking 'git
rebase --no-rebase-merges'.

* tc/replay-linearize:
  replay: offer an option to linearize the commit topology
  replay: resolve the replay base outside pick_regular_commit()
  replay: add helper to put entry into replayed_commits
2026-09-04 07:52:34 -07:00
Junio C Hamano d33f0c0813 Merge branch 'hk/typofix' into next
Various spelling mistakes in comments and test descriptions have
been corrected.

* hk/typofix:
  versioncmp: fix typo in versioncmp.c, t/t0022-crlf-rename.sh
2026-09-03 14:54:36 -07:00
Junio C Hamano b04ceb887c Merge branch 'rs/worktree-add-basename-fixes' into next
The string extraction logic for the branch name and worktree name
from the given path in 'git worktree add' has been corrected and
simplified to avoid out-of-bounds reads and improper handling of
trailing slashes.

* rs/worktree-add-basename-fixes:
  worktree add: let worktree_basename() return string copy
  worktree add: trim slashes when deriving branch name from path
  worktree add: reject separator-only path
  worktree add: don't read out of bounds in worktree_basename()
2026-09-03 14:54:36 -07:00
Junio C Hamano e4d4816938 Merge branch 'hn/ci-cancel-stale-pr-runs' into next
GitHub Actions CI workflow runs triggered by pull requests have
been configured to cancel older runs when a new push is made to the
same pull request.

* hn/ci-cancel-stale-pr-runs:
  ci: cancel stale pull request workflow runs
2026-09-03 14:54:36 -07:00
Junio C Hamano 67a1cf3baa Merge branch 'ns/ref-symref-additional-tests' into next
A few tests for the reference handling subsystem have been added to
exercise the handling of forbidden characters and symbolic references.

* ns/ref-symref-additional-tests:
  t1402: test forbidden characters in refnames
  t1401: check symbolic-ref failure and --quiet silence on a non-symbolic ref
2026-09-03 12:42:59 -07:00
Junio C Hamano 17ff1f9808 Sync with 'master' 2026-09-02 10:50:40 -07:00
Junio C Hamano 3cb9185f65 The 22nd batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-02 09:21:59 -07:00
Junio C Hamano 6163a7066e Merge branch 'jc/rerere-doc-typofix'
A missing preposition in the rerere technical documentation has been
fixed.

* jc/rerere-doc-typofix:
  rerere: technical documentation typofix
2026-09-02 09:21:59 -07:00
Junio C Hamano 61d89f5acf Merge branch 'ty/repository-fetch-if-missing'
The global variable 'fetch_if_missing' has been moved to a member in
'struct repository', continuing the libification process and
allowing per-repository control (such as for submodules).

* ty/repository-fetch-if-missing:
  repository: move fetch_if_missing into struct repository
2026-09-02 09:21:59 -07:00
Jeff King 2c03739705 submodule--helper: free URL when repository setup fails
If repo setup fails, we'll return an error without freeing the allocated
url string, leaking the memory. The test suite does trigger this error,
but never with the leak. We only allocate a url if submodule_from_path()
returned something, but our tests use other situations, like totally
nonexistent submodules.

We can cover this case by asking about a submodule that exists but which
has not been initialized. The new test fails with SANITIZE=leak.

The smallest fix would just be a call to free(url), but I think it's a
little nicer to set up a dedicated out-path for cleanup here. The
previous commit made it safe to call repo_clear() even if
repo_submodule_init() fails.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-02 08:45:55 -07:00
Jeff King 95d48952cc repository: make repo_clear() idempotent
Calling repo_clear() twice in a row will segfault because the second
call will invoke parse_object_pool_clear() on a NULL pointer. This is
not usually a big deal, but we can make some error cleanup a little
simpler if callers do not need to worry about invoking it twice.

We can fix it by catching the NULL case. The rest of repo_clear()
appears to be idempotent.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-02 08:45:55 -07:00
Wolfgang Faust 609d2a8834 imap-send: add --draft to set IMAP \Draft flag
The documented purpose of imap-send is to upload draft emails for sending
later, but it did not have any way to mark the messages as \Draft, so some
email clients presented the result as an un-editable, un-sendable email
even if it happened to be in a "Drafts" folder.

Signed-off-by: Wolfgang Faust <contrib-git@wolfgangfaust.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-02 08:35:33 -07:00
Elijah Newren cc499d40e5 commit: refuse partial commits during conflict resolution
Similar to the previous commit, just as `git commit --amend` is a
foot-gun during conflict resolution, so is a partial commit (`git commit
<paths>`).  Recording a conflict resolution is about capturing the state
of the entire tree on top of HEAD, not a subset of paths.  For many years
we have rejected partial commits in the middle of
  - a merge
  - a cherry-pick

but, just like amending, this was never extended to the other operations
that can also leave conflicts to resolve:
  - an `am` operation
  - a revert
  - a rebase that stopped for conflict resolution

Reuse sequencer_ongoing_operation(), introduced for the analogous
`--amend` check, to detect these and refuse the partial commit.  A rebase
that stopped because a pick became empty is not conflict resolution and,
as an earlier patch established, is deliberately left permitted.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 21:24:33 -07:00
Elijah Newren 6257588252 commit: refuse to amend during conflict resolution
Running `git commit --amend` during conflict resolution is an ugly
foot-gun.  For many years, we have rejected amending during conflict
resolution in the middle of
  - a merge
  - a cherry-pick
However, this was never extended to other operations that can also
produce conflicts:
  - an `am` operation
  - a revert
  - a rebase

Extend it to handle these other cases now.

Extending to `am`, revert, and the apply backend of rebase are fairly
straightforward.  However, with the merge backend of rebase we have to
be more careful, since it powers interactive rebases and
  - the interactive machinery internally uses `git commit --amend` for
    `squash` and `reword` directives
  - users are expected to `git commit --amend` after hitting an `edit`
    or `break` directive
So, we need to be careful with rebase to only reject amending when doing
conflict resolution.

A few files under the rebase-merge/ directory provide us the necessary
information:

  - stopped-sha is written only when the rebase stops and hands control
    back to the user, so its presence marks a genuine stop -- as opposed
    to the sequencer's own internal `git commit --amend` while applying
    a squash, fixup, or reword, during which no stopped-sha exists.

  - amend is written only when the rebase stops with HEAD already
    pointing at the commit the user is meant to amend: a clean `edit`,
    or a fast-forward `reword`.  Its absence at a stop therefore means
    the commit did not apply, so HEAD is the previously-applied commit
    rather than the one being rebased -- exactly the case we refuse.

So for the merge backend we die when stopped-sha exists and amend does
not.  This covers a plain conflicted pick as well as a conflicted `edit`
(both leave HEAD on the previously-applied commit), while still allowing
a clean `edit` or `reword` stop and a `break` stop (no stopped-sha).
stopped-sha is unlinked at the start of the resume loop, so a resumed
squash's internal amend is unaffected.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 21:24:33 -07:00
Elijah Newren a3837282fe commit: reword the empty-commit rebase amend error
When a rebase applies a commit that becomes empty, it stops and asks the
user to decide whether to keep it or drop it.  HEAD still points at the
previously-applied commit at that point, so amending is refused, with:

    You are in the middle of a rebase -- cannot amend.

That message would suggest that amending is not allowed during an 'edit'
or 'break' stop, which is misleading, plus it lacks the specificity that
might help the user know why their particular case is a problem: the
commit they intended to amend became empty and was dropped, so amending
would affect the wrong commit.  Reword the error accordingly.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 21:24:33 -07:00
Elijah Newren d692305326 commit: allow a partial commit when a rebase pick becomes empty
For years, we disallowed partial commits during merges or cherry-picks.
In commit 430b75f720 (commit: give correct advice for empty commit
during a rebase, 2019-12-06) it was noted that the "cannot do a partial
commit during a cherry-pick" message was also printed when rebasing a
commit that became empty, and rather than drop the check in that case,
that commit opted to make the message print the actual operation that
was in progress.

Since a commit that has become empty comes without conflicts, a new
partial commit poses no problems; remove the error in that case.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 21:24:33 -07:00
Elijah Newren aef843026b commit: clarify FROM_REBASE_PICK and is_from_rebase() names
Commit 430b75f720 (commit: give correct advice for empty commit during
a rebase, 2019-12-06) introduced a FROM_REBASE_PICK enum value and an
is_from_rebase() function.  Those names failed to convey that they were
specifically about hitting a commit that becomes empty when rebasing.
Clarify their names now.

While at it, change `whence == FROM_REBASE_NOW_EMPTY` to use
`is_from_rebase_now_empty(whence)`.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 21:24:33 -07:00
Jeff King 0e96176af4 revision: simplify mark_argv_for_free() callers
You do not want to mark an argv element for freeing unless the caller
has given us the free_removed_argv_elements flag. Originally we just
called free() in this case, so each caller checked the flag itself. Now
that we mark them via a helper function, we can push the check down into
the helper. This saves a little bit of duplicated code, but also
hopefully makes the result conceptually simpler.

Every caller but one was already checking this flag. The exception is
setup_revisions_from_strvec(), but it always sets the flag explicitly
(since its whole purpose is managing argv memory). So even though it was
not checking the flag, doing so is OK (it will always be set).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 11:04:18 -07:00
Jeff King 66f4856110 revision: hang on to "freed" argv elements
In setup_revisions() we rewrite the incoming argv array, losing
references to the strings it contains. For a synthetic argv array
constructed from heap strings, that traditionally meant we leaked those
allocated strings.

We fixed the leak in cd43948798 (revision: manage memory ownership of
argv in setup_revisions(), 2025-09-19). Now callers can tell the
revision code that argv entries are allocated and should be freed, which
it will do before overwriting them.

But this introduced a new bug! The overwritten entries go away as soon
as option parsing is finished, but a few options may actually create new
references to those strings. And once we free the strings, those stale
references become use-after-free bugs. For example, running:

  git stash show --src-prefix=foo/

demonstrates the problem:

  1. The stash command generates its own synthetic argv (because it has
     to treat the stash specifiers specially) which it then passes to
     setup_revisions().

  2. Parsing will create a reference to the partial string "foo/" in
     revs.diffopt.a_prefix.

  3. When setup_revisions() finishes, we rewrite argv to throw away
     parsed strings. This frees the entry holding "--src-prefix=foo",
     at which point we have a dangling reference in revs.diffopt.

  4. We generate an actual diff, accessing garbage memory via
     revs.diffopt.a_prefix. The output is usually garbled, but ASan also
     detects this reliably.

One obvious fix here is to allocate new strings when we pull data out of
the argv array. But doing so is error prone (every string option must
remember to do it or risk a subtle bug), and creates more questions
about memory ownership (e.g., some callers assign string literals
directly to a_prefix, and we would not want to free those).

Instead we can fix this centrally by delaying the free() calls. We'll
collect any "freed" strings in a new array, hold on to it for the life
of the rev_info struct, and then release it at the end. We can easily
use a strvec for this, since it handles growth and cleanup for us.

This fixes the prefix case above (which is now tested in t3903), and
should fix any other stray cases. Though I could not find any; we use
OPT_STRING only in the prefix diff options, and very few revision opts
store strings. Those that do (like --format and --encoding) already make
a copy of the string. They do not need for us to hold on to the memory
longer, but it does not hurt them if we do.

One may note that combined with cd43948798 we have approached a simpler
solution in a roundabout way. We are still hacking up argv, but now
carefully constructing a parallel argv of old strings we've overwritten
(and will eventually free). In an alternate universe, we could instead
leave the original argv pristine and return a new reduced-size argv.
This is conceptually simpler, though it does mean that every caller must
free that new argv array itself (not the entries). That's not something
they traditionally had to do, so it would mean tweaking every caller.

So even though the combination of this cd43948798 and this patch is a
little convoluted, it should make things just work (no leaks and no
use-after-free) without modifying any callers.

Reported-by: Nicolas Le Cam <niko.lecam@gmail.com>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 11:03:56 -07:00
Michael Montalbo c2a48fdcb5 t/lib-httpd: document writing concurrency-safe CGI helpers
Update t/lib-httpd.sh to document the fixes applied to
apply-one-time-script.sh and http-429.sh for future developers working
on helper scripts. Add concrete examples of patterns and anti-patterns
that should be considered when handling state management.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 09:02:53 -07:00
Michael Montalbo b86132120d t/lib-httpd: make http-429 first-request check atomic
http-429.sh is a helper for testing retry logic. It uses "test -f" to
check for the existence of a state file and later uses "touch" or
"rm -f" on that file to determine if it should return a 429. This method
of managing state can fail if the helper script is invoked concurrently.
However, this failure does not currently manifest itself since the
helper is invoked sequentially.

As a preventive measure, fix the state management logic so it relies on
an atomic mkdir operation to mark that a 429 was returned. When
$retry_after is "permanent", always return 429 now that we do not rely
on a state file that is "touch"ed and "rm"ed to indicate when to respond
with a 429.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 09:02:53 -07:00
Michael Montalbo 5945464690 t/lib-httpd: fix apply-one-time-script race under concurrent requests
apply-one-time-script.sh is a test helper that executes a
"one-time-script" responsible for modifying the response normally
returned by git-http-backend. apply-one-time-script.sh should run
"one-time-script" once and return a modified response once. However,
sometimes a race between multiple concurrent requests causes
apply-one-time-script.sh to misbehave and return multiple modified
responses or an empty response that results in:

  fatal: ... The requested URL returned error: 500
  fatal: could not fetch <oid> from promisor remote

This can be seen in the flaky failure of t5616.47 on the macOS CI
runners.

Fix the logic that checks if "one-time-script" has returned its modified
response by chaining "rm one-time-script" with its execution. This
ensures a racing script does not also have the opportunity to execute
"one-time-script".

Add t/t5567-one-time-script.sh to verify the race is fixed. Implement a
stub "git-http-backend" that intentionally invokes a concurrent request,
and check that only one modified response is returned without error.

Signed-off-by: Michael Montalbo <mmontalbo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-09-01 09:02:53 -07:00
Hardik Kumar c486c1df72 versioncmp: fix typo in versioncmp.c, t/t0022-crlf-rename.sh
The patch fixes two typos in two places.
versioncmp.c:           "fractionnal" -> "fractional"
t/t0022-crlf-rename.sh: "similiarity" -> "similarity"

No functional changes, only update a comment and a test_description.

Signed-off-by: Hardik Kumar <hardikxk@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 13:47:04 -07:00
Harald Nordgren a251b1bd21 ci: cancel stale pull request workflow runs
The CI workflow groups all runs by commit hash using
`group: ${{ github.sha }}`.  This means every push to a pull
request starts a separate workflow run, and all workflows
triggered by the same commit share the same concurrency group.

With this change, pull request runs are grouped by pull request
number instead of commit hash, and runs superseded by a newer
push are canceled.  The concurrency group becomes
`${{ github.workflow }}-${{ github.event.pull_request.number ||
github.sha }}` and `cancel-in-progress` is set to true for
pull request events.

For pull request events, the group is `<workflow>-<pull-request-number>`
(e.g., "main-workflow-42").  If you push a new commit to an
existing pull request before the CI working on it finishes, the
new request will be placed in the same group and cancel the
currently running run.

For non-pull-request events, the group is `${{ github.workflow }}-${{
github.sha }}` and `cancel-in-progress` defaults to false, so
there is no regression in behavior.

Note that the previous configuration used `group: ${{ github.sha }}`,
which meant all workflows sharing the same commit hash were in the
same group.  The new configuration includes the workflow name in
the group, so each workflow has its own concurrency group per
commit/PR.

Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 11:05:35 -07:00
Toon Claes 354c736978 replay: offer an option to linearize the commit topology
One of the stated goals of git-replay(1) is to allow implementing the
git-rebase(1) functionality on the server side.

The default mode of git-rebase(1) is to act as if `--no-rebase-merges`
was given. This mode drops merge commits instead of replaying them, and
linearizes the history into a sequence of regular (single-parent)
commits.

Add option `--linearize` to git-replay(1) to do the same. Each replayed
commit is stacked on top of the previously replayed one. When a merge is
encountered, the commits reachable from all of its sides are replayed
into the single line and the merge itself is dropped.

If a ref was pointing to a merge commit, that ref is updated to the
merge's last replayed ancestor.

git-replay(1) accepts multiple branches, for example:

    $ git replay --onto main topic1 topic2

Without `--linearize` this replays 'topic1' and 'topic2' onto 'main'
(keeping shared portions of history shared and divergent parts
divergent) and updates both refs.

Due to current implementation limitations, replaying multiple branches
with `--linearize` is disallowed to avoid concatenating unrelated
histories into a single line. For the same reason disallow the use of
`--contained` with `--linearize`.

Users who want to linearize multiple branches are advised to do this in
separate git-replay(1) invocations. Linearizing multiple branches at
once might be added later.

Note that `--linearize` is not modeled after git-rebase(1)'s
`--rebase-merges[=<mode>]` interface. Recreating merges, by preserving
their topology, is a distinct operation that would be a separate mode.
`--linearize` only drops merges and replays commits linearly. So
git-replay(1) uses its own option rather than reusing that interface.

Based-on-patches-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 10:29:06 -07:00
Toon Claes 446099ef7c replay: resolve the replay base outside pick_regular_commit()
Depending on what gets passed into the function pick_regular_commit(),
it decides the new base for the replayed commit. It first tries to find
the replayed results of `pickme`'s parent in the `replayed_commits` map.
If not found, it falls back to `onto`.

When using git-replay(1) with --onto, the fallback is the revision
passed in with this option, but when using --revert, the fallback is
`last_commit`.

It's rather confusing the base is decided partly inside
pick_regular_commit() and partly by its caller.

Move the base selection completely into the caller: replay_revisions().
This bundles all the logic of deciding on the base together. Also, this
reduces the number of parameters of pick_regular_commit(), making its
interface cleaner.

This refactoring doesn't bring any behavior changes.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 10:29:06 -07:00
Toon Claes 98b33a62f6 replay: add helper to put entry into replayed_commits
The function replay_revisions() in replay.c is rather lengthy. Extract
the logic to put a commit entry into a `struct mapped_commits` into a
helper function put_mapped_commit().

While at it, rename mapped_commit() to get_mapped_commit() to pair with
this new function.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 10:29:05 -07:00
Junio C Hamano 10538fe699 Sync with 'master' 2026-08-31 08:26:28 -07:00
Junio C Hamano 15072b025f Merge branch 'yn/worktree-repair-relative' into next
The git worktree repair command failed to rewrite the .git file of
a working tree from a relative path to an absolute path when the
command was run in the working tree itself. The
read_gitfile_gently() function was modified to also return whether
the path originally recorded in the file was absolute, and this new
capability is used to correctly detect such mismatches.

* yn/worktree-repair-relative:
  worktree repair: detect relative path in .git file correctly
2026-08-31 08:26:18 -07:00
Junio C Hamano fee97cc13c Merge branch 'll/zsh-complete-git-potty-options' into next
The zsh completion script (in 'contrib/') has been updated to
correctly locate the Git command after global options like '-C' by
properly skipping them, similar to how the bash completion does.

* ll/zsh-complete-git-potty-options:
  completion: zsh: support completion after "git -C <path>"
2026-08-31 08:26:18 -07:00
Junio C Hamano 04ee2ac5c5 Merge branch 'gr/add-e-use-apply-api' into next
The application of the edited patch in 'git add -e' has been
refactored to use the internal apply API directly, avoiding the need
to spawn a 'git apply' subprocess.

* gr/add-e-use-apply-api:
  builtin/add.c: replace run_command() with direct apply_all_patches() call
2026-08-31 08:26:17 -07:00
Junio C Hamano 1630431f32 The 21st batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 08:25:00 -07:00
Junio C Hamano 6e75a57d1b Merge branch 'fr/pack-objects-trace-pack-bytes'
The pack-objects command has been updated to record the total bytes
written to pack files in trace2 output, allowing performance
analysis of different compression settings by comparing the
resulting pack sizes.

* fr/pack-objects-trace-pack-bytes:
  pack-objects: trace pack bytes written
2026-08-31 08:25:00 -07:00
Junio C Hamano 923bf36c46 Merge branch 'ps/odb-pluggable-pack-generation'
The mechanism to generate a packfile corresponding to the result of
a fetch/push has been made pluggable through a set of object
database callback functions, removing hardcoded references to
'pack-objects' and enabling alternative ODBs to serve packfiles
themselves.

* ps/odb-pluggable-pack-generation:
  bundle: generate packfiles via the object database
  bundle: get (mostly) rid of `the_repository`
  builtin/bundle: refactor option handling for progress meter
  send-pack: generate packfiles via the object database
  upload-pack: generate packfiles via the object database
  odb: introduce interface to generate packfiles
2026-08-31 08:25:00 -07:00
Junio C Hamano 26e1e47b47 Merge branch 'jt/receive-pack-pluggable-writes'
The 'git receive-pack' command has been updated to use a new ODB
transaction interface for writing incoming packfiles, making it more
backend-agnostic.

* jt/receive-pack-pluggable-writes:
  odb/transaction: add transaction interface to write packfiles
  odb: return temporary ODB source when set
  builtin/receive-pack: explicitly pass packfile fd
  builtin/receive-pack: report unpack errors via strbuf
  builtin/receive-pack: lift global state out of unpack()
  builtin/receive-pack: read unpack limit config lazily
  builtin/receive-pack: pass shallow file explicitly
  odb/transaction: add transaction finalize interface
  builtin/receive-pack: properly clean up keep files
2026-08-31 08:25:00 -07:00
Junio C Hamano 93f737d51b Merge branch 'ps/odb-geometric-repack-loose-threshold'
The threshold for geometric repacking to trigger based on loose
object count has been adjusted to match that of 'git gc --auto',
preventing over-aggressive repacking during concurrent writes.

* ps/odb-geometric-repack-loose-threshold:
  odb/files: be less aggressive with geometric repacking
2026-08-31 08:24:59 -07:00