2005-06-25 11:23:43 +02:00
|
|
|
#!/bin/sh
|
|
|
|
#
|
|
|
|
# Copyright (c) 2005 Junio C Hamano.
|
|
|
|
#
|
|
|
|
|
2007-01-12 21:52:03 +01:00
|
|
|
SUBDIRECTORY_OK=Yes
|
2011-03-01 02:59:26 +01:00
|
|
|
OPTIONS_KEEPDASHDASH=
|
2014-02-10 02:03:36 +01:00
|
|
|
OPTIONS_STUCKLONG=t
|
2011-03-01 02:59:26 +01:00
|
|
|
OPTIONS_SPEC="\
|
2012-06-12 10:05:12 +02:00
|
|
|
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
|
2012-07-16 06:38:41 +02:00
|
|
|
git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
|
2017-11-20 16:26:52 +01:00
|
|
|
git rebase --continue | --abort | --skip | --edit-todo
|
2011-03-01 02:59:26 +01:00
|
|
|
--
|
|
|
|
Available options are
|
|
|
|
v,verbose! display a diffstat of what changed upstream
|
|
|
|
q,quiet! be quiet. implies --no-stat
|
2015-09-11 00:30:51 +02:00
|
|
|
autostash automatically stash/stash pop before and after
|
2013-12-10 00:16:16 +01:00
|
|
|
fork-point use 'merge-base --fork-point' to refine upstream
|
2011-03-01 02:59:26 +01:00
|
|
|
onto=! rebase onto given branch instead of upstream
|
rebase -i: introduce --rebase-merges=[no-]rebase-cousins
When running `git rebase --rebase-merges` non-interactively with an
ancestor of HEAD as <upstream> (or leaving the todo list unmodified),
we would ideally recreate the exact same commits as before the rebase.
However, if there are commits in the commit range <upstream>.. that do not
have <upstream> as direct ancestor (i.e. if `git log <upstream>..` would
show commits that are omitted by `git log --ancestry-path <upstream>..`),
this is currently not the case: we would turn them into commits that have
<upstream> as direct ancestor.
Let's illustrate that with a diagram:
C
/ \
A - B - E - F
\ /
D
Currently, after running `git rebase -i --rebase-merges B`, the new branch
structure would be (pay particular attention to the commit `D`):
--- C' --
/ \
A - B ------ E' - F'
\ /
D'
This is not really preserving the branch topology from before! The
reason is that the commit `D` does not have `B` as ancestor, and
therefore it gets rebased onto `B`.
This is unintuitive behavior. Even worse, when recreating branch
structure, most use cases would appear to want cousins *not* to be
rebased onto the new base commit. For example, Git for Windows (the
heaviest user of the Git garden shears, which served as the blueprint
for --rebase-merges) frequently merges branches from `next` early, and
these branches certainly do *not* want to be rebased. In the example
above, the desired outcome would look like this:
--- C' --
/ \
A - B ------ E' - F'
\ /
-- D' --
Let's introduce the term "cousins" for such commits ("D" in the
example), and let's not rebase them by default. For hypothetical
use cases where cousins *do* need to be rebased, `git rebase
--rebase=merges=rebase-cousins` needs to be used.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:40 +02:00
|
|
|
r,rebase-merges? try to rebase merges instead of skipping them
|
2011-03-01 02:59:26 +01:00
|
|
|
p,preserve-merges! try to recreate merges instead of ignoring them
|
|
|
|
s,strategy=! use the given merge strategy
|
2018-06-25 18:12:53 +02:00
|
|
|
X,strategy-option=! pass the argument through to the merge strategy
|
2011-03-01 02:59:26 +01:00
|
|
|
no-ff! cherry-pick all commits, even if unchanged
|
2018-06-25 18:12:53 +02:00
|
|
|
f,force-rebase! cherry-pick all commits, even if unchanged
|
2011-03-01 02:59:26 +01:00
|
|
|
m,merge! use merging strategies to rebase
|
|
|
|
i,interactive! let the user edit the list of commits to rebase
|
2012-06-12 10:05:12 +02:00
|
|
|
x,exec=! add exec lines after each commit of the editable list
|
2012-04-20 16:36:17 +02:00
|
|
|
k,keep-empty preserve empty commits during rebase
|
2018-02-04 21:08:13 +01:00
|
|
|
allow-empty-message allow rebasing commits with empty messages
|
2011-03-01 02:59:26 +01:00
|
|
|
stat! display a diffstat of what changed upstream
|
|
|
|
n,no-stat! do not show diffstat of what changed upstream
|
|
|
|
verify allow pre-rebase hook to run
|
|
|
|
rerere-autoupdate allow rerere to update index with resolved conflicts
|
|
|
|
root! rebase all reachable commits up to the root(s)
|
|
|
|
autosquash move commits that begin with squash!/fixup! under -i
|
2018-06-25 18:12:53 +02:00
|
|
|
signoff add a Signed-off-by: line to each commit
|
2011-03-01 02:59:26 +01:00
|
|
|
committer-date-is-author-date! passed to 'git am'
|
|
|
|
ignore-date! passed to 'git am'
|
|
|
|
whitespace=! passed to 'git apply'
|
|
|
|
ignore-whitespace! passed to 'git apply'
|
|
|
|
C=! passed to 'git apply'
|
2014-02-10 02:03:37 +01:00
|
|
|
S,gpg-sign? GPG-sign commits
|
2011-03-01 02:59:26 +01:00
|
|
|
Actions:
|
2011-07-14 05:47:06 +02:00
|
|
|
continue! continue
|
|
|
|
abort! abort and check out the original branch
|
|
|
|
skip! skip current patch and continue
|
2012-09-18 03:28:09 +02:00
|
|
|
edit-todo! edit the todo list during an interactive rebase
|
2016-11-12 03:00:41 +01:00
|
|
|
quit! abort but keep HEAD where it is
|
2018-02-11 10:43:27 +01:00
|
|
|
show-current-patch! show the patch file being applied or merged
|
2011-03-01 02:59:26 +01:00
|
|
|
"
|
2005-11-24 09:12:11 +01:00
|
|
|
. git-sh-setup
|
2006-12-28 08:34:48 +01:00
|
|
|
set_reflog_action rebase
|
pull,rebase: handle GIT_WORK_TREE better
You can't currently run git-pull or git-rebase from outside
of the work tree, even with GIT_WORK_TREE set, due to an
overeager require_work_tree function. Commit e2eb527
documents this problem and provides the infrastructure for a
fix, but left it to later commits to audit and update
individual scripts.
Changing these scripts to use require_work_tree_exists is
easy to verify. We immediately call cd_to_toplevel, anyway.
Therefore no matter which function we use, the state
afterwards is one of:
1. We have a work tree, and we are at the top level.
2. We don't have a work tree, and we have died.
The only catch is that we must also make sure no code that
ran before the cd_to_toplevel assumed that we were already
in the working tree.
In this case, we will only have included shell libraries and
called set_reflog_action, neither of which care about the
current working directory at all.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-13 17:59:24 +02:00
|
|
|
require_work_tree_exists
|
2007-01-12 21:52:03 +01:00
|
|
|
cd_to_toplevel
|
2005-08-08 00:51:09 +02:00
|
|
|
|
2009-11-20 12:02:44 +01:00
|
|
|
LF='
|
|
|
|
'
|
2011-02-06 19:43:37 +01:00
|
|
|
ok_to_skip_pre_rebase=
|
|
|
|
resolvemsg="
|
2017-07-16 21:42:20 +02:00
|
|
|
$(gettext 'Resolve all conflicts manually, mark them as resolved with
|
|
|
|
"git add/rm <conflicted_files>", then run "git rebase --continue".
|
|
|
|
You can instead skip this commit: run "git rebase --skip".
|
|
|
|
To abort and get back to the state before "git rebase", run "git rebase --abort".')
|
2006-05-14 05:34:08 +02:00
|
|
|
"
|
2018-03-20 11:03:13 +01:00
|
|
|
squash_onto=
|
2011-02-06 19:43:37 +01:00
|
|
|
unset onto
|
2014-07-16 21:23:49 +02:00
|
|
|
unset restrict_revision
|
2012-06-12 10:05:12 +02:00
|
|
|
cmd=
|
2011-02-06 19:43:38 +01:00
|
|
|
strategy=
|
2010-07-29 00:04:29 +02:00
|
|
|
strategy_opts=
|
2006-06-21 12:04:41 +02:00
|
|
|
do_merge=
|
2011-02-06 19:43:30 +01:00
|
|
|
merge_dir="$GIT_DIR"/rebase-merge
|
|
|
|
apply_dir="$GIT_DIR"/rebase-apply
|
2006-10-03 18:29:31 +02:00
|
|
|
verbose=
|
2010-11-09 21:59:00 +01:00
|
|
|
diffstat=
|
|
|
|
test "$(git config --bool rebase.stat)" = true && diffstat=t
|
2013-05-12 13:56:41 +02:00
|
|
|
autostash="$(git config --bool rebase.autostash || echo false)"
|
2013-12-10 00:16:16 +01:00
|
|
|
fork_point=auto
|
2007-02-08 14:57:08 +01:00
|
|
|
git_am_opt=
|
2017-08-10 20:32:56 +02:00
|
|
|
git_format_patch_opt=
|
2009-01-05 18:35:16 +01:00
|
|
|
rebase_root=
|
2009-02-13 23:48:01 +01:00
|
|
|
force_rebase=
|
2009-12-04 09:20:48 +01:00
|
|
|
allow_rerere_autoupdate=
|
2011-02-06 19:43:34 +01:00
|
|
|
# Non-empty if a rebase was in progress when 'git rebase' was invoked
|
|
|
|
in_progress=
|
|
|
|
# One of {am, merge, interactive}
|
|
|
|
type=
|
|
|
|
# One of {"$GIT_DIR"/rebase-apply, "$GIT_DIR"/rebase-merge}
|
|
|
|
state_dir=
|
2011-02-06 19:43:35 +01:00
|
|
|
# One of {'', continue, skip, abort}, as parsed from command line
|
|
|
|
action=
|
rebase: introduce the --rebase-merges option
Once upon a time, this here developer thought: wouldn't it be nice if,
say, Git for Windows' patches on top of core Git could be represented as
a thicket of branches, and be rebased on top of core Git in order to
maintain a cherry-pick'able set of patch series?
The original attempt to answer this was: git rebase --preserve-merges.
However, that experiment was never intended as an interactive option,
and it only piggy-backed on git rebase --interactive because that
command's implementation looked already very, very familiar: it was
designed by the same person who designed --preserve-merges: yours truly.
Some time later, some other developer (I am looking at you, Andreas!
;-)) decided that it would be a good idea to allow --preserve-merges to
be combined with --interactive (with caveats!) and the Git maintainer
(well, the interim Git maintainer during Junio's absence, that is)
agreed, and that is when the glamor of the --preserve-merges design
started to fall apart rather quickly and unglamorously.
The reason? In --preserve-merges mode, the parents of a merge commit (or
for that matter, of *any* commit) were not stated explicitly, but were
*implied* by the commit name passed to the `pick` command.
This made it impossible, for example, to reorder commits. Not to mention
to move commits between branches or, deity forbid, to split topic branches
into two.
Alas, these shortcomings also prevented that mode (whose original
purpose was to serve Git for Windows' needs, with the additional hope
that it may be useful to others, too) from serving Git for Windows'
needs.
Five years later, when it became really untenable to have one unwieldy,
big hodge-podge patch series of partly related, partly unrelated patches
in Git for Windows that was rebased onto core Git's tags from time to
time (earning the undeserved wrath of the developer of the ill-fated
git-remote-hg series that first obsoleted Git for Windows' competing
approach, only to be abandoned without maintainer later) was really
untenable, the "Git garden shears" were born [*1*/*2*]: a script,
piggy-backing on top of the interactive rebase, that would first
determine the branch topology of the patches to be rebased, create a
pseudo todo list for further editing, transform the result into a real
todo list (making heavy use of the `exec` command to "implement" the
missing todo list commands) and finally recreate the patch series on
top of the new base commit.
That was in 2013. And it took about three weeks to come up with the
design and implement it as an out-of-tree script. Needless to say, the
implementation needed quite a few years to stabilize, all the while the
design itself proved itself sound.
With this patch, the goodness of the Git garden shears comes to `git
rebase -i` itself. Passing the `--rebase-merges` option will generate
a todo list that can be understood readily, and where it is obvious
how to reorder commits. New branches can be introduced by inserting
`label` commands and calling `merge <label>`. And once this mode will
have become stable and universally accepted, we can deprecate the design
mistake that was `--preserve-merges`.
Link *1*:
https://github.com/msysgit/msysgit/blob/master/share/msysGit/shears.sh
Link *2*:
https://github.com/git-for-windows/build-extra/blob/master/shears.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:04 +02:00
|
|
|
rebase_merges=
|
rebase -i: introduce --rebase-merges=[no-]rebase-cousins
When running `git rebase --rebase-merges` non-interactively with an
ancestor of HEAD as <upstream> (or leaving the todo list unmodified),
we would ideally recreate the exact same commits as before the rebase.
However, if there are commits in the commit range <upstream>.. that do not
have <upstream> as direct ancestor (i.e. if `git log <upstream>..` would
show commits that are omitted by `git log --ancestry-path <upstream>..`),
this is currently not the case: we would turn them into commits that have
<upstream> as direct ancestor.
Let's illustrate that with a diagram:
C
/ \
A - B - E - F
\ /
D
Currently, after running `git rebase -i --rebase-merges B`, the new branch
structure would be (pay particular attention to the commit `D`):
--- C' --
/ \
A - B ------ E' - F'
\ /
D'
This is not really preserving the branch topology from before! The
reason is that the commit `D` does not have `B` as ancestor, and
therefore it gets rebased onto `B`.
This is unintuitive behavior. Even worse, when recreating branch
structure, most use cases would appear to want cousins *not* to be
rebased onto the new base commit. For example, Git for Windows (the
heaviest user of the Git garden shears, which served as the blueprint
for --rebase-merges) frequently merges branches from `next` early, and
these branches certainly do *not* want to be rebased. In the example
above, the desired outcome would look like this:
--- C' --
/ \
A - B ------ E' - F'
\ /
-- D' --
Let's introduce the term "cousins" for such commits ("D" in the
example), and let's not rebase them by default. For hypothetical
use cases where cousins *do* need to be rebased, `git rebase
--rebase=merges=rebase-cousins` needs to be used.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:40 +02:00
|
|
|
rebase_cousins=
|
2011-02-06 19:43:39 +01:00
|
|
|
preserve_merges=
|
|
|
|
autosquash=
|
2012-04-20 16:36:17 +02:00
|
|
|
keep_empty=
|
git-rebase: make --allow-empty-message the default
rebase backends currently behave differently with empty commit messages,
largely as a side-effect of the different underlying commands on which
they are based. am-based rebases apply commits with an empty commit
message without stopping or requiring the user to specify an extra flag.
(It is interesting to note that am-based rebases are the default rebase
type, and no one has ever requested a --no-allow-empty-message flag to
change this behavior.) merge-based and interactive-based rebases (which
are ultimately based on git-commit), will currently halt on any such
commits and require the user to manually specify what to do with the
commit and continue.
One possible rationale for the difference in behavior is that the purpose
of an "am" based rebase is solely to transplant an existing history, while
an "interactive" rebase is one whose purpose is to polish a series before
making it publishable. Thus, stopping and asking for confirmation for a
possible problem is more appropriate in the latter case. However, there
are two problems with this rationale:
1) merge-based rebases are also non-interactive and there are multiple
types of rebases that use the interactive machinery but are not
explicitly interactive (e.g. when either --rebase-merges or
--keep-empty are specified without --interactive). These rebases are
also used solely to transplant an existing history, and thus also
should default to --allow-empty-message.
2) this rationale only says that the user is more accepting of stopping
in the case of an explicitly interactive rebase, not that stopping
for this particular reason actually makes sense. Exploring whether
it makes sense, requires backing up and analyzing the underlying
commands...
If git-commit did not error out on empty commits by default, accidental
creation of commits with empty messages would be a very common occurrence
(this check has caught me many times). Further, nearly all such empty
commit messages would be considered an accidental error (as evidenced by a
huge amount of documentation across version control systems and in various
blog posts explaining how important commit messages are). A simple check
for what would otherwise be a common error thus made a lot of sense, and
git-commit gained an --allow-empty-message flag for special case
overrides. This has made commits with empty messages very rare.
There are two sources for commits with empty messages for rebase (and
cherry-pick): (a) commits created in git where the user previously
specified --allow-empty-message to git-commit, and (b) commits imported
into git from other version control systems. In case (a), the user has
already explicitly specified that there is something special about this
commit that makes them not want to specify a commit message; forcing them
to re-specify with every cherry-pick or rebase seems more likely to be
infuriating than helpful. In case (b), the commit is highly unlikely to
have been authored by the person who has imported the history and is doing
the rebase or cherry-pick, and thus the user is unlikely to be the
appropriate person to write a commit message for it. Stopping and
expecting the user to modify the commit before proceeding thus seems
counter-productive.
Further, note that while empty commit messages was a common error case for
git-commit to deal with, it is a rare case for rebase (or cherry-pick).
The fact that it is rare raises the question of why it would be worth
checking and stopping on this particular condition and not others. For
example, why doesn't an interactive rebase automatically stop if the
commit message's first line is 2000 columns long, or is missing a blank
line after the first line, or has every line indented with five spaces, or
any number of other myriad problems?
Finally, note that if a user doing an interactive rebase does have the
necessary knowledge to add a message for any such commit and wants to do
so, it is rather simple for them to change the appropriate line from
'pick' to 'reword'. The fact that the subject is empty in the todo list
that the user edits should even serve as a way to notify them.
As far as I can tell, the fact that merge-based and interactive-based
rebases stop on commits with empty commit messages is solely a by-product
of having been based on git-commit. It went without notice for a long
time precisely because such cases are rare. The rareness of this
situation made it difficult to reason about, so when folks did eventually
notice this behavior, they assumed it was there for a good reason and just
added an --allow-empty-message flag. In my opinion, stopping on such
messages not desirable in any of these cases, even the (explicitly)
interactive case.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-27 09:23:19 +02:00
|
|
|
allow_empty_message=--allow-empty-message
|
2018-03-20 12:10:55 +01:00
|
|
|
signoff=
|
2011-02-06 19:43:39 +01:00
|
|
|
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
|
2016-05-02 23:58:45 +02:00
|
|
|
case "$(git config --bool commit.gpgsign)" in
|
|
|
|
true) gpg_sign_opt=-S ;;
|
|
|
|
*) gpg_sign_opt= ;;
|
|
|
|
esac
|
2006-06-21 12:04:41 +02:00
|
|
|
|
2011-02-06 19:43:47 +01:00
|
|
|
read_basic_state () {
|
2013-06-13 18:06:11 +02:00
|
|
|
test -f "$state_dir/head-name" &&
|
|
|
|
test -f "$state_dir/onto" &&
|
rebase: refactor reading of state
The code reading the state saved in $merge_dir or $rebase_dir is
currently spread out in many places, making it harder to read and to
introduce additional state. Extract this code into one method that
reads the state. Only extract the code associated with the state that
is written when the rebase is initiated. Leave the state that changes
for each commmit, at least for now.
Currently, when resuming a merge-based rebase using --continue or
--skip, move_to_original_branch (via finish_rb_merge) will be called
without head_name and orig_head set. These variables are then lazily
read in move_to_original_branch if head_name is not set (together with
onto, which is unnecessarily read again). Change this by always
eagerly reading the state, for both am-based and merge-based rebase,
in the --continue and --skip cases. Note that this does not change the
behavior for am-based rebase, which read the state eagerly even before
this commit.
Reading the state eagerly means that part of the state will sometimes
be read unnecessarily. One example is when the rebase is continued,
but stops again at another merge conflict. Another example is when the
rebase is aborted. However, since both of these cases involve user
interaction, the delay is hopefully not noticeable. The
call_merge/continue_merge loop is not affected.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-06 19:43:31 +01:00
|
|
|
head_name=$(cat "$state_dir"/head-name) &&
|
|
|
|
onto=$(cat "$state_dir"/onto) &&
|
2011-02-06 19:43:53 +01:00
|
|
|
# We always write to orig-head, but interactive rebase used to write to
|
|
|
|
# head. Fall back to reading from head to cover for the case that the
|
|
|
|
# user upgraded git with an ongoing interactive rebase.
|
|
|
|
if test -f "$state_dir"/orig-head
|
2011-02-06 19:43:52 +01:00
|
|
|
then
|
|
|
|
orig_head=$(cat "$state_dir"/orig-head)
|
2011-02-06 19:43:53 +01:00
|
|
|
else
|
|
|
|
orig_head=$(cat "$state_dir"/head)
|
2011-02-06 19:43:52 +01:00
|
|
|
fi &&
|
2011-02-06 19:43:54 +01:00
|
|
|
GIT_QUIET=$(cat "$state_dir"/quiet) &&
|
|
|
|
test -f "$state_dir"/verbose && verbose=t
|
2011-02-06 19:43:55 +01:00
|
|
|
test -f "$state_dir"/strategy && strategy="$(cat "$state_dir"/strategy)"
|
|
|
|
test -f "$state_dir"/strategy_opts &&
|
|
|
|
strategy_opts="$(cat "$state_dir"/strategy_opts)"
|
2011-02-06 19:43:56 +01:00
|
|
|
test -f "$state_dir"/allow_rerere_autoupdate &&
|
|
|
|
allow_rerere_autoupdate="$(cat "$state_dir"/allow_rerere_autoupdate)"
|
2014-02-10 02:03:37 +01:00
|
|
|
test -f "$state_dir"/gpg_sign_opt &&
|
|
|
|
gpg_sign_opt="$(cat "$state_dir"/gpg_sign_opt)"
|
2018-03-20 12:10:55 +01:00
|
|
|
test -f "$state_dir"/signoff && {
|
|
|
|
signoff="$(cat "$state_dir"/signoff)"
|
|
|
|
force_rebase=t
|
|
|
|
}
|
rebase: refactor reading of state
The code reading the state saved in $merge_dir or $rebase_dir is
currently spread out in many places, making it harder to read and to
introduce additional state. Extract this code into one method that
reads the state. Only extract the code associated with the state that
is written when the rebase is initiated. Leave the state that changes
for each commmit, at least for now.
Currently, when resuming a merge-based rebase using --continue or
--skip, move_to_original_branch (via finish_rb_merge) will be called
without head_name and orig_head set. These variables are then lazily
read in move_to_original_branch if head_name is not set (together with
onto, which is unnecessarily read again). Change this by always
eagerly reading the state, for both am-based and merge-based rebase,
in the --continue and --skip cases. Note that this does not change the
behavior for am-based rebase, which read the state eagerly even before
this commit.
Reading the state eagerly means that part of the state will sometimes
be read unnecessarily. One example is when the rebase is continued,
but stops again at another merge conflict. Another example is when the
rebase is aborted. However, since both of these cases involve user
interaction, the delay is hopefully not noticeable. The
call_merge/continue_merge loop is not affected.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-02-06 19:43:31 +01:00
|
|
|
}
|
|
|
|
|
2011-02-06 19:43:53 +01:00
|
|
|
write_basic_state () {
|
|
|
|
echo "$head_name" > "$state_dir"/head-name &&
|
|
|
|
echo "$onto" > "$state_dir"/onto &&
|
|
|
|
echo "$orig_head" > "$state_dir"/orig-head &&
|
2011-02-06 19:43:54 +01:00
|
|
|
echo "$GIT_QUIET" > "$state_dir"/quiet &&
|
|
|
|
test t = "$verbose" && : > "$state_dir"/verbose
|
2011-02-06 19:43:55 +01:00
|
|
|
test -n "$strategy" && echo "$strategy" > "$state_dir"/strategy
|
|
|
|
test -n "$strategy_opts" && echo "$strategy_opts" > \
|
|
|
|
"$state_dir"/strategy_opts
|
2011-02-06 19:43:56 +01:00
|
|
|
test -n "$allow_rerere_autoupdate" && echo "$allow_rerere_autoupdate" > \
|
|
|
|
"$state_dir"/allow_rerere_autoupdate
|
2014-02-10 02:03:37 +01:00
|
|
|
test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
|
2018-03-20 12:10:55 +01:00
|
|
|
test -n "$signoff" && echo "$signoff" >"$state_dir"/signoff
|
2011-02-06 19:43:53 +01:00
|
|
|
}
|
|
|
|
|
2011-02-06 19:43:51 +01:00
|
|
|
output () {
|
|
|
|
case "$verbose" in
|
|
|
|
'')
|
|
|
|
output=$("$@" 2>&1 )
|
|
|
|
status=$?
|
|
|
|
test $status != 0 && printf "%s\n" "$output"
|
|
|
|
return $status
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
"$@"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2007-11-08 19:19:08 +01:00
|
|
|
move_to_original_branch () {
|
|
|
|
case "$head_name" in
|
|
|
|
refs/*)
|
|
|
|
message="rebase finished: $head_name onto $onto"
|
|
|
|
git update-ref -m "$message" \
|
|
|
|
$head_name $(git rev-parse HEAD) $orig_head &&
|
2011-05-27 22:16:14 +02:00
|
|
|
git symbolic-ref \
|
|
|
|
-m "rebase finished: returning to $head_name" \
|
|
|
|
HEAD $head_name ||
|
2016-06-17 22:20:58 +02:00
|
|
|
die "$(eval_gettext "Could not move back to \$head_name")"
|
2007-11-08 19:19:08 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2014-05-20 00:05:20 +02:00
|
|
|
apply_autostash () {
|
2013-05-12 13:56:41 +02:00
|
|
|
if test -f "$state_dir/autostash"
|
|
|
|
then
|
|
|
|
stash_sha1=$(cat "$state_dir/autostash")
|
2017-11-13 22:20:09 +01:00
|
|
|
if git stash apply $stash_sha1 >/dev/null 2>&1
|
2013-05-12 13:56:41 +02:00
|
|
|
then
|
2017-06-19 19:56:02 +02:00
|
|
|
echo "$(gettext 'Applied autostash.')" >&2
|
2013-05-12 13:56:41 +02:00
|
|
|
else
|
2013-06-15 15:13:26 +02:00
|
|
|
git stash store -m "autostash" -q $stash_sha1 ||
|
|
|
|
die "$(eval_gettext "Cannot store \$stash_sha1")"
|
2013-05-12 13:56:41 +02:00
|
|
|
gettext 'Applying autostash resulted in conflicts.
|
|
|
|
Your changes are safe in the stash.
|
2013-07-29 06:24:43 +02:00
|
|
|
You can run "git stash pop" or "git stash drop" at any time.
|
2017-06-19 19:56:02 +02:00
|
|
|
' >&2
|
2013-05-12 13:56:41 +02:00
|
|
|
fi
|
|
|
|
fi
|
2014-05-20 00:05:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
finish_rebase () {
|
2018-02-11 10:43:28 +01:00
|
|
|
rm -f "$(git rev-parse --git-path REBASE_HEAD)"
|
2014-05-20 00:05:20 +02:00
|
|
|
apply_autostash &&
|
2016-01-13 19:47:18 +01:00
|
|
|
{ git gc --auto || true; } &&
|
2013-05-12 13:56:41 +02:00
|
|
|
rm -rf "$state_dir"
|
|
|
|
}
|
|
|
|
|
2014-04-11 10:28:18 +02:00
|
|
|
run_specific_rebase () {
|
2008-09-29 22:28:57 +02:00
|
|
|
if [ "$interactive_rebase" = implied ]; then
|
|
|
|
GIT_EDITOR=:
|
|
|
|
export GIT_EDITOR
|
2012-05-24 15:57:26 +02:00
|
|
|
autosquash=
|
2008-09-29 22:28:57 +02:00
|
|
|
fi
|
2011-02-06 19:43:48 +01:00
|
|
|
. git-rebase--$type
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
|
|
|
|
if test -z "$preserve_merges"
|
|
|
|
then
|
|
|
|
git_rebase__$type
|
|
|
|
else
|
|
|
|
git_rebase__preserve_merges
|
|
|
|
fi
|
|
|
|
|
2013-05-12 13:56:37 +02:00
|
|
|
ret=$?
|
|
|
|
if test $ret -eq 0
|
|
|
|
then
|
2013-05-12 13:56:41 +02:00
|
|
|
finish_rebase
|
2014-05-20 00:05:20 +02:00
|
|
|
elif test $ret -eq 2 # special exit status for rebase -i
|
|
|
|
then
|
|
|
|
apply_autostash &&
|
|
|
|
rm -rf "$state_dir" &&
|
|
|
|
die "Nothing to do"
|
2013-05-12 13:56:37 +02:00
|
|
|
fi
|
|
|
|
exit $ret
|
2007-06-25 02:11:14 +02:00
|
|
|
}
|
|
|
|
|
2008-10-06 07:14:24 +02:00
|
|
|
run_pre_rebase_hook () {
|
2011-02-06 19:43:37 +01:00
|
|
|
if test -z "$ok_to_skip_pre_rebase" &&
|
2014-11-30 09:24:38 +01:00
|
|
|
test -x "$(git rev-parse --git-path hooks/pre-rebase)"
|
2008-10-06 07:14:24 +02:00
|
|
|
then
|
2014-11-30 09:24:38 +01:00
|
|
|
"$(git rev-parse --git-path hooks/pre-rebase)" ${1+"$@"} ||
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(gettext "The pre-rebase hook refused to rebase.")"
|
2008-10-06 07:14:24 +02:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2011-02-06 19:43:30 +01:00
|
|
|
test -f "$apply_dir"/applying &&
|
2017-11-20 16:26:52 +01:00
|
|
|
die "$(gettext "It looks like 'git am' is in progress. Cannot rebase.")"
|
2008-08-17 06:25:43 +02:00
|
|
|
|
2011-02-06 19:43:34 +01:00
|
|
|
if test -d "$apply_dir"
|
|
|
|
then
|
|
|
|
type=am
|
|
|
|
state_dir="$apply_dir"
|
|
|
|
elif test -d "$merge_dir"
|
|
|
|
then
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
if test -d "$merge_dir"/rewritten
|
|
|
|
then
|
|
|
|
type=preserve-merges
|
|
|
|
interactive_rebase=explicit
|
|
|
|
preserve_merges=t
|
|
|
|
elif test -f "$merge_dir"/interactive
|
2011-02-06 19:43:34 +01:00
|
|
|
then
|
|
|
|
type=interactive
|
|
|
|
interactive_rebase=explicit
|
|
|
|
else
|
|
|
|
type=merge
|
|
|
|
fi
|
|
|
|
state_dir="$merge_dir"
|
|
|
|
fi
|
|
|
|
test -n "$type" && in_progress=t
|
|
|
|
|
2011-02-06 19:43:36 +01:00
|
|
|
total_argc=$#
|
2007-09-23 22:42:08 +02:00
|
|
|
while test $# != 0
|
2006-02-14 23:42:05 +01:00
|
|
|
do
|
|
|
|
case "$1" in
|
2008-10-06 07:14:29 +02:00
|
|
|
--no-verify)
|
2011-02-06 19:43:37 +01:00
|
|
|
ok_to_skip_pre_rebase=yes
|
2008-10-06 07:14:29 +02:00
|
|
|
;;
|
2010-11-22 21:21:01 +01:00
|
|
|
--verify)
|
2011-02-06 19:43:37 +01:00
|
|
|
ok_to_skip_pre_rebase=
|
2010-11-22 21:21:01 +01:00
|
|
|
;;
|
2018-02-11 10:43:27 +01:00
|
|
|
--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
|
2011-03-01 02:59:26 +01:00
|
|
|
test $total_argc -eq 2 || usage
|
2011-02-06 19:43:35 +01:00
|
|
|
action=${1##--}
|
2006-04-26 16:49:38 +02:00
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--onto=*)
|
|
|
|
onto="${1#--onto=}"
|
2006-02-14 23:42:05 +01:00
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--exec=*)
|
|
|
|
cmd="${cmd}exec ${1#--exec=}${LF}"
|
2016-03-18 22:26:17 +01:00
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
2012-06-12 10:05:12 +02:00
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--interactive)
|
2011-02-06 19:43:39 +01:00
|
|
|
interactive_rebase=explicit
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--keep-empty)
|
2012-04-20 16:36:17 +02:00
|
|
|
keep_empty=yes
|
|
|
|
;;
|
2018-02-04 21:08:13 +01:00
|
|
|
--allow-empty-message)
|
|
|
|
allow_empty_message=--allow-empty-message
|
|
|
|
;;
|
2018-03-20 11:03:15 +01:00
|
|
|
--no-keep-empty)
|
|
|
|
keep_empty=
|
|
|
|
;;
|
rebase: introduce the --rebase-merges option
Once upon a time, this here developer thought: wouldn't it be nice if,
say, Git for Windows' patches on top of core Git could be represented as
a thicket of branches, and be rebased on top of core Git in order to
maintain a cherry-pick'able set of patch series?
The original attempt to answer this was: git rebase --preserve-merges.
However, that experiment was never intended as an interactive option,
and it only piggy-backed on git rebase --interactive because that
command's implementation looked already very, very familiar: it was
designed by the same person who designed --preserve-merges: yours truly.
Some time later, some other developer (I am looking at you, Andreas!
;-)) decided that it would be a good idea to allow --preserve-merges to
be combined with --interactive (with caveats!) and the Git maintainer
(well, the interim Git maintainer during Junio's absence, that is)
agreed, and that is when the glamor of the --preserve-merges design
started to fall apart rather quickly and unglamorously.
The reason? In --preserve-merges mode, the parents of a merge commit (or
for that matter, of *any* commit) were not stated explicitly, but were
*implied* by the commit name passed to the `pick` command.
This made it impossible, for example, to reorder commits. Not to mention
to move commits between branches or, deity forbid, to split topic branches
into two.
Alas, these shortcomings also prevented that mode (whose original
purpose was to serve Git for Windows' needs, with the additional hope
that it may be useful to others, too) from serving Git for Windows'
needs.
Five years later, when it became really untenable to have one unwieldy,
big hodge-podge patch series of partly related, partly unrelated patches
in Git for Windows that was rebased onto core Git's tags from time to
time (earning the undeserved wrath of the developer of the ill-fated
git-remote-hg series that first obsoleted Git for Windows' competing
approach, only to be abandoned without maintainer later) was really
untenable, the "Git garden shears" were born [*1*/*2*]: a script,
piggy-backing on top of the interactive rebase, that would first
determine the branch topology of the patches to be rebased, create a
pseudo todo list for further editing, transform the result into a real
todo list (making heavy use of the `exec` command to "implement" the
missing todo list commands) and finally recreate the patch series on
top of the new base commit.
That was in 2013. And it took about three weeks to come up with the
design and implement it as an out-of-tree script. Needless to say, the
implementation needed quite a few years to stabilize, all the while the
design itself proved itself sound.
With this patch, the goodness of the Git garden shears comes to `git
rebase -i` itself. Passing the `--rebase-merges` option will generate
a todo list that can be understood readily, and where it is obvious
how to reorder commits. New branches can be introduced by inserting
`label` commands and calling `merge <label>`. And once this mode will
have become stable and universally accepted, we can deprecate the design
mistake that was `--preserve-merges`.
Link *1*:
https://github.com/msysgit/msysgit/blob/master/share/msysGit/shears.sh
Link *2*:
https://github.com/git-for-windows/build-extra/blob/master/shears.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:04 +02:00
|
|
|
--rebase-merges)
|
|
|
|
rebase_merges=t
|
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
|
|
|
;;
|
rebase -i: introduce --rebase-merges=[no-]rebase-cousins
When running `git rebase --rebase-merges` non-interactively with an
ancestor of HEAD as <upstream> (or leaving the todo list unmodified),
we would ideally recreate the exact same commits as before the rebase.
However, if there are commits in the commit range <upstream>.. that do not
have <upstream> as direct ancestor (i.e. if `git log <upstream>..` would
show commits that are omitted by `git log --ancestry-path <upstream>..`),
this is currently not the case: we would turn them into commits that have
<upstream> as direct ancestor.
Let's illustrate that with a diagram:
C
/ \
A - B - E - F
\ /
D
Currently, after running `git rebase -i --rebase-merges B`, the new branch
structure would be (pay particular attention to the commit `D`):
--- C' --
/ \
A - B ------ E' - F'
\ /
D'
This is not really preserving the branch topology from before! The
reason is that the commit `D` does not have `B` as ancestor, and
therefore it gets rebased onto `B`.
This is unintuitive behavior. Even worse, when recreating branch
structure, most use cases would appear to want cousins *not* to be
rebased onto the new base commit. For example, Git for Windows (the
heaviest user of the Git garden shears, which served as the blueprint
for --rebase-merges) frequently merges branches from `next` early, and
these branches certainly do *not* want to be rebased. In the example
above, the desired outcome would look like this:
--- C' --
/ \
A - B ------ E' - F'
\ /
-- D' --
Let's introduce the term "cousins" for such commits ("D" in the
example), and let's not rebase them by default. For hypothetical
use cases where cousins *do* need to be rebased, `git rebase
--rebase=merges=rebase-cousins` needs to be used.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:40 +02:00
|
|
|
--rebase-merges=*)
|
|
|
|
rebase_merges=t
|
|
|
|
case "${1#*=}" in
|
|
|
|
rebase-cousins) rebase_cousins=t;;
|
|
|
|
no-rebase-cousins) rebase_cousins=;;
|
|
|
|
*) die "Unknown mode: $1";;
|
|
|
|
esac
|
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--preserve-merges)
|
2011-02-06 19:43:39 +01:00
|
|
|
preserve_merges=t
|
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
|
|
|
;;
|
|
|
|
--autosquash)
|
|
|
|
autosquash=t
|
|
|
|
;;
|
|
|
|
--no-autosquash)
|
|
|
|
autosquash=
|
|
|
|
;;
|
2013-12-10 00:16:16 +01:00
|
|
|
--fork-point)
|
|
|
|
fork_point=t
|
|
|
|
;;
|
|
|
|
--no-fork-point)
|
|
|
|
fork_point=
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--merge)
|
2006-06-21 12:04:41 +02:00
|
|
|
do_merge=t
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--strategy-option=*)
|
2018-06-27 17:48:04 +02:00
|
|
|
strategy_opts="$strategy_opts $(git rev-parse --sq-quote "--${1#--strategy-option=}" | sed -e s/^.//)"
|
2010-07-29 00:04:29 +02:00
|
|
|
do_merge=t
|
2011-02-06 19:43:38 +01:00
|
|
|
test -z "$strategy" && strategy=recursive
|
2010-07-29 00:04:29 +02:00
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--strategy=*)
|
|
|
|
strategy="${1#--strategy=}"
|
2006-06-21 12:04:41 +02:00
|
|
|
do_merge=t
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--no-stat)
|
2009-03-01 23:11:38 +01:00
|
|
|
diffstat=
|
|
|
|
;;
|
|
|
|
--stat)
|
|
|
|
diffstat=t
|
|
|
|
;;
|
2013-05-12 13:56:41 +02:00
|
|
|
--autostash)
|
|
|
|
autostash=true
|
|
|
|
;;
|
2015-09-11 00:30:51 +02:00
|
|
|
--no-autostash)
|
|
|
|
autostash=false
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--verbose)
|
2006-10-03 18:29:31 +02:00
|
|
|
verbose=t
|
2009-03-01 23:11:38 +01:00
|
|
|
diffstat=t
|
2009-06-17 00:33:01 +02:00
|
|
|
GIT_QUIET=
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--quiet)
|
2009-06-17 00:33:01 +02:00
|
|
|
GIT_QUIET=t
|
|
|
|
git_am_opt="$git_am_opt -q"
|
|
|
|
verbose=
|
|
|
|
diffstat=
|
2006-10-03 18:29:31 +02:00
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--whitespace=*)
|
|
|
|
git_am_opt="$git_am_opt --whitespace=${1#--whitespace=}"
|
|
|
|
case "${1#--whitespace=}" in
|
2011-03-01 02:59:26 +01:00
|
|
|
fix|strip)
|
2009-02-13 23:48:01 +01:00
|
|
|
force_rebase=t
|
|
|
|
;;
|
|
|
|
esac
|
2007-09-07 16:20:50 +02:00
|
|
|
;;
|
2009-08-04 13:16:49 +02:00
|
|
|
--ignore-whitespace)
|
|
|
|
git_am_opt="$git_am_opt $1"
|
|
|
|
;;
|
2018-03-20 12:10:55 +01:00
|
|
|
--signoff)
|
|
|
|
signoff=--signoff
|
|
|
|
;;
|
|
|
|
--no-signoff)
|
|
|
|
signoff=
|
|
|
|
;;
|
|
|
|
--committer-date-is-author-date|--ignore-date)
|
2009-03-18 21:53:49 +01:00
|
|
|
git_am_opt="$git_am_opt $1"
|
|
|
|
force_rebase=t
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
-C*)
|
|
|
|
git_am_opt="$git_am_opt $1"
|
2007-02-08 14:57:08 +01:00
|
|
|
;;
|
2009-01-05 18:35:16 +01:00
|
|
|
--root)
|
|
|
|
rebase_root=t
|
|
|
|
;;
|
2014-02-10 02:03:36 +01:00
|
|
|
--force-rebase|--no-ff)
|
2009-02-13 23:48:01 +01:00
|
|
|
force_rebase=t
|
|
|
|
;;
|
2009-12-04 09:20:48 +01:00
|
|
|
--rerere-autoupdate|--no-rerere-autoupdate)
|
|
|
|
allow_rerere_autoupdate="$1"
|
|
|
|
;;
|
2014-02-10 02:03:37 +01:00
|
|
|
--gpg-sign)
|
|
|
|
gpg_sign_opt=-S
|
|
|
|
;;
|
|
|
|
--gpg-sign=*)
|
|
|
|
gpg_sign_opt="-S${1#--gpg-sign=}"
|
|
|
|
;;
|
2011-03-01 02:59:26 +01:00
|
|
|
--)
|
|
|
|
shift
|
2006-02-14 23:42:05 +01:00
|
|
|
break
|
|
|
|
;;
|
2017-09-18 00:28:17 +02:00
|
|
|
*)
|
|
|
|
usage
|
|
|
|
;;
|
2006-02-14 23:42:05 +01:00
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
2009-02-18 14:44:02 +01:00
|
|
|
test $# -gt 2 && usage
|
2005-12-14 12:11:37 +01:00
|
|
|
|
2011-02-06 19:43:39 +01:00
|
|
|
if test -n "$action"
|
|
|
|
then
|
2012-07-25 16:53:08 +02:00
|
|
|
test -z "$in_progress" && die "$(gettext "No rebase in progress?")"
|
2011-02-06 19:43:52 +01:00
|
|
|
# Only interactive rebase uses detailed reflog messages
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
if test -n "$interactive_rebase" && test "$GIT_REFLOG_ACTION" = rebase
|
2011-02-06 19:43:52 +01:00
|
|
|
then
|
|
|
|
GIT_REFLOG_ACTION="rebase -i ($action)"
|
|
|
|
export GIT_REFLOG_ACTION
|
|
|
|
fi
|
2011-02-06 19:43:39 +01:00
|
|
|
fi
|
2011-02-06 19:43:35 +01:00
|
|
|
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
if test "$action" = "edit-todo" && test -z "$interactive_rebase"
|
2012-09-18 03:28:09 +02:00
|
|
|
then
|
|
|
|
die "$(gettext "The --edit-todo action can only be used during interactive rebase.")"
|
|
|
|
fi
|
|
|
|
|
2011-02-06 19:43:35 +01:00
|
|
|
case "$action" in
|
|
|
|
continue)
|
2011-02-06 19:43:52 +01:00
|
|
|
# Sanity check
|
|
|
|
git rev-parse --verify HEAD >/dev/null ||
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(gettext "Cannot read HEAD")"
|
2011-02-06 19:43:35 +01:00
|
|
|
git update-index --ignore-submodules --refresh &&
|
|
|
|
git diff-files --quiet --ignore-submodules || {
|
2012-07-25 16:53:08 +02:00
|
|
|
echo "$(gettext "You must edit all merge conflicts and then
|
|
|
|
mark them as resolved using git add")"
|
2011-02-06 19:43:35 +01:00
|
|
|
exit 1
|
|
|
|
}
|
2011-02-06 19:43:47 +01:00
|
|
|
read_basic_state
|
|
|
|
run_specific_rebase
|
2011-02-06 19:43:35 +01:00
|
|
|
;;
|
|
|
|
skip)
|
2011-02-06 19:43:51 +01:00
|
|
|
output git reset --hard HEAD || exit $?
|
2011-02-06 19:43:47 +01:00
|
|
|
read_basic_state
|
|
|
|
run_specific_rebase
|
2011-02-06 19:43:35 +01:00
|
|
|
;;
|
|
|
|
abort)
|
|
|
|
git rerere clear
|
2011-02-06 19:43:47 +01:00
|
|
|
read_basic_state
|
2011-02-06 19:43:35 +01:00
|
|
|
case "$head_name" in
|
|
|
|
refs/*)
|
2011-05-27 22:13:02 +02:00
|
|
|
git symbolic-ref -m "rebase: aborting" HEAD $head_name ||
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(eval_gettext "Could not move back to \$head_name")"
|
2011-02-06 19:43:35 +01:00
|
|
|
;;
|
|
|
|
esac
|
2011-02-06 19:43:51 +01:00
|
|
|
output git reset --hard $orig_head
|
2013-05-12 13:56:41 +02:00
|
|
|
finish_rebase
|
2011-02-06 19:43:35 +01:00
|
|
|
exit
|
|
|
|
;;
|
2016-11-12 03:00:41 +01:00
|
|
|
quit)
|
|
|
|
exec rm -rf "$state_dir"
|
|
|
|
;;
|
2012-09-18 03:28:09 +02:00
|
|
|
edit-todo)
|
|
|
|
run_specific_rebase
|
|
|
|
;;
|
2018-02-11 10:43:27 +01:00
|
|
|
show-current-patch)
|
|
|
|
run_specific_rebase
|
|
|
|
die "BUG: run_specific_rebase is not supposed to return here"
|
|
|
|
;;
|
2011-02-06 19:43:35 +01:00
|
|
|
esac
|
|
|
|
|
2011-02-06 19:43:34 +01:00
|
|
|
# Make sure no rebase is in progress
|
|
|
|
if test -n "$in_progress"
|
2005-11-28 22:00:31 +01:00
|
|
|
then
|
2012-07-25 16:53:08 +02:00
|
|
|
state_dir_base=${state_dir##*/}
|
|
|
|
cmd_live_rebase="git rebase (--continue | --abort | --skip)"
|
|
|
|
cmd_clear_stale_rebase="rm -fr \"$state_dir\""
|
|
|
|
die "
|
|
|
|
$(eval_gettext 'It seems that there is already a $state_dir_base directory, and
|
2012-08-01 19:09:09 +02:00
|
|
|
I wonder if you are in the middle of another rebase. If that is the
|
2011-02-06 19:43:34 +01:00
|
|
|
case, please try
|
2012-07-25 16:53:08 +02:00
|
|
|
$cmd_live_rebase
|
2011-02-06 19:43:34 +01:00
|
|
|
If that is not the case, please
|
2012-07-25 16:53:08 +02:00
|
|
|
$cmd_clear_stale_rebase
|
2008-08-17 06:25:43 +02:00
|
|
|
and run me again. I am stopping in case you still have something
|
2012-07-25 16:53:08 +02:00
|
|
|
valuable there.')"
|
2005-11-28 22:00:31 +01:00
|
|
|
fi
|
|
|
|
|
2012-06-26 23:55:23 +02:00
|
|
|
if test -n "$rebase_root" && test -z "$onto"
|
|
|
|
then
|
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
|
|
|
fi
|
|
|
|
|
2018-03-20 12:10:57 +01:00
|
|
|
if test -n "$keep_empty"
|
|
|
|
then
|
|
|
|
test -z "$interactive_rebase" && interactive_rebase=implied
|
2012-06-26 23:55:23 +02:00
|
|
|
fi
|
|
|
|
|
2011-02-06 19:43:39 +01:00
|
|
|
if test -n "$interactive_rebase"
|
|
|
|
then
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
if test -z "$preserve_merges"
|
|
|
|
then
|
|
|
|
type=interactive
|
|
|
|
else
|
|
|
|
type=preserve-merges
|
|
|
|
fi
|
|
|
|
|
2011-02-06 19:43:39 +01:00
|
|
|
state_dir="$merge_dir"
|
|
|
|
elif test -n "$do_merge"
|
|
|
|
then
|
|
|
|
type=merge
|
|
|
|
state_dir="$merge_dir"
|
|
|
|
else
|
|
|
|
type=am
|
|
|
|
state_dir="$apply_dir"
|
|
|
|
fi
|
|
|
|
|
2017-08-10 20:32:56 +02:00
|
|
|
if test -t 2 && test -z "$GIT_QUIET"
|
|
|
|
then
|
|
|
|
git_format_patch_opt="$git_format_patch_opt --progress"
|
|
|
|
fi
|
|
|
|
|
git-rebase: error out when incompatible options passed
git rebase has three different types: am, merge, and interactive, all of
which are implemented in terms of separate scripts. am builds on git-am,
merge builds on git-merge-recursive, and interactive builds on
git-cherry-pick. We make use of features in those lower-level commands in
the different rebase types, but those features don't exist in all of the
lower level commands so we have a range of incompatibilities. Previously,
we just accepted nearly any argument and silently ignored whichever ones
weren't implemented for the type of rebase specified. Change this so the
incompatibilities are documented, included in the testsuite, and tested
for at runtime with an appropriate error message shown.
Some exceptions I left out:
* --merge and --interactive are technically incompatible since they are
supposed to run different underlying scripts, but with a few small
changes, --interactive can do everything that --merge can. In fact,
I'll shortly be sending another patch to remove git-rebase--merge and
reimplement it on top of git-rebase--interactive.
* One could argue that --interactive and --quiet are incompatible since
--interactive doesn't implement a --quiet mode (perhaps since
cherry-pick itself does not implement one). However, the interactive
mode is more quiet than the other modes in general with progress
messages, so one could argue that it's already quiet.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-27 09:23:14 +02:00
|
|
|
if test -n "$git_am_opt"; then
|
|
|
|
incompatible_opts=$(echo " $git_am_opt " | \
|
|
|
|
sed -e 's/ -q / /g' -e 's/^ \(.*\) $/\1/')
|
|
|
|
if test -n "$interactive_rebase"
|
|
|
|
then
|
|
|
|
if test -n "$incompatible_opts"
|
|
|
|
then
|
|
|
|
die "$(gettext "error: cannot combine interactive options (--interactive, --exec, --rebase-merges, --preserve-merges, --keep-empty, --root + --onto) with am options ($incompatible_opts)")"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
if test -n "$do_merge"; then
|
|
|
|
if test -n "$incompatible_opts"
|
|
|
|
then
|
|
|
|
die "$(gettext "error: cannot combine merge options (--merge, --strategy, --strategy-option) with am options ($incompatible_opts)")"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2018-03-20 12:10:55 +01:00
|
|
|
if test -n "$signoff"
|
|
|
|
then
|
2018-03-20 12:10:56 +01:00
|
|
|
test -n "$preserve_merges" &&
|
|
|
|
die "$(gettext "error: cannot combine '--signoff' with '--preserve-merges'")"
|
2018-03-20 12:10:55 +01:00
|
|
|
git_am_opt="$git_am_opt $signoff"
|
|
|
|
force_rebase=t
|
|
|
|
fi
|
|
|
|
|
git-rebase: error out when incompatible options passed
git rebase has three different types: am, merge, and interactive, all of
which are implemented in terms of separate scripts. am builds on git-am,
merge builds on git-merge-recursive, and interactive builds on
git-cherry-pick. We make use of features in those lower-level commands in
the different rebase types, but those features don't exist in all of the
lower level commands so we have a range of incompatibilities. Previously,
we just accepted nearly any argument and silently ignored whichever ones
weren't implemented for the type of rebase specified. Change this so the
incompatibilities are documented, included in the testsuite, and tested
for at runtime with an appropriate error message shown.
Some exceptions I left out:
* --merge and --interactive are technically incompatible since they are
supposed to run different underlying scripts, but with a few small
changes, --interactive can do everything that --merge can. In fact,
I'll shortly be sending another patch to remove git-rebase--merge and
reimplement it on top of git-rebase--interactive.
* One could argue that --interactive and --quiet are incompatible since
--interactive doesn't implement a --quiet mode (perhaps since
cherry-pick itself does not implement one). However, the interactive
mode is more quiet than the other modes in general with progress
messages, so one could argue that it's already quiet.
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-06-27 09:23:14 +02:00
|
|
|
if test -n "$preserve_merges"
|
|
|
|
then
|
|
|
|
# Note: incompatibility with --signoff handled in signoff block above
|
|
|
|
# Note: incompatibility with --interactive is just a strong warning;
|
|
|
|
# git-rebase.txt caveats with "unless you know what you are doing"
|
|
|
|
test -n "$rebase_merges" &&
|
|
|
|
die "$(gettext "error: cannot combine '--preserve_merges' with '--rebase-merges'")"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if test -n "$rebase_merges"
|
|
|
|
then
|
|
|
|
test -n "$strategy_opts" &&
|
|
|
|
die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy-option'")"
|
|
|
|
test -n "$strategy" &&
|
|
|
|
die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy'")"
|
|
|
|
fi
|
|
|
|
|
2009-01-05 18:35:16 +01:00
|
|
|
if test -z "$rebase_root"
|
|
|
|
then
|
2011-02-10 02:54:02 +01:00
|
|
|
case "$#" in
|
|
|
|
0)
|
|
|
|
if ! upstream_name=$(git rev-parse --symbolic-full-name \
|
|
|
|
--verify -q @{upstream} 2>/dev/null)
|
|
|
|
then
|
|
|
|
. git-parse-remote
|
|
|
|
error_on_missing_default_upstream "rebase" "rebase" \
|
2016-06-17 22:20:59 +02:00
|
|
|
"against" "git rebase $(gettext '<branch>')"
|
2011-02-10 02:54:02 +01:00
|
|
|
fi
|
2013-12-10 00:16:16 +01:00
|
|
|
|
|
|
|
test "$fork_point" = auto && fork_point=t
|
2011-02-10 02:54:02 +01:00
|
|
|
;;
|
|
|
|
*) upstream_name="$1"
|
2014-03-19 12:02:15 +01:00
|
|
|
if test "$upstream_name" = "-"
|
|
|
|
then
|
|
|
|
upstream_name="@{-1}"
|
|
|
|
fi
|
2011-02-10 02:54:02 +01:00
|
|
|
shift
|
|
|
|
;;
|
|
|
|
esac
|
2013-06-14 15:17:52 +02:00
|
|
|
upstream=$(peel_committish "${upstream_name}") ||
|
2017-12-16 10:03:18 +01:00
|
|
|
die "$(eval_gettext "invalid upstream '\$upstream_name'")"
|
2009-01-05 18:35:16 +01:00
|
|
|
upstream_arg="$upstream_name"
|
|
|
|
else
|
2012-06-26 23:55:23 +02:00
|
|
|
if test -z "$onto"
|
|
|
|
then
|
2014-04-23 15:44:00 +02:00
|
|
|
empty_tree=$(git hash-object -t tree /dev/null)
|
|
|
|
onto=$(git commit-tree $empty_tree </dev/null)
|
2012-06-26 23:55:23 +02:00
|
|
|
squash_onto="$onto"
|
|
|
|
fi
|
2009-01-05 18:35:16 +01:00
|
|
|
unset upstream_name
|
|
|
|
unset upstream
|
2012-06-26 16:51:55 +02:00
|
|
|
test $# -gt 1 && usage
|
2011-02-06 19:43:48 +01:00
|
|
|
upstream_arg=--root
|
2009-01-05 18:35:16 +01:00
|
|
|
fi
|
2005-12-15 00:36:35 +01:00
|
|
|
|
2007-03-22 10:54:59 +01:00
|
|
|
# Make sure the branch to rebase onto is valid.
|
2011-02-06 19:43:37 +01:00
|
|
|
onto_name=${onto-"$upstream_name"}
|
2010-01-07 12:05:02 +01:00
|
|
|
case "$onto_name" in
|
|
|
|
*...*)
|
|
|
|
if left=${onto_name%...*} right=${onto_name#*...} &&
|
|
|
|
onto=$(git merge-base --all ${left:-HEAD} ${right:-HEAD})
|
|
|
|
then
|
|
|
|
case "$onto" in
|
|
|
|
?*"$LF"?*)
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(eval_gettext "\$onto_name: there are more than one merge bases")"
|
2010-01-07 12:05:02 +01:00
|
|
|
;;
|
|
|
|
'')
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(eval_gettext "\$onto_name: there is no merge base")"
|
2010-01-07 12:05:02 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
else
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(eval_gettext "\$onto_name: there is no merge base")"
|
2010-01-07 12:05:02 +01:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
*)
|
2013-06-14 15:17:52 +02:00
|
|
|
onto=$(peel_committish "$onto_name") ||
|
2012-07-25 16:53:08 +02:00
|
|
|
die "$(eval_gettext "Does not point to a valid commit: \$onto_name")"
|
2010-01-07 12:05:02 +01:00
|
|
|
;;
|
|
|
|
esac
|
2007-03-22 10:54:59 +01:00
|
|
|
|
2008-03-15 21:17:42 +01:00
|
|
|
# If the branch to rebase is given, that is the branch we will rebase
|
2017-12-16 10:03:17 +01:00
|
|
|
# $branch_name -- branch/commit being rebased, or HEAD (already detached)
|
2008-03-15 21:17:42 +01:00
|
|
|
# $orig_head -- commit object name of tip of the branch before rebasing
|
|
|
|
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
|
|
|
|
switch_to=
|
2005-06-25 11:23:43 +02:00
|
|
|
case "$#" in
|
2009-01-05 18:35:16 +01:00
|
|
|
1)
|
2008-03-15 21:17:42 +01:00
|
|
|
# Is it "rebase other $branchname" or "rebase other $commit"?
|
2009-01-05 18:35:16 +01:00
|
|
|
branch_name="$1"
|
|
|
|
switch_to="$1"
|
2008-03-15 21:17:42 +01:00
|
|
|
|
2017-12-16 10:03:17 +01:00
|
|
|
# Is it a local branch?
|
|
|
|
if git show-ref --verify --quiet -- "refs/heads/$branch_name" &&
|
|
|
|
orig_head=$(git rev-parse -q --verify "refs/heads/$branch_name")
|
2008-03-15 21:17:42 +01:00
|
|
|
then
|
2017-12-16 10:03:17 +01:00
|
|
|
head_name="refs/heads/$branch_name"
|
|
|
|
# If not is it a valid ref (branch or commit)?
|
|
|
|
elif orig_head=$(git rev-parse -q --verify "$branch_name")
|
2008-03-15 21:17:42 +01:00
|
|
|
then
|
|
|
|
head_name="detached HEAD"
|
2017-12-16 10:03:17 +01:00
|
|
|
|
2008-03-15 21:17:42 +01:00
|
|
|
else
|
2017-12-16 10:03:18 +01:00
|
|
|
die "$(eval_gettext "fatal: no such branch/commit '\$branch_name'")"
|
2008-03-15 21:17:42 +01:00
|
|
|
fi
|
2006-02-14 23:42:05 +01:00
|
|
|
;;
|
2012-06-26 16:51:55 +02:00
|
|
|
0)
|
2008-03-15 21:17:42 +01:00
|
|
|
# Do not need to switch branches, we are already on it.
|
2014-04-23 15:44:00 +02:00
|
|
|
if branch_name=$(git symbolic-ref -q HEAD)
|
2007-01-21 04:11:29 +01:00
|
|
|
then
|
2008-03-15 21:17:42 +01:00
|
|
|
head_name=$branch_name
|
2014-04-23 15:44:00 +02:00
|
|
|
branch_name=$(expr "z$branch_name" : 'zrefs/heads/\(.*\)')
|
2007-01-21 04:11:29 +01:00
|
|
|
else
|
2008-03-15 21:17:42 +01:00
|
|
|
head_name="detached HEAD"
|
2017-12-16 10:03:17 +01:00
|
|
|
branch_name=HEAD
|
2007-01-21 04:11:29 +01:00
|
|
|
fi
|
2013-04-24 00:51:14 +02:00
|
|
|
orig_head=$(git rev-parse --verify HEAD) || exit
|
2006-02-14 23:42:05 +01:00
|
|
|
;;
|
2012-06-26 16:51:55 +02:00
|
|
|
*)
|
|
|
|
die "BUG: unexpected number of arguments left to parse"
|
|
|
|
;;
|
2005-06-25 11:23:43 +02:00
|
|
|
esac
|
|
|
|
|
2013-12-10 00:16:16 +01:00
|
|
|
if test "$fork_point" = t
|
|
|
|
then
|
2014-01-09 20:47:34 +01:00
|
|
|
new_upstream=$(git merge-base --fork-point "$upstream_name" \
|
|
|
|
"${switch_to:-HEAD}")
|
2013-12-10 00:16:16 +01:00
|
|
|
if test -n "$new_upstream"
|
|
|
|
then
|
2014-07-16 21:23:49 +02:00
|
|
|
restrict_revision=$new_upstream
|
2013-12-10 00:16:16 +01:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2013-05-12 13:56:41 +02:00
|
|
|
if test "$autostash" = true && ! (require_clean_work_tree) 2>/dev/null
|
|
|
|
then
|
|
|
|
stash_sha1=$(git stash create "autostash") ||
|
|
|
|
die "$(gettext 'Cannot autostash')"
|
|
|
|
|
|
|
|
mkdir -p "$state_dir" &&
|
|
|
|
echo $stash_sha1 >"$state_dir/autostash" &&
|
|
|
|
stash_abbrev=$(git rev-parse --short $stash_sha1) &&
|
|
|
|
echo "$(eval_gettext 'Created autostash: $stash_abbrev')" &&
|
|
|
|
git reset --hard
|
|
|
|
fi
|
|
|
|
|
2012-07-25 16:53:08 +02:00
|
|
|
require_clean_work_tree "rebase" "$(gettext "Please commit or stash them.")"
|
2011-02-06 19:43:41 +01:00
|
|
|
|
2011-02-06 19:43:46 +01:00
|
|
|
# Now we are rebasing commits $upstream..$orig_head (or with --root,
|
|
|
|
# everything leading up to $orig_head) on top of $onto
|
2006-02-14 23:42:05 +01:00
|
|
|
|
2007-07-04 22:09:10 +02:00
|
|
|
# Check if we are already based on $onto with linear history,
|
2011-02-06 19:43:44 +01:00
|
|
|
# but this should be done only when upstream and onto are the same
|
|
|
|
# and if this is not an interactive rebase.
|
2011-02-06 19:43:46 +01:00
|
|
|
mb=$(git merge-base "$onto" "$orig_head")
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
if test -z "$interactive_rebase" && test "$upstream" = "$onto" &&
|
2014-07-16 21:23:49 +02:00
|
|
|
test "$mb" = "$onto" && test -z "$restrict_revision" &&
|
2007-07-04 22:09:10 +02:00
|
|
|
# linear history?
|
2011-02-06 19:43:46 +01:00
|
|
|
! (git rev-list --parents "$onto".."$orig_head" | sane_grep " .* ") > /dev/null
|
2005-11-28 22:00:31 +01:00
|
|
|
then
|
2009-02-13 23:48:01 +01:00
|
|
|
if test -z "$force_rebase"
|
|
|
|
then
|
|
|
|
# Lazily switch to the target branch if needed...
|
2013-06-16 10:45:12 +02:00
|
|
|
test -z "$switch_to" ||
|
|
|
|
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to" \
|
rebase: silence "git checkout" for noop rebase
When the branch to be rebased is already up to date, we
"git checkout" the branch, print an "up to date" message,
and end the rebase early. However, our checkout may print
"Switched to branch 'foo'" or "Already on 'foo'", even if
the user has asked for "--quiet".
We should avoid printing these messages at all, "--quiet" or
no. Since the rebase is a noop, this checkout can be seen as
optimizing out these other two checkout operations (that
happen in a real rebase):
1. Moving to the detached HEAD to start the rebase; we
always feed "-q" to checkout there, and instead rely on
our own custom message (which respects --quiet).
2. Finishing a rebase, where we move to the final branch.
Here we actually use update-ref rather than
git-checkout, and produce no messages.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-04-28 07:17:37 +02:00
|
|
|
git checkout -q "$switch_to" --
|
2017-12-16 10:03:19 +01:00
|
|
|
if test "$branch_name" = "HEAD" &&
|
|
|
|
! git symbolic-ref -q HEAD
|
|
|
|
then
|
|
|
|
say "$(eval_gettext "HEAD is up to date.")"
|
|
|
|
else
|
|
|
|
say "$(eval_gettext "Current branch \$branch_name is up to date.")"
|
|
|
|
fi
|
2013-06-13 18:06:13 +02:00
|
|
|
finish_rebase
|
2009-02-13 23:48:01 +01:00
|
|
|
exit 0
|
|
|
|
else
|
2017-12-16 10:03:19 +01:00
|
|
|
if test "$branch_name" = "HEAD" &&
|
|
|
|
! git symbolic-ref -q HEAD
|
|
|
|
then
|
|
|
|
say "$(eval_gettext "HEAD is up to date, rebase forced.")"
|
|
|
|
else
|
|
|
|
say "$(eval_gettext "Current branch \$branch_name is up to date, rebase forced.")"
|
|
|
|
fi
|
2009-02-13 23:48:01 +01:00
|
|
|
fi
|
2005-11-28 22:00:31 +01:00
|
|
|
fi
|
|
|
|
|
2011-02-06 19:43:41 +01:00
|
|
|
# If a hook exists, give it a chance to interrupt
|
|
|
|
run_pre_rebase_hook "$upstream_arg" "$@"
|
|
|
|
|
2009-03-01 23:11:38 +01:00
|
|
|
if test -n "$diffstat"
|
|
|
|
then
|
|
|
|
if test -n "$verbose"
|
|
|
|
then
|
2012-07-25 16:53:08 +02:00
|
|
|
echo "$(eval_gettext "Changes from \$mb to \$onto:")"
|
2009-03-01 23:11:38 +01:00
|
|
|
fi
|
|
|
|
# We want color (if set), but no pager
|
|
|
|
GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
|
|
|
|
fi
|
|
|
|
|
rebase: use the new git-rebase--preserve-merges.sh
Create a new type of rebase, "preserve-merges", used when rebase is
called with -p.
Before that, the type for preserve-merges was "interactive", and some
places of this script compared $type to "interactive". Instead, the code
now checks if $interactive_rebase is empty or not, as it is set to
"explicit" when calling an interactive rebase (and, possibly, one of its
submodes), and "implied" when calling one of its
submodes (eg. preserve-merges) *without* interactive rebase.
It also detects the presence of the directory "$merge_dir"/rewritten
left by the preserve-merges script when calling rebase --continue,
--skip, etc., and, if it exists, sets the rebase mode to
preserve-merges. In this case, interactive_rebase is set to "explicit",
as "implied" would break some tests.
Signed-off-by: Alban Gruin <alban.gruin@gmail.com>
2018-05-28 14:34:21 +02:00
|
|
|
test -n "$interactive_rebase" && run_specific_rebase
|
2011-02-06 19:43:45 +01:00
|
|
|
|
|
|
|
# Detach HEAD and reset the tree
|
2012-07-25 16:53:08 +02:00
|
|
|
say "$(gettext "First, rewinding head to replay your work on top of it...")"
|
2013-06-16 10:45:12 +02:00
|
|
|
|
|
|
|
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name" \
|
|
|
|
git checkout -q "$onto^0" || die "could not detach HEAD"
|
2011-02-06 19:43:46 +01:00
|
|
|
git update-ref ORIG_HEAD $orig_head
|
2011-02-06 19:43:45 +01:00
|
|
|
|
2006-02-14 23:42:05 +01:00
|
|
|
# If the $onto is a proper descendant of the tip of the branch, then
|
2009-10-24 10:31:32 +02:00
|
|
|
# we just fast-forwarded.
|
2011-02-06 19:43:46 +01:00
|
|
|
if test "$mb" = "$orig_head"
|
2005-12-15 00:36:35 +01:00
|
|
|
then
|
2012-07-25 16:53:08 +02:00
|
|
|
say "$(eval_gettext "Fast-forwarded \$branch_name to \$onto_name.")"
|
2007-11-08 19:19:08 +01:00
|
|
|
move_to_original_branch
|
2013-06-13 18:06:12 +02:00
|
|
|
finish_rebase
|
2005-12-15 00:36:35 +01:00
|
|
|
exit 0
|
|
|
|
fi
|
|
|
|
|
2009-01-05 18:35:16 +01:00
|
|
|
if test -n "$rebase_root"
|
|
|
|
then
|
|
|
|
revisions="$onto..$orig_head"
|
|
|
|
else
|
2014-07-16 21:23:49 +02:00
|
|
|
revisions="${restrict_revision-$upstream}..$orig_head"
|
2009-01-05 18:35:16 +01:00
|
|
|
fi
|
|
|
|
|
2011-02-06 19:43:47 +01:00
|
|
|
run_specific_rebase
|