git-replay(1)
=============

NAME
----
git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos too


SYNOPSIS
--------
[verse]
(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch> | --revert <branch>) [--ref-action[=<mode>]] <revision-range>

DESCRIPTION
-----------

Takes a range of commits and replays them onto a new location. Leaves
the working tree and the index untouched. By default, updates the
relevant references using an atomic transaction (all refs update or
none). Use `--ref-action=print` to avoid automatic ref updates and
instead get update commands that can be piped to `git update-ref --stdin`
(see the <<output,OUTPUT>> section below).

THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.

OPTIONS
-------

--onto <newbase>::
	Starting point at which to create the new commits.  May be any
	valid commit, and not just an existing branch name.
+
When `--onto` is specified, the branch(es) in the revision range will be
updated to point at the new commits, similar to the way `git rebase --update-refs`
updates multiple branches in the affected range.

--advance <branch>::
	Starting point at which to create the new commits; must be a
	branch name.
+
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`.

--ref-action[=<mode>]::
	Control how references are updated. The mode can be:
+
--
	* `update` (default): Update refs directly using an atomic transaction.
	  All refs are updated or none are (all-or-nothing behavior).
	* `print`: Output update-ref commands for pipeline use. This is the
	  traditional behavior where output can be piped to `git update-ref --stdin`.
--
+
The default mode can be configured via the `replay.refAction` configuration variable.

<revision-range>::
	Range of commits to replay; see "Specifying Ranges" in
	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
include::rev-list-options.adoc[]

[[output]]
OUTPUT
------

By default, or with `--ref-action=update`, this command produces no output on
success, as refs are updated directly using an atomic transaction.

When using `--ref-action=print`, the output is usable as input to
`git update-ref --stdin`. It is of the form:

	update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
	update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
	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` 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.

[[exit-status]]
EXIT STATUS
-----------

For a successful, non-conflicted replay, the exit status is 0.  When
the replay has conflicts, the exit status is 1.  If the replay is not
able to complete (or start) due to some kind of error, the exit status
is something other than 0 or 1.

EXAMPLES
--------

To simply rebase `mybranch` onto `target`:

------------
$ git replay --onto target origin/main..mybranch
------------

The refs are updated atomically and no output is produced on success.

To see what would be updated without actually updating:

------------
$ git replay --ref-action=print --onto target origin/main..mybranch
update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
------------

To cherry-pick the commits from mybranch onto target:

------------
$ git replay --advance target origin/main..mybranch
------------

Note that the first two examples replay the exact same commits and on
top of the exact same new base, they only differ in that the first
updates mybranch to point at the new commits and the second updates
target to point at them.

What if you have a stack of branches, one depending upon another, and
you'd really like to rebase the whole set?

------------
$ git replay --contained --onto origin/main origin/main..tipbranch
------------

All three branches (`branch1`, `branch2`, and `tipbranch`) are updated
atomically.

When calling `git replay`, one does not need to specify a range of
commits to replay using the syntax `A..B`; any range expression will
do:

------------
$ git replay --onto origin/main ^base branch1 branch2 branch3
------------

This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
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
