Skip to content

Commit

Permalink
Merge branch 'cc/git-replay' into seen
Browse files Browse the repository at this point in the history
* cc/git-replay:
  SQUASH???
  replay: stop assuming replayed branches do not diverge
  replay: add --contained to rebase contained branches
  replay: add --advance or 'cherry-pick' mode
  replay: disallow revision specific options and pathspecs
  replay: use standard revision ranges
  replay: make it a minimal server side command
  replay: remove HEAD related sanity check
  replay: remove progress and info output
  replay: add an important FIXME comment about gpg signing
  replay: don't simplify history
  replay: introduce pick_regular_commit()
  replay: die() instead of failing assert()
  replay: start using parse_options API
  replay: introduce new builtin
  t6429: remove switching aspects of fast-rebase
  • Loading branch information
gitster committed Jun 1, 2023
2 parents 46460e1 + b37a7d7 commit f9d70d1
Show file tree
Hide file tree
Showing 12 changed files with 794 additions and 264 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -135,6 +135,7 @@
/git-remote-ext
/git-repack
/git-replace
/git-replay
/git-request-pull
/git-rerere
/git-reset
Expand Down
125 changes: 125 additions & 0 deletions Documentation/git-replay.txt
@@ -0,0 +1,125 @@
git-replay(1)
=============

NAME
----
git-replay - Replay commits on a different base, without touching working tree


SYNOPSIS
--------
[verse]
'git replay' [--contained] (--onto <newbase> | --advance <branch>) <revision-range>...

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

Takes a range of commits, and replays them onto a new location. Does
not touch the working tree or index, and does not update any
references. However, the output of this command is meant to be used
as input to `git update-ref --stdin`, which would update the relevant
branches.

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 update-ref command(s) in the output will
update the branch(es) in the revision range to point at the new
commits (in other words, this mimics a rebase operation).

--advance <branch>::
Starting point at which to create the new commits; must be a
branch name.
+
When `--advance` is specified, the update-ref command(s) in the output
will update the branch passed as an argument to `--advance` to point at
the new commits (in other words, this mimics a cherry-pick operation).

<revision-range>::
Range of commits to replay; see "Specifying Ranges" in
linkgit:git-rev-parse.

OUTPUT
------

When there are no conflicts, the output of this command is usable as
input to `git update-ref --stdin`. It is basically 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 depend on the arguments passed. 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).

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
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
update refs/heads/target ${NEW_target_HASH} ${OLD_target_HASH}
------------

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
provides instructions to make mybranch point at the new commits and
the second provides instructions to make target 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
update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}
------------

In contrast, trying to do this with rebase would require 3 separate
rebases, eacho of which involves a different <ONTO> and <UPSTREAM> and
forces you to first check out each branch in turn.

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
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}
------------

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.

GIT
---
Part of the linkgit:git[1] suite
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -801,7 +801,6 @@ TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
TEST_BUILTINS_OBJS += test-env-helper.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-fast-rebase.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
TEST_BUILTINS_OBJS += test-genrandom.o
TEST_BUILTINS_OBJS += test-genzeros.o
Expand Down Expand Up @@ -1289,6 +1288,7 @@ BUILTIN_OBJS += builtin/remote-fd.o
BUILTIN_OBJS += builtin/remote.o
BUILTIN_OBJS += builtin/repack.o
BUILTIN_OBJS += builtin/replace.o
BUILTIN_OBJS += builtin/replay.o
BUILTIN_OBJS += builtin/rerere.o
BUILTIN_OBJS += builtin/reset.o
BUILTIN_OBJS += builtin/rev-list.o
Expand Down
1 change: 1 addition & 0 deletions builtin.h
Expand Up @@ -211,6 +211,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix);
int cmd_remote_ext(int argc, const char **argv, const char *prefix);
int cmd_remote_fd(int argc, const char **argv, const char *prefix);
int cmd_repack(int argc, const char **argv, const char *prefix);
int cmd_replay(int argc, const char **argv, const char *prefix);
int cmd_rerere(int argc, const char **argv, const char *prefix);
int cmd_reset(int argc, const char **argv, const char *prefix);
int cmd_restore(int argc, const char **argv, const char *prefix);
Expand Down

0 comments on commit f9d70d1

Please sign in to comment.