summaryrefslogtreecommitdiff
path: root/sequencer.c
AgeCommit message (Collapse)AuthorFilesLines
5 daysMerge branch 'tb/rerere-lock-grace' into seenJunio C Hamano1-3/+35
The sequencer machinery (used by 'git rebase', 'git cherry-pick', and 'git revert') has been updated to defer automatic maintenance tasks until the end of the operation, preventing nested 'git commit', 'git merge', and 'exec' commands from triggering GC operations that could contend for locks or delete open packs while the sequence is in progress. * tb/rerere-lock-grace: sequencer: disable auto maintenance in spawned commands rebase, cherry-pick, revert: run auto maintenance when done config: add git_config_append_parameter()
5 daysMerge branch 'fz/rebase-autosquash-empty' into seenJunio C Hamano1-4/+295
A commit that is emptied by melding a 'fixup!' or 'squash!' commit during 'git rebase --autosquash' is now handled according to the '--empty' option, allowing it to be dropped, kept, or to halt the rebase. * fz/rebase-autosquash-empty: sequencer: honor --empty when a fixup!/squash! empties its target
5 daysMerge branch 'hn/history-squash' into seenJunio C Hamano1-31/+39
The experimental 'git history' command has been taught a new 'squash' subcommand to fold a range of commits into a single commit, with any descendants replayed on top. * hn/history-squash: history: support editing squashed commit messages history: create squashed commits without editing history: protect branches when squashing a range history: validate squash revision ranges history: add skeleton for squash subcommand sequencer: share the squash message marker helpers and flags history: give commit_tree_ext a message template history: extract helper for a commit's parent tree
5 daysMerge branch 'hs/rebase-continue-edit' into seenJunio C Hamano1-1/+28
Support for skipping the editor when continuing a rebase after conflict resolution has been added with the '--no-edit' option, and forcing it with '--edit'. A new configuration variable 'rebase.noEdit' can be used to set the default behavior. * hs/rebase-continue-edit: rebase: add --[no-]edit to --continue
5 daysMerge branch 'sn/rebase-update-refs-symrefs' into seenJunio C Hamano1-12/+51
'git rebase --update-refs' has been taught to resolve local branch symrefs to their referents before queuing updates, ensuring aliases of the current branch are skipped and duplicate updates are avoided to prevent failures when branch aliases are present. * sn/rebase-update-refs-symrefs: rebase: guard non-branch symref targets rebase: skip branch symref aliases
5 daysMerge branch 'ps/odb-stop-registering-in-memory-sources' into jchJunio C Hamano1-1/+1
The mechanism to register in-memory alternate object sources has been removed, as submodule object databases are now accessed natively via their own repository structures. This simplifies object database management and prepares the codebase for migrating alternate tracking into the files backend. * ps/odb-stop-registering-in-memory-sources: odb: remove the ability to link sources ad-hoc t/helper: stop registering alternates in "ref-store" command t/helper: adapt read-midx to not link ad-hoc source anymore builtin/multi-pack-index: refuse unknown sources with "--object-dir=" odb/packed: fix memory leaks when freeing source tmp-objdir: drop unused function to register alternate odb: remove infrastructure to register submodule sources builtin/grep: stop registering submodule ODB as source submodule-config: stop registering submodule sources submodule-config: stop using `the_hash_algo` submodule-config: remove uses of `the_repository` cache-tree: remove dependency on `the_repository` cache-tree: drop `the_repository` in `cache_tree_fully_valid()`
5 daysMerge branch 'hn/checkout-m-autostash-refine' into jchJunio C Hamano1-39/+70
The autostash fallback in 'git checkout -m' has been refined to only retry when there are local changes. Additionally, a blank line now visually separates autostash conflict advice from the subsequent branch-switch message. * hn/checkout-m-autostash-refine: checkout: separate autostash conflict advice from branch-switch message stash: reserve exit status 1 for conflicts
5 daysMerge branch 'en/no-amend-during-conflicts' into jchJunio C Hamano1-1/+58
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
6 dayssequencer: disable auto maintenance in spawned commandsThomas Bachem1-3/+35
Sequencer-spawned commands like 'commit' and 'merge' run background auto maintenance, which interferes with ongoing operations (e.g. 'rerere gc' holding MERGE_RR.lock or repacks deleting active packs). Pass maintenance.auto=false via GIT_CONFIG_PARAMETERS to the spawned commit, merge and exec commands. Appending it after the user's own settings ensures it wins, and the environment reaches whatever they spawn in turn. Auto maintenance now runs exactly once when the sequence completes. Commands run manually by the user while stopped are unaffected and continue to run auto maintenance normally. Assisted-by: Claude Fable 5.1 Signed-off-by: Thomas Bachem <mail@thomasbachem.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
6 dayssequencer: share the squash message marker helpers and flagsHarald Nordgren1-31/+39
When "git rebase -i" squashes commits it builds an editor template with a "This is a combination of N commits." banner, a "This is the 1st/Nth commit message:" header above each kept message (or a "will be skipped" header for a dropped one), and a commented-out subject for any fixup!, squash! or amend! commit. The banner, the headers and the subject-commenting all live in static helpers in sequencer.c wired to the rebase state, so no other command can present a squash the same way. Pull the three pieces out into add_squash_combination_header(), add_squash_message_header() (which takes a flag for the "will be skipped" variant) and squash_subject_comment_len(), and use them from update_squash_messages() and append_squash_message(). Also move the todo_item_flags enum to the header, so a caller reading the output of todo_list_rearrange_squash() can tell an amend! (TODO_REPLACE_FIXUP_MSG) from a plain fixup!. A later change reuses all of this to give "git history squash" the same template. No change in behavior. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 daysstash: reserve exit status 1 for conflictsHarald Nordgren1-39/+70
"git stash apply", "pop" and "branch" exit with status 1 both when applying the stash entry resulted in conflicts and when they fail for other reasons, so callers cannot tell the two apart. Follow the convention of "git merge-tree" and the merge strategies, which exit with status 1 to indicate conflicts and with a different non-zero status for errors: those subcommands now exit with status 1 only when applying the stash entry resulted in conflicts, in which case the stash entry is left in place, and exit with status 128, the status die() uses, when they fail for other reasons. Document the exit statuses. The only subcommand implementations that can return a positive value are "apply", "pop" and "branch", which return the value of do_apply_stash(): "apply" returns it directly, and "pop" and "branch" drop the stash entry, via do_drop_stash(), which always returns 0, only when the application succeeded. do_apply_stash() only returns a positive value when the three-way merge was unclean. cmd_stash() now maps negative values to 128 and passes positive values through as the exit status, so exit status 1 unambiguously indicates conflicts. enum stash_apply_result makes the convention explicit, and the autostash helpers use it to tell users that their stashed changes were saved when applying them fails. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 dayscache-tree: drop `the_repository` in `cache_tree_fully_valid()`Patrick Steinhardt1-1/+1
The function `cache_tree_fully_valid()` verifies whether the cache tree owned by the index is valid or not. As part of that, the function checks whether the objects referenced by the cache all exist. But because the function has no repository available, it is using the object database of `the_repository` instead. We could of course adapt callers to pass in a repository as parameter explicitly to get rid of this implicit dependency on global state. But all of them pass the cache tree owned by a `struct index_state`, and that structure already has a reference to its owning repository. So instead, adapt the function to accept a `struct index_state`, which ensures that callers will implicitly always pass the correct repository. Adapt callers accordingly. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 dayscommit: refuse to amend during conflict resolutionElijah Newren1-0/+57
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>
13 dayscommit: clarify FROM_REBASE_PICK and is_from_rebase() namesElijah Newren1-1/+1
Commit 430b75f7209c (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-08-27sequencer: honor --empty when a fixup!/squash! empties its targetFarid Zakaria1-4/+295
When "git rebase --autosquash" squashes a "fixup!" or "squash!" commit into its target, the result can be a commit that no longer changes anything relative to its parent, for example when the squashed change reverts the target. Rather than dropping or keeping that commit, the rebase stops with You asked to amend the most recent commit, but doing so would make it empty. ... and "--empty" has no effect on it. This makes backing a change out of a series awkward: reverting a commit as a "fixup!" and running "git rebase --autosquash --empty=drop" ought to remove both the commit and its revert, but it halts instead. A "fixup" is applied by amending HEAD, so the commit it produces is empty when the index matches the tree of HEAD's parent rather than the tree of HEAD. allow_empty() only knows about the latter, so it never notices that the fixup cancelled the commit out and "git commit --amend" is left to refuse to create the empty commit. Check for this case separately and honor "--empty" for it, subject to two restrictions. First, "--empty" only governs commits that become empty, so a commit that was picked empty to begin with must be left alone. To tell the two apart, record in "struct replay_ctx" what the "pick" that created the commit at HEAD was, and write it to "$GIT_DIR/rebase-merge/fixup-target" so that it survives a stop for conflict resolution. Only a commit created by a "pick" is a candidate: when the todo list has been edited so that a chain starts after "reset", "exec" or "break", we do not know how the commit at HEAD came to be and keep it. Second, only the last fixup of a chain may drop the commit. Were an earlier one to drop it, the fixups still to come would be squashed into the previous commit instead, so a commit emptied mid-chain is kept -- empty for the time being -- and the decision is deferred to the end of the chain. With "--empty=drop" the emptied commit has already been created by the "pick", so drop it by moving HEAD back to its parent and report the new PICK_RESULT_DROPPED_HEAD, so that neither that commit nor any of the fixups squashed into it is recorded as rewritten and the post-rewrite machinery has nothing to report. A "label" or "update-ref" that follows then sees HEAD at the parent. A conflicted fixup that the user resolves by undoing the commit it is being squashed into leaves the same empty commit behind, so give commit_staged_changes() the same treatment. Signed-off-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-24Merge branch 'en/sequencer-lose-pretty-given'Junio C Hamano1-1/+0
The setting of a now-unused member '.pretty_given' in the sequencer machinery has been removed. * en/sequencer-lose-pretty-given: sequencer: remove unnecessary variable setting
2026-08-12sequencer: release the ODB before spawning git commitJohannes Schindelin1-0/+1
As of 4557f1add261 (rebase--helper: add a builtin helper for interactive rebases, 2017-02-09), continuing an interactive rebase uses the builtin sequencer, which spawns `git commit`. The child may trigger auto-maintenance, which may need to replace files for which the sequencer still holds resources. See https://github.com/git-for-windows/git/issues/6315: on Windows, this produces unlink retry prompts that cannot succeed while the sequencer waits for the child. Resources such as file handles or memory mappings must be released before spawning a command that may run auto-maintenance, as established by 28d04e1ec197 (run-command: offer to close the object store before running, 2021-09-09): release the ODB file handles and memory mappings, so that auto-gc can repack (potentially deleting existing packfiles in the process); If the sequencer needs to access the ODB afterwards, it will gracefully (re-)open the ODB. Release the sequencer's ODB before spawning `git commit`. The regression test uses the legacy-delete trick introduced by 69ed0e35a754 (mingw: optionally use legacy (non-POSIX) delete semantics, 2026-05-07) to trigger the failure on modern Windows. Assisted-by: GPT-5.6 Sol Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-12sequencer: remove unnecessary variable settingElijah Newren1-1/+0
revs.pretty_given is only ever read in builtin/log.c, and nothing from builtin/log.c is ever called from sequencer.c. So setting this variable cannot do anything. This was introduced in commit 62db524779 ("rebase -i: generate the script via rebase--helper", 2017-07-14), which used `git rev-list` even though its commit message describes the logic as having been based on `git log`. Because of this, I am guessing this line was copied or ported from part of builtin/log.c without recognizing that this line was not doing anything and could be removed. It's certainly not doing anything now, though, so remove it. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-05Merge branch 'pw/rebase-fixup-fixes'Junio C Hamano1-5/+26
Two bugs in how 'git rebase' handles skipped 'fixup' and 'squash' commands have been fixed. One bug caused an incorrect commit count to be shown in the template message when multiple commands were skipped, and another prevented the editor from opening when the final command in a chain containing 'fixup -c' was skipped. * pw/rebase-fixup-fixes: rebase: remember fixup -c after skipping fixup/squash rebase -i: fix counting of fixups after rebase --skip
2026-07-27Merge branch 'pw/rebase-drop-notes-with-commit'Junio C Hamano1-32/+92
The rebase post-rewrite notes-copying logic has been corrected. When a commit is dropped during rebase (e.g., because its changes are already upstream), it is no longer recorded as rewritten, preventing its notes from being copied to an unrelated commit. * pw/rebase-drop-notes-with-commit: sequencer: do not record dropped commits as rewritten sequencer: use an enum to represent result of picking a commit sequencer: simplify pick_one_commit() sequencer: remove unnecessary condition in pick_one_commit() sequencer: simplify handling of fixup with conflicts sequencer: remove unnecessary "or" in pick_one_commit() sequencer: never reschedule on failed commit sequencer: be more careful with external merge t3400: restore coverage for note copying with apply backend
2026-07-26rebase: remember fixup -c after skipping fixup/squashPhillip Wood1-4/+16
When the final command in a chain of "fixup" and "squash" commands is skipped, we should prompt the user to edit the commit message if the chain contains a "fixup -c" command that was not skipped. Unfortunately, commit_staged_changes() only looks for completed "squash" commands and so does not prompt the user to edit the message. Fix this by recording whether a fixup command has the "-c" flag set and then checking whether we have seen either a "fixup -c" or a "squash" command. Add regression tests for skipping a command in the middle of the chain (which currently works but has no test coverage), and for skipping the final command (which is fixed by this patch). Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-26rebase -i: fix counting of fixups after rebase --skipPhillip Wood1-1/+10
When the sequencer processes a chain of "fixup" and "squash" commands it keeps a list of the commands that have been executed. If there are conflicts, then the list is saved when the rebase stops for the user to resolve them. When the rebase resumes, the list is loaded and is used to initialize the count of how many "fixup" and "squash" commands have been processed; if a command has been skipped with "git rebase --skip", then the last command needs to be popped off the end of the list. To count the number of commands, commit_staged_changes() uses the number of newlines in the file plus one. This is due to the slightly unusual way the list is constructed - instead of appending a newline when a command is added, a newline is inserted before the command if the current count is greater than zero. Therefore, when we pop a skipped command off the list, we should also remove the newline that precedes it. Otherwise, when a new command is added, a blank line will be left before it, which will contribute to the fixup count the next time the file is read. Unfortunately, the preceding newline is not removed, leading to an incorrect count. Fix this by removing the newline that appears before the skipped command. In addition to fixing the code that removes a skipped command from the list, the code that reads the list is fixed to skip blank lines. We have had reports of users starting a rebase with one version of git and continuing it with another. Often this happens because the version of git bundled with an IDE or TUI differs from the one used at the command line. By fixing both the reading and writing ends of the problem we ensure the count is correct when an older version of git reads the fixup file written by a newer version and vice versa. Triggering the incorrect count requires the user to skip two "fixup" or "squash" commands before the final command in the chain. An existing test is extended to prevent future regressions. The consequence of miscounting is not serious: we just print the wrong count in the header of the commit message template. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-22rebase: guard non-branch symref targetsSon Luong Ngoc1-0/+19
A local branch symbolic ref may point outside refs/heads/. Such an alias cannot be skipped like a branch-to-branch alias because its concrete target ref is absent from the local branch decoration list. However, queuing each alias independently can update the same target ref more than once and make the second compare-and-swap fail. A reservation from another worktree can also name either an alias or its resolved target ref, so checking only one form can miss an in-progress update. Fix these cases by checking both the literal alias and its resolved target ref against checked-out reservations. Deduplicate updates by target ref. Also reserve both forms when loading another worktree's update-refs state. This makes different aliases honor the same in-progress update. This keeps non-branch symrefs supported without allowing duplicate or cross-worktree ref updates. Signed-off-by: Son Luong Ngoc <sluongng@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-22rebase: skip branch symref aliasesSon Luong Ngoc1-12/+32
git rebase --update-refs can finish rewriting the current branch and then fail while updating a local branch that is a symbolic ref. This can happen during a default-branch rename where refs/heads/main points at refs/heads/master while users migrate. The problem is a partially applied ref update: the main rebase has already succeeded when the later ref update fails. The sequencer queues updates from local branch decorations. Commit 106b6885c7 (rebase: ignore non-branch update-refs) filters out decorations such as HEAD and tags. A branch symref is still a local branch decoration, but refs_update_ref() dereferences it, so an alias to another branch duplicates the concrete branch update. Resolve local branch decorations before queuing them. Skip symrefs whose targets are under refs/heads/ so that only the concrete branch update is queued. Keep an owned copy of the resolved HEAD and skip the current branch before checked-out handling so later ref resolution cannot change the comparison. This prevents a successful rebase from being followed by a failed, partially applied ref update while preserving each alias as a symref. Signed-off-by: Son Luong Ngoc <sluongng@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-21rebase: add --[no-]edit to --continueHugo Sales1-1/+28
Allow skipping the editor when continuing after resolving conflicts, via --no-edit or the rebase.noEdit configuration variable. The --edit option overrides rebase.noEdit when both are set. Signed-off-by: Hugo Sales <hugo@hsal.es> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-16copy: drop dependency on `the_repository`Patrick Steinhardt1-3/+3
When copying a file we need to potentially adapt permissions of the new file based on whether or not "core.shared" is enabled. Parsing this configuration makes us implicitly depend on `the_repository`. Refactor the code to instead require the caller to pass in a repository so that we can remove `USE_THE_REPOSITORY_VARIABLE`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15Merge branch 'ps/history-drop'Junio C Hamano1-6/+11
The experimental 'git history' command has been taught a new 'drop' subcommand to remove a commit, with its descendants replayed onto its parent. * ps/history-drop: builtin/history: implement "drop" subcommand builtin/history: split handling of ref updates into two phases replay: expose `replay_result_queue_update()` reset: stop assuming that the caller passes in a clean index reset: allow the caller to specify the current HEAD object reset: introduce ability to skip updating HEAD reset: introduce dry-run mode reset: modernize flags passed to `reset_working_tree()` reset: rename `reset_head()` reset: drop `USE_THE_REPOSITORY_VARIABLE` read-cache: split out function to drop unmerged entries to stage 0
2026-07-15sequencer: do not record dropped commits as rewrittenPhillip Wood1-5/+19
If a commit gets dropped because its changes are already upstream then we should not record it as rewritten. As well as confusing any post-rewrite hooks, it means we end up copying the notes from the dropped commit to the commit that was picked immediately before the one that was dropped. While we do not want to record the dropped commit as rewritten, if it is the final commit in a chain of fixups then we need to flush the list of rewritten commits. The behavior of an "edit" command where the commit is dropped is changed so that "rebase --continue" will not amend the previous pick. However, as the code comment notes it will still be erroneously recorded as rewritten when the rebase continues. That will need to be addressed separately along with not recording skipped commits as rewritten. The initialization of "drop_commit" is moved to ensure it is initialized when rewording a fast-forwarded commit. Reported-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> Tested-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: use an enum to represent result of picking a commitPhillip Wood1-16/+45
Rather than using an integer where -1 is an error, 0 is success and 1 indicates there were conflicts, use an enum. This is clearer and lets us add a separate return value for commits that are dropped because they become empty in the next commit. Note we continue to use "return error(...)" to return errors and take advantage of C's lax typing of enums Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: simplify pick_one_commit()Phillip Wood1-8/+11
Unless we're rebasing, all we do in pick_one_commit() is call do_pick_commit() and return its result. Simplify the code by returning early if we're not rebasing so that we don't have to repeatedly call is_rebase_i() in the rest of the function. Note that there are a couple of conditions that do not call is_rebase_i() but they check for either an "edit" or a "fixup" command, both of which imply we're rebasing. The only block that does not return early is the one guarded by "!res". Move the return into that block to make it clear that after recording the commit as rewritten, all we do is return from the function. As the conditional blocks are all mutually exclusive (either the conditions are mutually exclusive, or an earlier conditional block that would match a later one contains a "return" statement) chain them together with "else if" to make that clear. While we could remove "res" from the conditions below "if (!res)" they are left alone because, when we start using an enum in the next commit, it makes it clear that these clauses are handling cases where there are conflicts. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: remove unnecessary condition in pick_one_commit()Phillip Wood1-1/+1
item->commit holds the commit to be picked and so it must be non-NULL otherwise pick_one_commit() would not know which commit to pick. It is also unconditionally dereferenced in do_pick_commit() which is called at the top of this function. Therefore the check to see if it is non-NULL is superfluous. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: simplify handling of fixup with conflictsPhillip Wood1-3/+1
Commit e032abd5a0 (rebase: fix rewritten list for failed pick, 2023-09-06) introduced an early return when res == -1, so if we enter this conditional block then res is positive. After the last couple of commits the only possible positive value is 1. That means we can simplify the code by removing the conditional call to intend_to_amend() and have error_failed_squash() request that it is called in error_with_patch() instead. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: remove unnecessary "or" in pick_one_commit()Phillip Wood1-3/+2
If error_with_patch(..., res, ...) succeeds then it returns "res", if it fails then it returns -1. This means that or-ing the return value with "res" is pointless as the result is the same as the return value. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: never reschedule on failed commitPhillip Wood1-0/+6
If "git commit" fails to run then run_git_commit() returns -1 which causes the current command to be rescheduled. This is incorrect as we have successfully picked the commit and have written all the state files we need to successfully commit when the user continues. Fix this by converting -1 to 1 which matches what do_merge() does. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-15sequencer: be more careful with external mergePhillip Wood1-4/+15
If an external merge strategy cannot merge (for example because it would overwrite an untracked file) it exits with a non-zero exit code other than 1. This should be treated differently from a merge with conflicts, which is signaled by an exit code of 1, because, as the merge failed, we need to reschedule the last pick. The caller expects us to return -1 in this case. Also reschedule without trying to merge if the commit message cannot be written as that prevents us from successfully picking the commit. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-06Merge branch 'pw/status-rebase-todo'Junio C Hamano1-12/+27
The display of the rebase todo list in "git status" has been improved to correctly abbreviate object IDs for more commands and avoid misinterpreting refs as object IDs. * pw/status-rebase-todo: status: improve rebase todo list parsing sequencer: factor out parsing of todo commands
2026-07-03reset: introduce ability to skip updating HEADPatrick Steinhardt1-1/+3
In a subsequent commit we'll introduce a new caller to `reset_working_tree()` that really only wants to update the index and working tree, without updating any references. Introduce a new flag that makes the caller opt in to updating HEAD and adapt all callers to set that flag. Note that in a previous iteration we instead introduced a flag that made callers opt out of updating any references. This was somewhat awkward though because we already have the `UPDATE_ORIG_HEAD` flag, so the result was somewhat inconsistent. Suggested-by: Phillip Wood <phillip.wood123@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> [jc: fixed-up a typo pointed out by Christian] Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-01reset: modernize flags passed to `reset_working_tree()`Patrick Steinhardt1-3/+6
The flags passed to `reset_working_tree()` are declared as defines. This has fallen a bit out of practice nowadays, where we instead prefer to use enums. Furthermore, the prefix of those flags does not match the function name anymore after the rename in the preceding commit. Adapt the code to follow modern best practices and adapt the flag names. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-07-01reset: rename `reset_head()`Patrick Steinhardt1-4/+4
In a subsequent commit we're about to adapt `reset_head()` so that the reference update to HEAD is optional, only. At this point the function starts to feel misnamed, as it doesn't necessarily have anything to do with the HEAD reference anymore. The gist of the function then is that we reset the working tree to a specific new commit, updating both the index and the checked-out files. Rename it to `reset_working_tree()` to better reflect that. Note that we don't adjust the flags yet. This will happen in a subsequent commit. Suggested-by: Phillip Wood <phillip.wood123@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-23sequencer: factor out parsing of todo commandsPhillip Wood1-12/+27
Move the code that parses todo commands into a separate function so that it can be shared with "git status" in the next commit. As we know the input is NUL terminated we do not pass a pointer to the end of the line and instead test for a blank line by looking for NUL, CR LF, or LF. We use starts_with() instead of starts_with_mem() for the same reason. This results in slightly different behavior when there a CR at the start of the line that is not followed by LF. Previously such a line was treated as a comment rather than an invalid line. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-09Merge branch 'rs/strbuf-add-oid-hex'Junio C Hamano1-2/+2
Formatting object name in full hexadecimal form has been optimized by using a new strbuf_add_oid_hex() helper function. * rs/strbuf-add-oid-hex: hex: add and use strbuf_add_oid_hex()
2026-05-25Merge branch 'ag/sequencer-remove-unused-struct-member'Junio C Hamano1-2/+0
Code clean-up. * ag/sequencer-remove-unused-struct-member: sequencer: remove todo_add_branch_context.commit
2026-05-19Merge branch 'ag/rebase-update-refs-limit-to-branches'Junio C Hamano1-1/+7
"git rebase --update-refs", when used with an rebase.instructionFormat with "%d" (describe) in it, tried to update local branch HEAD by mistake, which has been corrected. * ag/rebase-update-refs-limit-to-branches: rebase: ignore non-branch update-refs
2026-05-14hex: add and use strbuf_add_oid_hex()René Scharfe1-2/+2
Add a function for adding the full hexadecimal hash value of an object ID to a strbuf. It's thread-safe and slightly more efficient than using strbuf_addstr() with oid_to_hex() because it doesn't have to determine the length of the string or copy it from the intermediate static buffer. Add and apply a semantic patch to use it throughout the code base. I get a tiny speedup for git log showing a single hash per commit: Benchmark 1: ./git_main log --format=%H Time (mean ± σ): 91.2 ms ± 0.7 ms [User: 51.9 ms, System: 38.6 ms] Range (min … max): 89.8 ms … 92.6 ms 31 runs Benchmark 2: ./git log --format=%H Time (mean ± σ): 90.5 ms ± 0.7 ms [User: 51.0 ms, System: 38.8 ms] Range (min … max): 89.2 ms … 92.3 ms 32 runs Summary ./git log --format=%H ran 1.01 ± 0.01 times faster than ./git_main log --format=%H Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-05-12sequencer: remove todo_add_branch_context.commitAbhinav Gupta1-2/+0
The 'commit' field in 'struct todo_add_branch_context' is unused. It's written to, but never read from. add_decorations_to_list() gets the commit passed to it explicitly as an argument. Signed-off-by: Abhinav Gupta <mail@abhinavg.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-05-11rebase: ignore non-branch update-refsAbhinav Gupta1-1/+7
The following Git configuration breaks git rebase --update-refs: [rebase] instructionFormat = %s%d The '%d' format requests all available decorations for a commit, filling the global decoration table with all of them, which --update-refs then uses to populate 'update-ref' instructions in the rebase todo list. Specifically, this results in the following instruction: update-ref HEAD The todo parser then rejects the instruction: error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD error: invalid line 3: update-ref HEAD To fix, ignore decorations that are not local branches when scanning through the table. This matches the documented contract: it moves branch refs under refs/heads/ and leaves display-only decorations (HEAD, tags, etc.) alone. Verification: A regression test that fails without this fix is included. Signed-off-by: Abhinav Gupta <mail@abhinavg.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29checkout -m: autostash when switching branchesHarald Nordgren1-5/+9
When switching branches with "git checkout -m", the attempted merge of local modifications may cause conflicts with the changes made on the other branch, which the user may not want to (or may not be able to) resolve right now. Because there is no easy way to recover from this situation, we discouraged users from using "checkout -m" unless they are certain their changes are trivial and within their ability to resolve conflicts. Teach the -m flow to create a temporary stash before switching and reapply it after. On success, the stash is silently applied and the list of locally modified paths is shown, same as a successful "git checkout" without "-m". If reapplying causes conflicts, the stash is kept and the user is told they can resolve and run "git stash drop", or run "git reset --hard" and later "git stash pop" to recover their changes. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29sequencer: teach autostash apply to take optional conflict marker labelsHarald Nordgren1-9/+29
Add label_ours, label_theirs, label_base, and stash_msg parameters to apply_autostash_ref() and the autostash apply machinery so callers can pass custom conflict marker labels through to "git stash apply --label-ours/--label-theirs/--label-base", as well as a custom stash message for "git stash store -m". Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29sequencer: allow create_autostash to run silentlyHarald Nordgren1-6/+11
Add a silent parameter to create_autostash_internal and introduce create_autostash_ref_silent so that callers can create an autostash without printing the "Created autostash" message. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-03Merge branch 'sa/replay-revert'Junio C Hamano1-32/+46
"git replay" (experimental) learns, in addition to "pick" and "replay", a new operating mode "revert". * sa/replay-revert: replay: add --revert mode to reverse commit changes sequencer: extract revert message formatting into shared function