Skip to content

Commit df5df20

Browse files
arachsysgitster
authored andcommitted
rebase -i: support --root without --onto
Allow --root to be specified to rebase -i without --onto, making it possible to edit and re-order all commits right back to the root(s). If there is a conflict to be resolved when applying the first change, the user will expect a sane index and working tree to get sensible behaviour from git-diff and friends, so create a sentinel commit with an empty tree to rebase onto. Automatically squash the sentinel with any commits rebased directly onto it, so they end up as root commits in their own right and retain their authorship and commit message. Implicitly use rebase -i for non-interactive rebase of --root without an --onto argument now that rebase -i can correctly do this. Signed-off-by: Chris Webb <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bc9e7dd commit df5df20

File tree

3 files changed

+43
-12
lines changed

3 files changed

+43
-12
lines changed

Documentation/git-rebase.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ SYNOPSIS
1010
[verse]
1111
'git rebase' [-i | --interactive] [options] [--onto <newbase>]
1212
[<upstream>] [<branch>]
13-
'git rebase' [-i | --interactive] [options] --onto <newbase>
13+
'git rebase' [-i | --interactive] [options] [--onto <newbase>]
1414
--root [<branch>]
1515
'git rebase' --continue | --skip | --abort
1616

@@ -348,10 +348,11 @@ idea unless you know what you are doing (see BUGS below).
348348
--root::
349349
Rebase all commits reachable from <branch>, instead of
350350
limiting them with an <upstream>. This allows you to rebase
351-
the root commit(s) on a branch. Must be used with --onto, and
351+
the root commit(s) on a branch. When used with --onto, it
352352
will skip changes already contained in <newbase> (instead of
353-
<upstream>). When used together with --preserve-merges, 'all'
354-
root commits will be rewritten to have <newbase> as parent
353+
<upstream>) whereas without --onto it will operate on every change.
354+
When used together with both --onto and --preserve-merges,
355+
'all' root commits will be rewritten to have <newbase> as parent
355356
instead.
356357

357358
--autosquash::

git-rebase--interactive.sh

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,29 @@ record_in_rewritten() {
417417
esac
418418
}
419419

420+
do_pick () {
421+
if test "$(git rev-parse HEAD)" = "$squash_onto"
422+
then
423+
# Set the correct commit message and author info on the
424+
# sentinel root before cherry-picking the original changes
425+
# without committing (-n). Finally, update the sentinel again
426+
# to include these changes. If the cherry-pick results in a
427+
# conflict, this means our behaviour is similar to a standard
428+
# failed cherry-pick during rebase, with a dirty index to
429+
# resolve before manually running git commit --amend then git
430+
# rebase --continue.
431+
git commit --allow-empty --allow-empty-message --amend \
432+
--no-post-rewrite -n -q -C $1 &&
433+
pick_one -n $1 &&
434+
git commit --allow-empty --allow-empty-message \
435+
--amend --no-post-rewrite -n -q -C $1 ||
436+
die_with_patch $1 "Could not apply $1... $2"
437+
else
438+
pick_one $1 ||
439+
die_with_patch $1 "Could not apply $1... $2"
440+
fi
441+
}
442+
420443
do_next () {
421444
rm -f "$msg" "$author_script" "$amend" || exit
422445
read -r command sha1 rest < "$todo"
@@ -428,16 +451,14 @@ do_next () {
428451
comment_for_reflog pick
429452

430453
mark_action_done
431-
pick_one $sha1 ||
432-
die_with_patch $sha1 "Could not apply $sha1... $rest"
454+
do_pick $sha1 "$rest"
433455
record_in_rewritten $sha1
434456
;;
435457
reword|r)
436458
comment_for_reflog reword
437459

438460
mark_action_done
439-
pick_one $sha1 ||
440-
die_with_patch $sha1 "Could not apply $sha1... $rest"
461+
do_pick $sha1 "$rest"
441462
git commit --amend --no-post-rewrite || {
442463
warn "Could not amend commit after successfully picking $sha1... $rest"
443464
warn "This is most likely due to an empty commit message, or the pre-commit hook"
@@ -451,8 +472,7 @@ do_next () {
451472
comment_for_reflog edit
452473

453474
mark_action_done
454-
pick_one $sha1 ||
455-
die_with_patch $sha1 "Could not apply $sha1... $rest"
475+
do_pick $sha1 "$rest"
456476
warn "Stopped at $sha1... $rest"
457477
exit_with_patch $sha1 0
458478
;;

git-rebase.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ SUBDIRECTORY_OK=Yes
3131
OPTIONS_KEEPDASHDASH=
3232
OPTIONS_SPEC="\
3333
git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]
34-
git rebase [-i] [options] --onto <newbase> --root [<branch>]
34+
git rebase [-i] [options] [--onto <newbase>] --root [<branch>]
3535
git-rebase [-i] --continue | --abort | --skip
3636
--
3737
Available options are
@@ -364,6 +364,11 @@ and run me again. I am stopping in case you still have something
364364
valuable there.'
365365
fi
366366

367+
if test -n "$rebase_root" && test -z "$onto"
368+
then
369+
test -z "$interactive_rebase" && interactive_rebase=implied
370+
fi
371+
367372
if test -n "$interactive_rebase"
368373
then
369374
type=interactive
@@ -397,7 +402,12 @@ then
397402
die "invalid upstream $upstream_name"
398403
upstream_arg="$upstream_name"
399404
else
400-
test -z "$onto" && die "You must specify --onto when using --root"
405+
if test -z "$onto"
406+
then
407+
empty_tree=`git hash-object -t tree /dev/null`
408+
onto=`git commit-tree $empty_tree </dev/null`
409+
squash_onto="$onto"
410+
fi
401411
unset upstream_name
402412
unset upstream
403413
upstream_arg=--root

0 commit comments

Comments
 (0)