diff options
| author | Siddharth Asthana <siddharthasthana31@gmail.com> | 2026-03-26 01:53:52 +0530 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-25 14:21:20 -0700 |
| commit | 2760ee49834953c0860fa5d7983a6af4d27cb6a9 (patch) | |
| tree | 9798f8a97b0a3a52c048501c9990756da1a42e88 /Documentation | |
| parent | 1e6434ebbd63d4ec0ad2f8bccf25bd0d98d55030 (diff) | |
| download | git-2760ee49834953c0860fa5d7983a6af4d27cb6a9.tar.xz | |
replay: add --revert mode to reverse commit changes
Add a `--revert <branch>` mode to git replay that undoes the changes
introduced by the specified commits. Like --onto and --advance, --revert
is a standalone mode: it takes a branch argument and updates that branch
with the newly created revert commits.
At GitLab, we need this in Gitaly for reverting commits directly on bare
repositories without requiring a working tree checkout.
The approach is the same as sequencer.c's do_pick_commit() -- cherry-pick
and revert are just the same three-way merge with swapped arguments:
- Cherry-pick: merge(ancestor=parent, ours=current, theirs=commit)
- Revert: merge(ancestor=commit, ours=current, theirs=parent)
We swap the base and pickme trees passed to merge_incore_nonrecursive()
to reverse the diff direction.
Reverts are processed newest-first (matching git revert behavior) to
reduce conflicts by peeling off changes from the top. Each revert
builds on the result of the previous one via the last_commit fallback
in the main replay loop, rather than relying on the parent-mapping
used for cherry-pick.
Revert commit messages follow the usual git revert conventions: prefixed
with "Revert" (or "Reapply" when reverting a revert), and including
"This reverts commit <hash>.". The author is set to the current user
rather than preserving the original author, matching git revert behavior.
Helped-by: Christian Couder <christian.couder@gmail.com>
Helped-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Elijah Newren <newren@gmail.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'Documentation')
| -rw-r--r-- | Documentation/git-replay.adoc | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc index 8d696ce3ab..997097e420 100644 --- a/Documentation/git-replay.adoc +++ b/Documentation/git-replay.adoc @@ -9,7 +9,7 @@ git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos t SYNOPSIS -------- [verse] -(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) [--ref-action[=<mode>]] <revision-range> +(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) [--ref-action[=<mode>]] <revision-range> DESCRIPTION ----------- @@ -42,6 +42,25 @@ 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. +--revert <branch>:: + Starting point at which to create the reverted commits; must be a + branch name. ++ +When `--revert` is specified, the commits in the revision range are reverted +(their changes are undone) and the reverted commits are created on top of +<branch>. The <branch> is then updated to point at the new commits. This is +the same as running `git revert <revision-range>` but does not update the +working tree. ++ +The commit messages follow `git revert` conventions: they are prefixed with +"Revert" and include "This reverts commit <hash>." When reverting a commit +whose message starts with "Revert", the new message uses "Reapply" instead. +Unlike cherry-pick which preserves the original author, revert commits use +the current user as the author, matching the behavior of `git revert`. ++ +This option is mutually exclusive with `--onto` and `--advance`. It is also +incompatible with `--contained` (which is a modifier for `--onto` only). + --contained:: Update all branches that point at commits in <revision-range>. Requires `--onto`. @@ -60,10 +79,11 @@ The default mode can be configured via the `replay.refAction` configuration vari <revision-range>:: Range of commits to replay; see "Specifying Ranges" in - linkgit:git-rev-parse[1]. In `--advance <branch>` mode, the - range should have a single tip, so that it's clear to which tip the - advanced <branch> should point. Any commits in the range whose - changes are already present in the branch the commits are being + linkgit:git-rev-parse[1]. In `--advance <branch>` or + `--revert <branch>` mode, the range should have a single tip, + so that it's clear to which tip the advanced or reverted + <branch> should point. Any commits in the range whose changes + are already present in the branch the commits are being replayed onto will be dropped. :git-replay: 1 @@ -84,9 +104,10 @@ When using `--ref-action=print`, the output is usable as input to update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH} where the number of refs updated depends on the arguments passed and -the shape of the history being replayed. When using `--advance`, the -number of refs updated is always one, but for `--onto`, it can be one -or more (rebasing multiple branches simultaneously is supported). +the shape of the history being replayed. When using `--advance` or +`--revert`, the number of refs updated is always one, but for `--onto`, +it can be one or more (rebasing multiple branches simultaneously is +supported). There is no stderr output on conflicts; see the <<exit-status,EXIT STATUS>> section below. @@ -152,6 +173,21 @@ all commits they have since `base`, playing them on top of `origin/main`. These three branches may have commits on top of `base` that they have in common, but that does not need to be the case. +To revert commits on a branch: + +------------ +$ git replay --revert main topic~2..topic +------------ + +This reverts the last two commits from `topic`, creating revert commits on +top of `main`, and updates `main` to point at the result. This is useful when +commits from `topic` were previously merged or cherry-picked into `main` and +need to be undone. + +NOTE: For reverting an entire merge request as a single commit (rather than +commit-by-commit), consider using `git merge-tree --merge-base $TIP HEAD $BASE` +which can avoid unnecessary merge conflicts. + GIT --- Part of the linkgit:git[1] suite |
