[PATCH v14 0/8] history: add squash subcommand to fold a range
"Harald Nordgren via GitGitGadget" <[email protected]>
| Newsgroups | org.kernel.vger.git |
|---|---|
| Message-ID | <[email protected]> |
Adds git history squash <revision-range> to fold a range of commits.
Changes in v14:
* Update commit message trailers.
* Simplify rev-parse and tr complexity in the tests.
Changes in v13:
* Split the squash implementation into five patches covering parsing, range
validation, branch protection, commit creation, and message editing.
* Print the sorted names of local branches that prevent a squash, with
clearer advice for --update-refs=head.
* Isolate --no-edit behavior from the final patch that enables default
editor-based message combining.
Changes in v12:
* Incorporated fixups from Phillip:
* Reworks range validation into a single walk that rejects roots and
multiple tips while preserving every parent when squashing into a
merge.
* Resolves fixup!, squash! and amend! targets directly, preserving
message intent and safely consolidating related markers.
* Builds the editor template from the exact selected revisions, including
exclusions, while retaining --no-edit behavior.
* Protects descendant local branches while leaving tags and
remote-tracking refs unchanged.
Changes in v11:
* Make message editing the default with the autosquash-style template, add
--no-edit instead of squash-specific --reedit-message.
* Validate one actual boundary and tip, rejecting root-reaching and
multi-tip ranges.
* Protect only interior local branches, leaving tags and remote-tracking
refs unchanged.
* Move sequencer preparation before squash and fold the later
message-editing patch into the feature commit.
Changes in v10:
* Record the full revision expression in squash reflog.
* Preserve the boundary-walk invariant when sanitizing rev-list options.
* Clarify amend! and --reedit-message documentation.
Changes in v9:
* Use the last amend! targeting the oldest folded commit as the default
squashed message. Ignore amend! markers targeting later commits while
selecting that replacement message.
* Improve tests.
Changes in v8:
* --reedit-message now builds the same editor template as git rebase -i
--autosquash: fixup!, squash! and amend! commits are grouped under the
commit they target instead of shown in commit order, and an amend!
replaces its target's message.
* A fixup!, squash! or amend! is refused only when its target is outside
the range, so several fixups for an in-range commit fold together. A
range that is entirely markers for one below-range target is combined
into a single commit, keeping the last amend! message.
* Merges inside the range are folded when the range has a single base, with
no dedicated opt-in flag, --ancestry-path ensures only commits descended
from the base are folded, and a range reaching more than one base is
rejected.
* Rev-list options are accepted and sanitized the way git replay does,
forcing the walk order back with a warning, which also fixes git history
squash -- --reverse slipping past the previous option check.
* Kept this as an explicit squash subcommand rather than making
--reedit-message the default or renaming the command.
Changes in v7:
* --reedit-message now builds the same editor template git rebase -i shows
for a squash (a combination of N commits banner with each folded message
under its own header) and follows autosquash for markers: a fixup!
message falls out (commented under a will be skipped header), while a
squash! or amend! keeps its body with only the marker subject commented
so its remark can be reworded in. Only the message text is affected,
every commit's changes are always folded in.
* Reuse git rebase -i's squash-message code: a preparatory sequencer:
commit extracts the banner, header and marker-comment helpers so both
rebase and git history squash build the identical template from one
source.
* Refuse a range whose oldest commit is a fixup!, squash! or amend!, since
the marker's target cannot be inside the range.
* Reorder the squash usage so dashed options come before <revision-range>,
and spell out HEAD instead of @ in the documentation and examples.
* Expand the squash commit message and documentation with this overview,
and scope the merge limitation so it no longer contradicts squash folding
a single-base interior merge.
Changes in v6:
* git history squash now accepts multiple revision arguments, read like the
arguments to git-rev-list, so a compound range such as @~3.. ^topic
works.
* The base to reparent onto is now the oldest in-range commit's parent; a
boundary other than that base means the range has more than one base and
is rejected. This also fixes the earlier overly-restrictive handling of
merges and side branches.
* A single-commit range (e.g. @^!) is rejected with "nothing to squash"
(this also covers the @^!-style example that previously succeeded
silently).
* Commit messages reworded: the squash commit now gives an overview of
fixup!/squash!/amend! handling, rewording, merge-parent and ref behavior.
Changes in v5:
* The range walk now uses --ancestry-path, so only commits descended from
the base are folded; a single revision such as HEAD or HEAD~1 is now
rejected as "not a <base>..<tip> range" rather than treated as a squash
down to the root.
* This adopts the --ancestry-path suggestion; the multi-base rejection is
unchanged, so a side branch that forked before the base and merged in is
still refused.
* Added tests covering more merge topologies: two interior merges, a nested
merge, an octopus merge, an octopus arm forked before the base, a merge
among the descendants replayed above the range, and a ref pointing at an
interior merge commit.
Changes in v4:
* git history squash now detects when another ref points at a commit inside
the range being folded and refuses, with an advice.historyUpdateRefs hint
to use --update-refs=head.
* A merge inside the range is folded fine as long as the range has a single
base; a range with merge commit at the tip or base also folds correctly.
Only a range with more than one base is rejected.
Changes in v3:
* Moved the feature out of git rebase and into a new git history squash
<revision-range> subcommand, per the list discussion. git rebase --squash
is dropped.
* Takes an arbitrary range (git history squash @~3.., git history squash
@~5..@~2), folding it into the oldest commit and replaying any
descendants on top.
* Implemented as a single tree operation rather than picking each commit,
so there are no repeated conflict stops (addresses Phillip's efficiency
point).
* A merge inside the range is folded fine, only a range with more than one
base is rejected.
* --reedit-message seeds the editor with every folded-in message, not just
the oldest.
Harald Nordgren (8):
history: extract helper for a commit's parent tree
history: give commit_tree_ext a message template
sequencer: share the squash message marker helpers and flags
history: add skeleton for squash subcommand
history: validate squash revision ranges
history: protect branches when squashing a range
history: create squashed commits without editing
history: support editing squashed commit messages
Documentation/config/advice.adoc | 4 +
Documentation/git-history.adoc | 59 +-
advice.c | 1 +
advice.h | 1 +
builtin/history.c | 720 +++++++++++++++++++++++--
object.h | 1 +
sequencer.c | 70 +--
sequencer.h | 30 ++
t/meson.build | 1 +
t/t3455-history-squash.sh | 886 +++++++++++++++++++++++++++++++
10 files changed, 1702 insertions(+), 71 deletions(-)
create mode 100755 t/t3455-history-squash.sh
base-commit: 18e66859d87fb4b76599f73460b54f0848c76b16
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2337%2FHaraldNordgren%2Frebase-fixup-fold-v14
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2337/HaraldNordgren/rebase-fixup-fold-v14
Pull-Request: https://github.com/git/git/pull/2337
Range-diff vs v13:
1: b175bdca54 = 1: 19c5e311a3 history: extract helper for a commit's parent tree
2: 965074f9e8 = 2: aadb7a5df4 history: give commit_tree_ext a message template
3: cdbdd766b2 = 3: e1621f656e sequencer: share the squash message marker helpers and flags
4: f7d953b081 ! 4: 016ae0fd42 history: add skeleton for squash subcommand
@@ Commit message
Keep this step limited to defining the revision input contract so graph
validation and the rewrite can be added independently.
+ Signed-off-by: Phillip Wood <[email protected]>
Helped-by: Phillip Wood <[email protected]>
Signed-off-by: Harald Nordgren <[email protected]>
5: dbbf66ba02 ! 5: 4992d14ce4 history: validate squash revision ranges
@@ Commit message
parents will be preserved and the single tip whose tree will be used by
the rewrite.
+ Signed-off-by: Phillip Wood <[email protected]>
Helped-by: Phillip Wood <[email protected]>
Signed-off-by: Harald Nordgren <[email protected]>
6: e71a8adfbe ! 6: b862a5b4c3 history: protect branches when squashing a range
@@ Commit message
Add advice.historyUpdateRefs for the hint that points to
--update-refs=head.
+ Signed-off-by: Phillip Wood <[email protected]>
Helped-by: Phillip Wood <[email protected]>
Signed-off-by: Harald Nordgren <[email protected]>
7: 8b3551d0d4 ! 7: 03528d3b34 history: create squashed commits without editing
@@ Commit message
applicable amend! body supplying the message.
Inspired-by: Sergey Chernov <[email protected]>
+ Signed-off-by: Phillip Wood <[email protected]>
Helped-by: Phillip Wood <[email protected]>
Signed-off-by: Harald Nordgren <[email protected]>
@@ t/t3455-history-squash.sh: test_expect_success 'errors on a single revision that
+ test_commit WIP &&
+
+ cat >msg <<-EOF &&
-+ amend! $(git rev-parse HEAD^ | tr a-f A-F)
++ amend! $(git rev-parse --short HEAD^)
+
+ The third reword
+
8: 821217ed7c ! 8: 98aa3922cb history: support editing squashed commit messages
@@ Commit message
unless a preceding squash! requires both bodies. This keeps message
editing aligned with the marker validation used by the no-edit path.
+ Signed-off-by: Phillip Wood <[email protected]>
Helped-by: Phillip Wood <[email protected]>
Signed-off-by: Harald Nordgren <[email protected]>
--
gitgitgadget