Thread (114 messages) 114 messages, 6 authors, 1d ago
WARM1d
Revisions (8)
  1. v1 [diff vs current]
  2. v2 [diff vs current]
  3. v3 [diff vs current]
  4. v4 [diff vs current]
  5. v5 [diff vs current]
  6. v6 [diff vs current]
  7. v7 [diff vs current]
  8. v8 current

[PATCH v8 00/11] builtin/history: introduce "drop" subcommand

From: Patrick Steinhardt <hidden>
Date: 2026-07-01 11:35:43

Hi,

this small patch series introduces the new "drop" subcommand for
git-history(1). As a reader might guess, the command does exactly that:
given a commit, it will drop that commit from the commit history and
replay descendant branches on top of it.

Changes in v8:
  - Pass `RESOLVE_REF_READING` to make `refs_resolve_ref_unsafe()`
    return a NULL pointer when it cannot resolve the reference.
  - Drop unneeded code that sets `head_target = "HEAD"` on detached
    HEAD.
  - Add a test case that verifies that we can drop commits with
    "--update-refs=head" and a detached HEAD.
  - Link to v7: https://patch.msgid.link/20260629-b4-pks-history-drop-v7-0-6e9392a957d8@pks.im

Changes in v7:
  - Expose `replay_result_queue_update()` so that we don't have to
    duplicate its functionality.
  - Add missing SOB.
  - Link to v6: https://patch.msgid.link/20260615-b4-pks-history-drop-v6-0-2e329e536d78@pks.im

Changes in v6:
  - Fix bad interactions of DRY_RUN with UPDATE_HEAD
  - Link to v5: https://patch.msgid.link/20260611-b4-pks-history-drop-v5-0-34d35725559c@pks.im

Changes in v5:
  - Reject UPDATE_ORIG_HEAD without UPDATE_HEAD.
  - Link to v4: https://patch.msgid.link/20260610-b4-pks-history-drop-v4-0-70d5f0ae8c25@pks.im

Changes in v4:
  - Remove the `SKIP_REF_UPDATES` flag in favor of a new `UPDATE_HEAD`
    flag, as suggested by Phillip.
  - Rename `reset_head()` to `reset_working_tree()`. This better matches
    the new scope of the function, and it helps us to catch any
    in-flight patches that would now have to set the `UPDATE_HEAD` flag.
  - Link to v3: https://patch.msgid.link/20260608-b4-pks-history-drop-v3-0-84ca8e43e937@pks.im

Changes in v3:
  - Fix commit message typos.
  - Make `update_orig_head` and `skip_ref_updates` mutually exclusive.
  - Use fancy revisions to specify the commit to drop in the example
    section.
  - Detect conflicting changes in the index/working tree in dry-run
    mode.
  - Consistently use a subshell.
  - Rename `RESET_HEAD_ORIG_HEAD` to `RESET_HEAD_UPDATE_ORIG_HEAD`.
  - Link to v2: https://patch.msgid.link/20260603-b4-pks-history-drop-v2-0-742cb5b5176d@pks.im

Changes in v2:
  - Reworked `update_worktree()` to use `reset_head()`, which required a
    bunch of changes to `reset_head()`.
  - Consistently mention the commit that cannot be dropped as part of
    error messages.
  - Adapt error message to not use backticks anymore.
  - Drop redundant "--graph" flag in a test helper.
  - Link to v1: https://patch.msgid.link/20260601-b4-pks-history-drop-v1-0-643e32340d55@pks.im

Thanks!

Patrick

---
Patrick Steinhardt (11):
      read-cache: split out function to drop unmerged entries to stage 0
      reset: drop `USE_THE_REPOSITORY_VARIABLE`
      reset: rename `reset_head()`
      reset: modernize flags passed to `reset_working_tree()`
      reset: introduce dry-run mode
      reset: introduce ability to skip updating HEAD
      reset: allow the caller to specify the current HEAD object
      reset: stop assuming that the caller passes in a clean index
      replay: expose `replay_result_queue_update()`
      builtin/history: split handling of ref updates into two phases
      builtin/history: implement "drop" subcommand

 Documentation/git-history.adoc |  38 ++-
 builtin/history.c              | 284 ++++++++++++++++++---
 builtin/rebase.c               |  41 +--
 read-cache-ll.h                |   1 +
 read-cache.c                   |  12 +-
 replay.c                       |   8 +-
 replay.h                       |   5 +
 reset.c                        | 102 +++++---
 reset.h                        |  51 ++--
 sequencer.c                    |  17 +-
 t/meson.build                  |   1 +
 t/t3454-history-drop.sh        | 561 +++++++++++++++++++++++++++++++++++++++++
 12 files changed, 1000 insertions(+), 121 deletions(-)

Range-diff versus v7:

 1:  4b8702dbff =  1:  8145bb1408 read-cache: split out function to drop unmerged entries to stage 0
 2:  1794f27cc4 =  2:  022d65d3db reset: drop `USE_THE_REPOSITORY_VARIABLE`
 3:  2cb6c21f6a =  3:  c37abd69d3 reset: rename `reset_head()`
 4:  55fb296c39 =  4:  84f80ff33b reset: modernize flags passed to `reset_working_tree()`
 5:  b57d52b5ca =  5:  2465dcf8ec reset: introduce dry-run mode
 6:  a54dbccb17 =  6:  65b1853ce4 reset: introduce ability to skip updating HEAD
 7:  f22a1c9b70 =  7:  acfc768574 reset: allow the caller to specify the current HEAD object
 8:  5ec7867767 =  8:  8e2d3fa7b3 reset: stop assuming that the caller passes in a clean index
 9:  d8c9548408 =  9:  80015c6cec replay: expose `replay_result_queue_update()`
10:  d01ce11892 = 10:  b518dcd5ef builtin/history: split handling of ref updates into two phases
11:  1ee3600b98 ! 11:  963636e72c builtin/history: implement "drop" subcommand
    @@ builtin/history.c: static int cmd_history_split(int argc,
     +
     +	*changed = false;
     +
    -+	head_target = refs_resolve_ref_unsafe(get_main_ref_store(repo),
    -+					      "HEAD", RESOLVE_REF_NO_RECURSE,
    ++	head_target = refs_resolve_ref_unsafe(get_main_ref_store(repo), "HEAD",
    ++					      RESOLVE_REF_NO_RECURSE | RESOLVE_REF_READING,
     +					      NULL, &head_flags);
     +	if (!head_target)
     +		return error(_("cannot look up HEAD"));
    -+	if (!(head_flags & REF_ISSYMREF))
    -+		head_target = "HEAD";
     +
     +	for (size_t i = 0; i < result->updates_nr; i++) {
     +		if (!strcmp(result->updates[i].refname, head_target)) {
    @@ t/t3454-history-drop.sh (new)
     +	)
     +'
     +
    ++test_expect_success '--update-refs=head can rewrite detached HEAD' '
    ++	test_when_finished "rm -rf repo" &&
    ++	git init repo --initial-branch=main &&
    ++	(
    ++		cd repo &&
    ++		test_commit first &&
    ++		test_commit second &&
    ++		test_commit third &&
    ++		git switch --detach HEAD &&
    ++
    ++		git history drop --update-refs=head second &&
    ++
    ++		expect_log HEAD <<-\EOF &&
    ++		third
    ++		first
    ++		EOF
    ++		expect_log main <<-\EOF
    ++		third
    ++		second
    ++		first
    ++		EOF
    ++	)
    ++'
    ++
     +test_expect_success 'conflict with replayed commit aborts cleanly' '
     +	test_when_finished "rm -rf repo" &&
     +	git init repo &&

---
base-commit: 1666c1265231b0bc5f613fbbf3f0a9896cdef76e
change-id: 20260601-b4-pks-history-drop-28f6c6399e7b
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help