* [PATCH 0/3] rebase --root
@ 2008-12-29 16:45 Thomas Rast
[not found] ` <cover.1230569041.git.trast@student.ethz.ch>
0 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2008-12-29 16:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Inspired by f95ebf7 (Allow cherry-picking root commits, 2008-07-04),
this teaches git rebase to rebase everything up to the root commit(s).
The main use-case for this is if you hack on new history, then later
notice that you want to unroll the commits "on" a git-svn branch to
dcommit them separately. (If you just want to squash them, a merge
will do fine.)
Note that --root (in both modes) requires --onto; you cannot rebase
"onto nothing" to edit the root commit. Such an option --onto-nothing
might be a worthwile feature however, since it would also allow
"detaching" a set of commits from their parent history.
BTW, while hacking this I noticed that there are two different tests
t3409:
t3409-rebase-hook.sh
t3409-rebase-preserve-merges.sh
Is this okay, or should one of them be renamed?
Thomas Rast (3):
rebase: learn to rebase root commit
rebase -i: learn to rebase root commit
rebase: update documentation for --root
Documentation/git-rebase.txt | 17 +++++++---
git-rebase--interactive.sh | 53 +++++++++++++++++++++++++--------
git-rebase.sh | 51 ++++++++++++++++++++++----------
t/t3412-rebase-root.sh | 66 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 153 insertions(+), 34 deletions(-)
create mode 100755 t/t3412-rebase-root.sh
^ permalink raw reply [flat|nested] 27+ messages in thread
* rebase: learn to rebase root commit
[not found] ` <cover.1230569041.git.trast@student.ethz.ch>
@ 2008-12-29 16:45 ` Thomas Rast
2008-12-29 16:45 ` rebase -i: " Thomas Rast
2008-12-29 16:45 ` rebase: update documentation for --root Thomas Rast
2 siblings, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2008-12-29 16:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>.
The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN. You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection. This previously had to be done by
cherry-picking the root commit manually.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
git-rebase.sh | 51 ++++++++++++++++++++++++++++++++--------------
t/t3412-rebase-root.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 16 deletions(-)
create mode 100755 t/t3412-rebase-root.sh
diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..89de3c4 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
git_am_opt=
+rebase_root=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
-C*)
git_am_opt="$git_am_opt $1"
;;
+ --root)
+ rebase_root=t
+ ;;
-*)
usage
;;
@@ -344,17 +348,23 @@ case "$diff" in
;;
esac
+if test -z "$rebase_root"; then
# The upstream head must be given. Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ upstream_name="$1"
+ shift
+ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ die "invalid upstream $upstream_name"
+fi
+
+test ! -z "$rebase_root" -a -z "$newbase" &&
+ die "--root must be used with --onto"
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook ${upstream_name+"$upstream_name"} "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +372,16 @@ run_pre_rebase_hook ${1+"$@"}
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
-2)
+1)
# Is it "rebase other $branchname" or "rebase other $commit"?
- branch_name="$2"
- switch_to="$2"
+ branch_name="$1"
+ switch_to="$1"
- if git show-ref --verify --quiet -- "refs/heads/$2" &&
- branch=$(git rev-parse -q --verify "refs/heads/$2")
+ if git show-ref --verify --quiet -- "refs/heads/$1" &&
+ branch=$(git rev-parse -q --verify "refs/heads/$1")
then
- head_name="refs/heads/$2"
- elif branch=$(git rev-parse -q --verify "$2")
+ head_name="refs/heads/$1"
+ elif branch=$(git rev-parse -q --verify "$1")
then
head_name="detached HEAD"
else
@@ -393,7 +403,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or simply $branch
+# with --root) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -429,10 +440,18 @@ then
exit 0
fi
+if test ! -z "$rebase_root"; then
+ revisions="$orig_head"
+ fp_flag="--root"
+else
+ revisions="$upstream..$orig_head"
+ fp_flag="--ignore-if-in-upstream"
+fi
+
if test -z "$do_merge"
then
- git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- "$upstream..$orig_head" |
+ git format-patch -k --stdout --full-index "$fp_flag" \
+ "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -455,7 +474,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..63ec5e6
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1 &&
+ echo 2 > A &&
+ git add A &&
+ git commit -m 2 &&
+ git symbolic-ref HEAD refs/heads/other &&
+ rm .git/index &&
+ rm A &&
+ echo 3 > B &&
+ git add B &&
+ git commit -m 3 &&
+ echo 4 > B &&
+ git add B &&
+ git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+ test_must_fail git rebase --root
+'
+
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+ git checkout -b work &&
+ git rebase --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased &&
+ test_cmp expect rebased
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+ git branch work2 other &&
+ git rebase --root --onto master work2 &&
+ git log --pretty=tformat:"%s" > rebased2 &&
+ test_cmp expect rebased2
+'
+
+test_done
--
1.6.1.1.g4c1d9.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* rebase -i: learn to rebase root commit
[not found] ` <cover.1230569041.git.trast@student.ethz.ch>
2008-12-29 16:45 ` rebase: learn to rebase root commit Thomas Rast
@ 2008-12-29 16:45 ` Thomas Rast
2008-12-29 21:49 ` Thomas Rast
2008-12-29 16:45 ` rebase: update documentation for --root Thomas Rast
2 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2008-12-29 16:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Teach git-rebase -i a new option --root, which instructs it to rebase
the entire history leading up to <branch>. This is mainly for
symmetry with ordinary git-rebase; it cannot be used to edit the root
commit in-place (it requires --onto).
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
git-rebase--interactive.sh | 53 +++++++++++++++++++++++++++++++++----------
t/t3412-rebase-root.sh | 14 +++++++++++
2 files changed, 54 insertions(+), 13 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c8b0861..f29b5ee 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -27,6 +27,7 @@ continue continue rebasing process
abort abort rebasing process and restore original branch
skip skip current patch and continue rebasing process
no-verify override pre-rebase hook from stopping the operation
+root rebase all reachable commmits up to the root(s)
"
. git-sh-setup
@@ -44,6 +45,7 @@ STRATEGY=
ONTO=
VERBOSE=
OK_TO_SKIP_PRE_REBASE=
+REBASE_ROOT=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
@@ -154,6 +156,11 @@ pick_one () {
output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
test -d "$REWRITTEN" &&
pick_one_preserving_merges "$@" && return
+ if test ! -z "$REBASE_ROOT"
+ then
+ output git cherry-pick "$@"
+ return
+ fi
parent_sha1=$(git rev-parse --verify $sha1^) ||
die "Could not get the parent of $sha1"
current_sha1=$(git rev-parse --verify HEAD)
@@ -443,6 +450,7 @@ get_saved_options () {
test -d "$REWRITTEN" && PRESERVE_MERGES=t
test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
test -f "$DOTEST"/verbose && VERBOSE=t
+ test ! -s "$DOTEST"/upstream && REBASE_ROOT=t
}
while test $# != 0
@@ -547,6 +555,9 @@ first and then run 'git rebase --continue' again."
-i)
# yeah, we know
;;
+ --root)
+ REBASE_ROOT=t
+ ;;
--onto)
shift
ONTO=$(git rev-parse --verify "$1") ||
@@ -555,7 +566,7 @@ first and then run 'git rebase --continue' again."
--)
shift
run_pre_rebase_hook ${1+"$@"}
- test $# -eq 1 -o $# -eq 2 || usage
+ test ! -z "$REBASE_ROOT" -o $# -eq 1 -o $# -eq 2 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
@@ -566,15 +577,22 @@ first and then run 'git rebase --continue' again."
require_clean_work_tree
- UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
- test -z "$ONTO" && ONTO=$UPSTREAM
+ if test -z "$REBASE_ROOT"
+ then
+ UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+ test -z "$ONTO" && ONTO=$UPSTREAM
+ shift
+ else
+ test -z "$ONTO" &&
+ die "You must specify --onto when using --root"
+ fi
- if test ! -z "$2"
+ if test ! -z "$1"
then
- output git show-ref --verify --quiet "refs/heads/$2" ||
- die "Invalid branchname: $2"
- output git checkout "$2" ||
- die "Could not checkout $2"
+ output git show-ref --verify --quiet "refs/heads/$1" ||
+ die "Invalid branchname: $1"
+ output git checkout "$1" ||
+ die "Could not checkout $1"
fi
HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
@@ -613,12 +631,21 @@ first and then run 'git rebase --continue' again."
MERGES_OPTION="--no-merges --cherry-pick"
fi
- SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
SHORTHEAD=$(git rev-parse --short $HEAD)
SHORTONTO=$(git rev-parse --short $ONTO)
+ if test -z "$REBASE_ROOT"
+ # this is now equivalent to ! -z "$UPSTREAM"
+ then
+ SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
+ REVISIONS=$UPSTREAM...$HEAD
+ SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
+ else
+ REVISIONS=$HEAD
+ SHORTREVISIONS=$SHORTHEAD
+ fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
--abbrev=7 --reverse --left-right --topo-order \
- $UPSTREAM...$HEAD | \
+ $REVISIONS | \
sed -n "s/^>//p" | while read shortsha1 rest
do
if test t != "$PRESERVE_MERGES"
@@ -647,11 +674,11 @@ first and then run 'git rebase --continue' again."
then
mkdir "$DROPPED"
# Save all non-cherry-picked changes
- git rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \
+ git rev-list $REVISIONS --left-right --cherry-pick | \
sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
# Now all commits and note which ones are missing in
# not-cherry-picks and hence being dropped
- git rev-list $UPSTREAM..$HEAD |
+ git rev-list $REVISIONS |
while read rev
do
if test -f "$REWRITTEN"/$rev -a "$(grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
@@ -670,7 +697,7 @@ first and then run 'git rebase --continue' again."
test -s "$TODO" || echo noop >> "$TODO"
cat >> "$TODO" << EOF
-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
+# Rebase $SHORTREVISIONS onto $SHORTONTO
#
# Commands:
# p, pick = use commit
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 63ec5e6..bb44a52 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -49,4 +49,18 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '
test_cmp expect rebased2
'
+test_expect_success 'rebase -i --root --onto <newbase>' '
+ git checkout -b work3 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased3 &&
+ test_cmp expect rebased3
+'
+
+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '
+ git branch work4 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master work4 &&
+ git log --pretty=tformat:"%s" > rebased4 &&
+ test_cmp expect rebased4
+'
+
test_done
--
1.6.1.1.g4c1d9.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* rebase: update documentation for --root
[not found] ` <cover.1230569041.git.trast@student.ethz.ch>
2008-12-29 16:45 ` rebase: learn to rebase root commit Thomas Rast
2008-12-29 16:45 ` rebase -i: " Thomas Rast
@ 2008-12-29 16:45 ` Thomas Rast
2 siblings, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2008-12-29 16:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Since the new option depends on --onto and omission of <upstream>, use
a separate invocation style, and omit most options to save space.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Documentation/git-rebase.txt | 17 ++++++++++++-----
1 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index c8ad86a..3268cd2 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
- [-s <strategy> | --strategy=<strategy>] [--no-verify]
- [-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
- [--onto <newbase>] <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+ <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] --onto <newbase>
+ --root [<branch>]
+
'git rebase' --continue | --skip | --abort
DESCRIPTION
@@ -22,7 +23,8 @@ it remains on the current branch.
All changes made by commits in the current branch but that are not
in <upstream> are saved to a temporary area. This is the same set
-of commits that would be shown by `git log <upstream>..HEAD`.
+of commits that would be shown by `git log <upstream>..HEAD` (or
+`git log HEAD`, if --root is specified).
The current branch is reset to <upstream>, or <newbase> if the
--onto option was supplied. This has the exact same effect as
@@ -255,6 +257,11 @@ OPTIONS
--preserve-merges::
Instead of ignoring merges, try to recreate them.
+--root::
+ Rebase all commits reachable from <branch>, instead of
+ limiting them with an <upstream>. This allows you to rebase
+ the root commit(s) on a branch. Must be used with --onto.
+
include::merge-strategies.txt[]
NOTES
--
1.6.1.1.g4c1d9.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: rebase -i: learn to rebase root commit
2008-12-29 16:45 ` rebase -i: " Thomas Rast
@ 2008-12-29 21:49 ` Thomas Rast
2008-12-29 22:21 ` Boyd Stephen Smith Jr.
2008-12-30 8:22 ` rebase -i: " Junio C Hamano
0 siblings, 2 replies; 27+ messages in thread
From: Thomas Rast @ 2008-12-29 21:49 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
[-- Attachment #1: Type: text/plain, Size: 710 bytes --]
Thomas Rast wrote:
> Teach git-rebase -i a new option --root, which instructs it to rebase
> the entire history leading up to <branch>. This is mainly for
> symmetry with ordinary git-rebase; it cannot be used to edit the root
> commit in-place (it requires --onto).
Actually, I forgot the "rebase -i -p" code path, which dies if --root
is used with -p. Apologies.
So for now, consider this broken and RFC: is there any sensible
use/interpretation of -p --root that I'm missing? Or should it just
disallow this combination?
[I also seem to manage to shoot myself with format-patch & topgit
every time, no matter how trivial the issue.]
--
Thomas Rast
trast@{inf,student}.ethz.ch
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: rebase -i: learn to rebase root commit
2008-12-29 21:49 ` Thomas Rast
@ 2008-12-29 22:21 ` Boyd Stephen Smith Jr.
2008-12-30 12:23 ` Thomas Rast
2008-12-30 8:22 ` rebase -i: " Junio C Hamano
1 sibling, 1 reply; 27+ messages in thread
From: Boyd Stephen Smith Jr. @ 2008-12-29 22:21 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, Junio C Hamano
[-- Attachment #1: Type: text/plain, Size: 1456 bytes --]
On Monday 2008 December 29 15:49:42 Thomas Rast wrote:
> Thomas Rast wrote:
> > Teach git-rebase -i a new option --root, which instructs it to rebase
> > the entire history leading up to <branch>. This is mainly for
> > symmetry with ordinary git-rebase; it cannot be used to edit the root
> > commit in-place (it requires --onto).
>
> Actually, I forgot the "rebase -i -p" code path, which dies if --root
> is used with -p. Apologies.
>
> So for now, consider this broken and RFC: is there any sensible
> use/interpretation of -p --root that I'm missing? Or should it just
> disallow this combination?
Here's the interpretation that *I* come up with for -p --root used together:
The commit with no parents (OLD_ROOT) is rebased as if -p were not given, call
the resulting commit NEW_ROOT. Then, the rebase continues as if "--onto
NEW_ROOT OLD_ROOT <branch>" was specified instead of "--onto=NEW_ROOT^ --root
<branch>".
Basically, --root only changes how the first commit is handled, which I think
is consistent with other uses of --root. It's also similar to cherry-picking
the first commit, follwed by a non-root rebase, which I think is also
consistent with the intention of --root.
--
Boyd Stephen Smith Jr. ,= ,-_-. =.
bss@iguanasuicide.net ((_/)o o(\_))
ICQ: 514984 YM/AIM: DaTwinkDaddy `-'(. .)`-'
http://iguanasuicide.net/ \_/
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: rebase -i: learn to rebase root commit
2008-12-29 21:49 ` Thomas Rast
2008-12-29 22:21 ` Boyd Stephen Smith Jr.
@ 2008-12-30 8:22 ` Junio C Hamano
1 sibling, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2008-12-30 8:22 UTC (permalink / raw)
To: Thomas Rast; +Cc: git
Thomas Rast <trast@student.ethz.ch> writes:
> ... is there any sensible
> use/interpretation of -p --root that I'm missing? Or should it just
> disallow this combination?
If --root is about replaying all the history, wouldn't people want to use
it together with -p to reconstruct the whole history as a substitute for
filter-branch? IOW, I have a suspicion that they most likely should go
together.
I never felt a need to rebase deep down to --root myself anyway, so I am a
bad judge for people's needs on this topic, though.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: rebase -i: learn to rebase root commit
2008-12-29 22:21 ` Boyd Stephen Smith Jr.
@ 2008-12-30 12:23 ` Thomas Rast
2008-12-30 12:29 ` [PATCH v2 1/3] rebase: " Thomas Rast
0 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2008-12-30 12:23 UTC (permalink / raw)
To: git; +Cc: Boyd Stephen Smith Jr.
[-- Attachment #1: Type: text/plain, Size: 2042 bytes --]
Boyd Stephen Smith Jr. wrote:
> Here's the interpretation that *I* come up with for -p --root used together:
> The commit with no parents (OLD_ROOT) is rebased as if -p were not given, call
> the resulting commit NEW_ROOT. Then, the rebase continues as if "--onto
> NEW_ROOT OLD_ROOT <branch>" was specified instead of "--onto=NEW_ROOT^ --root
> <branch>".
I like this logic, but it feels inconsistent as soon as there are
several root commits. (This may be somewhat academic, since any repo
with several roots should also be able to cope with a merge...)
Some digging into the -p code shows that it knows which commits were
rewritten, and which were untouched. It rewrites such that _all_
commits in $(git merge-base --all $branch $upstream) are rewritten to
look like $onto instead, i.e., all their occurrences in parent lists
of commits are rewritten to $onto. All other commits are only
rewritten if they have a parent that was rewritten.
So I think one sane way is to define a virtual parent 'root', and
think of parentless commits as having the (sole) parent 'root'. Then
we can rewrite such that 'root' becomes $onto, i.e., all occurrences
of 'root' in parent lists become $onto, consistent with the normal
operation. (For the other commits, the same rule as above is
applied.)
Of course this just boils down to saying that _all_ root commits
reachable from $branch are rewritten to have $onto as their parent.
Subsequently, all other commits will also be rewritten because they
all must have at least one rewritten parent.
> Basically, --root only changes how the first commit is handled, which I think
> is consistent with other uses of --root. It's also similar to cherry-picking
> the first commit, follwed by a non-root rebase, which I think is also
> consistent with the intention of --root.
I believe this remark still holds if there is only a single root
commit on $branch.
I will reroll with an updated 2/3 shortly.
--
Thomas Rast
trast@{inf,student}.ethz.ch
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v2 1/3] rebase: learn to rebase root commit
2008-12-30 12:23 ` Thomas Rast
@ 2008-12-30 12:29 ` Thomas Rast
2008-12-30 12:29 ` [PATCH v2 2/3] rebase -i: " Thomas Rast
2009-01-01 21:00 ` [PATCH v2 1/3] rebase: learn to rebase root commit Junio C Hamano
0 siblings, 2 replies; 27+ messages in thread
From: Thomas Rast @ 2008-12-30 12:29 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>.
The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN. You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection. This previously had to be done by
cherry-picking the root commit manually.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
No changes since v1.
git-rebase.sh | 51 ++++++++++++++++++++++++++++++++--------------
t/t3412-rebase-root.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 16 deletions(-)
create mode 100755 t/t3412-rebase-root.sh
diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..89de3c4 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
git_am_opt=
+rebase_root=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
-C*)
git_am_opt="$git_am_opt $1"
;;
+ --root)
+ rebase_root=t
+ ;;
-*)
usage
;;
@@ -344,17 +348,23 @@ case "$diff" in
;;
esac
+if test -z "$rebase_root"; then
# The upstream head must be given. Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ upstream_name="$1"
+ shift
+ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ die "invalid upstream $upstream_name"
+fi
+
+test ! -z "$rebase_root" -a -z "$newbase" &&
+ die "--root must be used with --onto"
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook ${upstream_name+"$upstream_name"} "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +372,16 @@ run_pre_rebase_hook ${1+"$@"}
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
-2)
+1)
# Is it "rebase other $branchname" or "rebase other $commit"?
- branch_name="$2"
- switch_to="$2"
+ branch_name="$1"
+ switch_to="$1"
- if git show-ref --verify --quiet -- "refs/heads/$2" &&
- branch=$(git rev-parse -q --verify "refs/heads/$2")
+ if git show-ref --verify --quiet -- "refs/heads/$1" &&
+ branch=$(git rev-parse -q --verify "refs/heads/$1")
then
- head_name="refs/heads/$2"
- elif branch=$(git rev-parse -q --verify "$2")
+ head_name="refs/heads/$1"
+ elif branch=$(git rev-parse -q --verify "$1")
then
head_name="detached HEAD"
else
@@ -393,7 +403,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or simply $branch
+# with --root) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -429,10 +440,18 @@ then
exit 0
fi
+if test ! -z "$rebase_root"; then
+ revisions="$orig_head"
+ fp_flag="--root"
+else
+ revisions="$upstream..$orig_head"
+ fp_flag="--ignore-if-in-upstream"
+fi
+
if test -z "$do_merge"
then
- git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- "$upstream..$orig_head" |
+ git format-patch -k --stdout --full-index "$fp_flag" \
+ "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -455,7 +474,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..63ec5e6
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1 &&
+ echo 2 > A &&
+ git add A &&
+ git commit -m 2 &&
+ git symbolic-ref HEAD refs/heads/other &&
+ rm .git/index &&
+ rm A &&
+ echo 3 > B &&
+ git add B &&
+ git commit -m 3 &&
+ echo 4 > B &&
+ git add B &&
+ git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+ test_must_fail git rebase --root
+'
+
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+ git checkout -b work &&
+ git rebase --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased &&
+ test_cmp expect rebased
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+ git branch work2 other &&
+ git rebase --root --onto master work2 &&
+ git log --pretty=tformat:"%s" > rebased2 &&
+ test_cmp expect rebased2
+'
+
+test_done
--
1.6.1.20.g7f5c5.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v2 2/3] rebase -i: learn to rebase root commit
2008-12-30 12:29 ` [PATCH v2 1/3] rebase: " Thomas Rast
@ 2008-12-30 12:29 ` Thomas Rast
2008-12-30 12:29 ` [PATCH v2 3/3] rebase: update documentation for --root Thomas Rast
2009-01-01 21:00 ` [PATCH v2 1/3] rebase: learn to rebase root commit Junio C Hamano
1 sibling, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2008-12-30 12:29 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Teach git-rebase -i a new option --root, which instructs it to rebase
the entire history leading up to <branch>. This is mainly for
symmetry with ordinary git-rebase; it cannot be used to edit the root
commit in-place (it requires --onto).
In the normal mode of operation, this is fairly straightforward. We
run cherry-pick in a loop, and cherry-pick has supported picking the
root commit since f95ebf7 (Allow cherry-picking root commits,
2008-07-04).
In --preserve-merges mode, we track the mapping from old to rewritten
commits and use it to update the parent list of each commit. In this
case, we define 'rebase -i -p --root --onto $onto $branch' to rewrite
the parent list of all root commit(s) on $branch to contain $onto
instead.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Changes since v1: also supports -p --root, with tests.
git-rebase--interactive.sh | 99 +++++++++++++++++++++++++++++++------------
t/t3412-rebase-root.sh | 82 ++++++++++++++++++++++++++++++++++++
2 files changed, 153 insertions(+), 28 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c8b0861..d6f54eb 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -27,6 +27,7 @@ continue continue rebasing process
abort abort rebasing process and restore original branch
skip skip current patch and continue rebasing process
no-verify override pre-rebase hook from stopping the operation
+root rebase all reachable commmits up to the root(s)
"
. git-sh-setup
@@ -44,6 +45,7 @@ STRATEGY=
ONTO=
VERBOSE=
OK_TO_SKIP_PRE_REBASE=
+REBASE_ROOT=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
@@ -154,6 +156,11 @@ pick_one () {
output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
test -d "$REWRITTEN" &&
pick_one_preserving_merges "$@" && return
+ if test ! -z "$REBASE_ROOT"
+ then
+ output git cherry-pick "$@"
+ return
+ fi
parent_sha1=$(git rev-parse --verify $sha1^) ||
die "Could not get the parent of $sha1"
current_sha1=$(git rev-parse --verify HEAD)
@@ -197,7 +204,11 @@ pick_one_preserving_merges () {
# rewrite parents; if none were rewritten, we can fast-forward.
new_parents=
- pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)"
+ pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)"
+ if test "$pend" = " "
+ then
+ pend=" root"
+ fi
while [ "$pend" != "" ]
do
p=$(expr "$pend" : ' \([^ ]*\)')
@@ -443,6 +454,7 @@ get_saved_options () {
test -d "$REWRITTEN" && PRESERVE_MERGES=t
test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
test -f "$DOTEST"/verbose && VERBOSE=t
+ test ! -s "$DOTEST"/upstream && REBASE_ROOT=t
}
while test $# != 0
@@ -547,6 +559,9 @@ first and then run 'git rebase --continue' again."
-i)
# yeah, we know
;;
+ --root)
+ REBASE_ROOT=t
+ ;;
--onto)
shift
ONTO=$(git rev-parse --verify "$1") ||
@@ -555,7 +570,7 @@ first and then run 'git rebase --continue' again."
--)
shift
run_pre_rebase_hook ${1+"$@"}
- test $# -eq 1 -o $# -eq 2 || usage
+ test ! -z "$REBASE_ROOT" -o $# -eq 1 -o $# -eq 2 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
@@ -566,15 +581,22 @@ first and then run 'git rebase --continue' again."
require_clean_work_tree
- UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
- test -z "$ONTO" && ONTO=$UPSTREAM
+ if test -z "$REBASE_ROOT"
+ then
+ UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+ test -z "$ONTO" && ONTO=$UPSTREAM
+ shift
+ else
+ test -z "$ONTO" &&
+ die "You must specify --onto when using --root"
+ fi
- if test ! -z "$2"
+ if test ! -z "$1"
then
- output git show-ref --verify --quiet "refs/heads/$2" ||
- die "Invalid branchname: $2"
- output git checkout "$2" ||
- die "Could not checkout $2"
+ output git show-ref --verify --quiet "refs/heads/$1" ||
+ die "Invalid branchname: $1"
+ output git checkout "$1" ||
+ die "Could not checkout $1"
fi
HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
@@ -598,12 +620,19 @@ first and then run 'git rebase --continue' again."
# This ensures that commits on merged, but otherwise
# unrelated side branches are left alone. (Think "X"
# in the man page's example.)
- mkdir "$REWRITTEN" &&
- for c in $(git merge-base --all $HEAD $UPSTREAM)
- do
- echo $ONTO > "$REWRITTEN"/$c ||
+ if test -z "$REBASE_ROOT"
+ then
+ mkdir "$REWRITTEN" &&
+ for c in $(git merge-base --all $HEAD $UPSTREAM)
+ do
+ echo $ONTO > "$REWRITTEN"/$c ||
+ die "Could not init rewritten commits"
+ done
+ else
+ mkdir "$REWRITTEN" &&
+ echo $ONTO > "$REWRITTEN"/root ||
die "Could not init rewritten commits"
- done
+ fi
# No cherry-pick because our first pass is to determine
# parents to rewrite and skipping dropped commits would
# prematurely end our probe
@@ -613,12 +642,21 @@ first and then run 'git rebase --continue' again."
MERGES_OPTION="--no-merges --cherry-pick"
fi
- SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
SHORTHEAD=$(git rev-parse --short $HEAD)
SHORTONTO=$(git rev-parse --short $ONTO)
+ if test -z "$REBASE_ROOT"
+ # this is now equivalent to ! -z "$UPSTREAM"
+ then
+ SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
+ REVISIONS=$UPSTREAM...$HEAD
+ SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
+ else
+ REVISIONS=$HEAD
+ SHORTREVISIONS=$SHORTHEAD
+ fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
--abbrev=7 --reverse --left-right --topo-order \
- $UPSTREAM...$HEAD | \
+ $REVISIONS | \
sed -n "s/^>//p" | while read shortsha1 rest
do
if test t != "$PRESERVE_MERGES"
@@ -626,14 +664,19 @@ first and then run 'git rebase --continue' again."
echo "pick $shortsha1 $rest" >> "$TODO"
else
sha1=$(git rev-parse $shortsha1)
- preserve=t
- for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)
- do
- if test -f "$REWRITTEN"/$p -a \( $p != $UPSTREAM -o $sha1 = $first_after_upstream \)
- then
- preserve=f
- fi
- done
+ if test -z "$REBASE_ROOT"
+ then
+ preserve=t
+ for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
+ do
+ if test -f "$REWRITTEN"/$p -a \( $p != $UPSTREAM -o $sha1 = $first_after_upstream \)
+ then
+ preserve=f
+ fi
+ done
+ else
+ preserve=f
+ fi
if test f = "$preserve"
then
touch "$REWRITTEN"/$sha1
@@ -647,11 +690,11 @@ first and then run 'git rebase --continue' again."
then
mkdir "$DROPPED"
# Save all non-cherry-picked changes
- git rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \
+ git rev-list $REVISIONS --left-right --cherry-pick | \
sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
# Now all commits and note which ones are missing in
# not-cherry-picks and hence being dropped
- git rev-list $UPSTREAM..$HEAD |
+ git rev-list $REVISIONS |
while read rev
do
if test -f "$REWRITTEN"/$rev -a "$(grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
@@ -660,7 +703,7 @@ first and then run 'git rebase --continue' again."
# not worthwhile, we don't want to track its multiple heads,
# just the history of its first-parent for others that will
# be rebasing on top of it
- git rev-list --parents -1 $rev | cut -d' ' -f2 > "$DROPPED"/$rev
+ git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
rm "$REWRITTEN"/$rev
@@ -670,7 +713,7 @@ first and then run 'git rebase --continue' again."
test -s "$TODO" || echo noop >> "$TODO"
cat >> "$TODO" << EOF
-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
+# Rebase $SHORTREVISIONS onto $SHORTONTO
#
# Commands:
# p, pick = use commit
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 63ec5e6..c845dfc 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -49,4 +49,86 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '
test_cmp expect rebased2
'
+test_expect_success 'rebase -i --root --onto <newbase>' '
+ git checkout -b work3 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased3 &&
+ test_cmp expect rebased3
+'
+
+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '
+ git branch work4 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master work4 &&
+ git log --pretty=tformat:"%s" > rebased4 &&
+ test_cmp expect rebased4
+'
+
+test_expect_success 'rebase -i -p with linear history' '
+ git checkout -b work5 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased5 &&
+ test_cmp expect rebased5
+'
+
+test_expect_success 'set up merge history' '
+ git checkout other^ &&
+ git checkout -b side &&
+ echo 5 > C &&
+ git add C &&
+ git commit -m 5 &&
+ git checkout other &&
+ git merge side
+'
+
+sed 's/#/ /g' > expect-side <<'EOF'
+* Merge branch 'side' into other
+|\##
+| * 5
+* | 4
+|/##
+* 3
+* 2
+* 1
+EOF
+
+test_expect_success 'rebase -i -p with merge' '
+ git checkout -b work6 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --graph --topo-order --pretty=tformat:"%s" > rebased6 &&
+ test_cmp expect-side rebased6
+'
+
+test_expect_success 'set up second root and merge' '
+ git symbolic-ref HEAD refs/heads/third &&
+ rm .git/index &&
+ rm A B C &&
+ echo 6 > D &&
+ git add D &&
+ git commit -m 6 &&
+ git checkout other &&
+ git merge third
+'
+
+sed 's/#/ /g' > expect-third <<'EOF'
+* Merge branch 'third' into other
+|\##
+| * 6
+* | Merge branch 'side' into other
+|\ \##
+| * | 5
+* | | 4
+|/ /##
+* | 3
+|/##
+* 2
+* 1
+EOF
+
+test_expect_success 'rebase -i -p with two roots' '
+ git checkout -b work7 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --graph --topo-order --pretty=tformat:"%s" > rebased7 &&
+ test_cmp expect-third rebased7
+'
+
test_done
--
1.6.1.20.g7f5c5.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v2 3/3] rebase: update documentation for --root
2008-12-30 12:29 ` [PATCH v2 2/3] rebase -i: " Thomas Rast
@ 2008-12-30 12:29 ` Thomas Rast
0 siblings, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2008-12-30 12:29 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Since the new option depends on --onto and omission of <upstream>, use
a separate invocation style, and omit most options to save space.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Changed since v1: remark about the effect of --root --preserve-merges.
Documentation/git-rebase.txt | 19 ++++++++++++++-----
1 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index c8ad86a..e3b4b83 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
- [-s <strategy> | --strategy=<strategy>] [--no-verify]
- [-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
- [--onto <newbase>] <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+ <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] --onto <newbase>
+ --root [<branch>]
+
'git rebase' --continue | --skip | --abort
DESCRIPTION
@@ -22,7 +23,8 @@ it remains on the current branch.
All changes made by commits in the current branch but that are not
in <upstream> are saved to a temporary area. This is the same set
-of commits that would be shown by `git log <upstream>..HEAD`.
+of commits that would be shown by `git log <upstream>..HEAD` (or
+`git log HEAD`, if --root is specified).
The current branch is reset to <upstream>, or <newbase> if the
--onto option was supplied. This has the exact same effect as
@@ -255,6 +257,13 @@ OPTIONS
--preserve-merges::
Instead of ignoring merges, try to recreate them.
+--root::
+ Rebase all commits reachable from <branch>, instead of
+ limiting them with an <upstream>. This allows you to rebase
+ the root commit(s) on a branch. Must be used with --onto.
+ When used together with --preserve-merges, 'all' root commits
+ will be rewritten to have <newbase> as parent instead.
+
include::merge-strategies.txt[]
NOTES
--
1.6.1.20.g7f5c5.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2008-12-30 12:29 ` [PATCH v2 1/3] rebase: " Thomas Rast
2008-12-30 12:29 ` [PATCH v2 2/3] rebase -i: " Thomas Rast
@ 2009-01-01 21:00 ` Junio C Hamano
2009-01-02 18:58 ` Johannes Schindelin
2009-01-02 22:20 ` Thomas Rast
1 sibling, 2 replies; 27+ messages in thread
From: Junio C Hamano @ 2009-01-01 21:00 UTC (permalink / raw)
To: Thomas Rast; +Cc: git
Thomas Rast <trast@student.ethz.ch> writes:
> Teach git-rebase a new option --root, which instructs it to rebase the
> entire history leading up to <branch>.
>
> The main use-case is with git-svn: suppose you start hacking (perhaps
> offline) on a new project, but later notice you want to commit this
> work to SVN. You will have to rebase the entire history, including
> the root commit, on a (possibly empty) commit coming from git-svn, to
> establish a history connection. This previously had to be done by
> cherry-picking the root commit manually.
I like what this series tries to do. Using the --root option is probably
a more natural way to do what people often do with the "add graft and
filter-branch the whole history once" procedure.
But it somewhat feels sad if the "main" use-case for this is to start your
project in git and then migrate away by feeding your history to subversion
;-).
> @@ -344,17 +348,23 @@ case "$diff" in
> ;;
> esac
>
> +if test -z "$rebase_root"; then
> # The upstream head must be given. Make sure it is valid.
> -upstream_name="$1"
> -upstream=`git rev-parse --verify "${upstream_name}^0"` ||
> - die "invalid upstream $upstream_name"
> + upstream_name="$1"
> + shift
> + upstream=`git rev-parse --verify "${upstream_name}^0"` ||
> + die "invalid upstream $upstream_name"
> +fi
> +
> +test ! -z "$rebase_root" -a -z "$newbase" &&
> + die "--root must be used with --onto"
This is much easier to read if it were:
if test -z "$rebase_root"
then
... do the upstream_name/upstream thing, such as
upstream_name="$1"
...
else
... do the rebase_root thing, including
unset upstream
unset upstream_name
test -z "$newbase" && die "--root without --onto"
...
fi
(Mental note. You shifted positional parameters and the remainders need
to be adjusted, which you seem to have done).
> # Make sure the branch to rebase onto is valid.
> onto_name=${newbase-"$upstream_name"}
> onto=$(git rev-parse --verify "${onto_name}^0") || exit
>
> # If a hook exists, give it a chance to interrupt
> -run_pre_rebase_hook ${1+"$@"}
> +run_pre_rebase_hook ${upstream_name+"$upstream_name"} "$@"
I do not think ${upstream_name+"$upstream_name"} is a good check to begin
with, because presense of it does not necessarily mean the command was
invoked without --root; it could have come from the environment of the
invoker (hence the suggestion to unset the variable explicitly).
And I do not think this is a good way to extend the calling convention of
the hook, either. pre-rebase-hook used to always take upstream and
optionally the explicit branch name. When --root is given, your code will
give the hook a single parameter which is the explicit branch name
(i.e. "we will switch to this branch and rebase it, are you Ok with it?"),
but the hook will mistakenly think you are feeding the fork-point commit.
Because an old pre-rebase-hook cannot verify --root case correctly anyway
and needs to be updated, how about doing 'run_pre_rebase_hook --root "$@"'
when --root was given?
> @@ -393,7 +403,8 @@ case "$#" in
> esac
> orig_head=$branch
>
> -# Now we are rebasing commits $upstream..$branch on top of $onto
> +# Now we are rebasing commits $upstream..$branch (or simply $branch
> +# with --root) on top of $onto
"or simply everything leading to $branch if --root is given"?
> # Check if we are already based on $onto with linear history,
> # but this should be done only when upstream and onto are the same.
> @@ -429,10 +440,18 @@ then
> exit 0
> fi
>
> +if test ! -z "$rebase_root"; then
> + revisions="$orig_head"
> + fp_flag="--root"
> +else
> + revisions="$upstream..$orig_head"
> + fp_flag="--ignore-if-in-upstream"
> +fi
Hmph, the reason why --ignore-if-in-upstream is irrelevant when --root is
given is because...?
> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
> new file mode 100755
> index 0000000..63ec5e6
> --- /dev/null
> +++ b/t/t3412-rebase-root.sh
> @@ -0,0 +1,52 @@
> +#!/bin/sh
> +
> +test_description='git rebase --root
> ...
> +test_done
Including tests for the pre-rebase-hook would be nice.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2009-01-01 21:00 ` [PATCH v2 1/3] rebase: learn to rebase root commit Junio C Hamano
@ 2009-01-02 18:58 ` Johannes Schindelin
2009-01-02 22:20 ` Thomas Rast
1 sibling, 0 replies; 27+ messages in thread
From: Johannes Schindelin @ 2009-01-02 18:58 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Thomas Rast, git
Hi,
On Thu, 1 Jan 2009, Junio C Hamano wrote:
> Thomas Rast <trast@student.ethz.ch> writes:
>
> > Teach git-rebase a new option --root, which instructs it to rebase the
> > entire history leading up to <branch>.
> >
> > The main use-case is with git-svn: suppose you start hacking (perhaps
> > offline) on a new project, but later notice you want to commit this
> > work to SVN. You will have to rebase the entire history, including
> > the root commit, on a (possibly empty) commit coming from git-svn, to
> > establish a history connection. This previously had to be done by
> > cherry-picking the root commit manually.
>
> I like what this series tries to do. Using the --root option is probably
> a more natural way to do what people often do with the "add graft and
> filter-branch the whole history once" procedure.
>
> But it somewhat feels sad if the "main" use-case for this is to start your
> project in git and then migrate away by feeding your history to subversion
> ;-).
FWIW I had a single case where I could have used something like this
myself, in my whole life. It was when I started to write
git-edit-patch-series.sh in its own repository, only to realize at the end
that I should have started it in a topic branch in my git.git tree.
Ciao,
Dscho
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2009-01-01 21:00 ` [PATCH v2 1/3] rebase: learn to rebase root commit Junio C Hamano
2009-01-02 18:58 ` Johannes Schindelin
@ 2009-01-02 22:20 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 1/4] rebase -i: execute hook only after argument checking Thomas Rast
2009-01-02 22:49 ` [PATCH v2 1/3] " Junio C Hamano
1 sibling, 2 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:20 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 3524 bytes --]
Junio C Hamano wrote:
> Thomas Rast <trast@student.ethz.ch> writes:
> > The main use-case is with git-svn: [...]
>
> I like what this series tries to do. Using the --root option is probably
> a more natural way to do what people often do with the "add graft and
> filter-branch the whole history once" procedure.
Their uses are somewhat disjoint, as grafting only works if the
grafted parent has an empty tree. Otherwise the grafted child will
appear to revert the entire history leading to it. Rebase OTOH
changes the committers.
> But it somewhat feels sad if the "main" use-case for this is to start your
> project in git and then migrate away by feeding your history to subversion
> ;-).
You can remove that paragraph if you don't want to "support" SVN in
git.git ;-)
> > # Make sure the branch to rebase onto is valid.
> > onto_name=${newbase-"$upstream_name"}
> > onto=$(git rev-parse --verify "${onto_name}^0") || exit
> >
> > # If a hook exists, give it a chance to interrupt
> > -run_pre_rebase_hook ${1+"$@"}
> > +run_pre_rebase_hook ${upstream_name+"$upstream_name"} "$@"
>
> I do not think ${upstream_name+"$upstream_name"} is a good check to begin
> with, because presense of it does not necessarily mean the command was
> invoked without --root; it could have come from the environment of the
> invoker (hence the suggestion to unset the variable explicitly).
Good catch, thanks.
I'm still not sure what ${1+"$@"} was about by the way. The most
authoritative reference I can find is
http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02
which says
If there are no positional parameters, the expansion of '@' shall
generate zero fields, even when '@' is double-quoted.
('man bash' agrees.)
> And I do not think this is a good way to extend the calling convention of
> the hook, either. pre-rebase-hook used to always take upstream and
> optionally the explicit branch name. When --root is given, your code will
> give the hook a single parameter which is the explicit branch name
> (i.e. "we will switch to this branch and rebase it, are you Ok with it?"),
> but the hook will mistakenly think you are feeding the fork-point commit.
>
> Because an old pre-rebase-hook cannot verify --root case correctly anyway
> and needs to be updated, how about doing 'run_pre_rebase_hook --root "$@"'
> when --root was given?
True. I noticed that I had to fix the positionals, but forgot about
the hook afterwards. v3 implements this as you suggested.
> > +if test ! -z "$rebase_root"; then
> > + revisions="$orig_head"
> > + fp_flag="--root"
> > +else
> > + revisions="$upstream..$orig_head"
> > + fp_flag="--ignore-if-in-upstream"
> > +fi
>
> Hmph, the reason why --ignore-if-in-upstream is irrelevant when --root is
> given is because...?
Well, originally because format-patch didn't like the argument.
Thanks for prodding however, $onto..$head makes sort of makes sense
here and I discovered that even $onto...$head works, which is used in
'rebase -i'.
However, it's still a change of semantics: With --root we now ignore
patches that are already contained in $onto, as opposed to patches
that were already in $upstream in normal operation. It seems sensible
to do it this way, and perhaps even normal rebase should do it the
same way... if only format-patch would support it.
Thanks for the review! v3 upcoming.
--
Thomas Rast
trast@{inf,student}.ethz.ch
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3 1/4] rebase -i: execute hook only after argument checking
2009-01-02 22:20 ` Thomas Rast
@ 2009-01-02 22:28 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 2/4] rebase: learn to rebase root commit Thomas Rast
2009-01-02 22:49 ` [PATCH v2 1/3] " Junio C Hamano
1 sibling, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:28 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
Previously, the pre-rebase-hook would be launched before we knew if
the <upstream> [<branch>] arguments were supplied.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
This is a quick fix and not really part of the series. 2/4 textually
depends on it, however, so I'm sending it along.
git-rebase--interactive.sh | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index c8b0861..2c668cd 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -554,7 +554,6 @@ first and then run 'git rebase --continue' again."
;;
--)
shift
- run_pre_rebase_hook ${1+"$@"}
test $# -eq 1 -o $# -eq 2 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
@@ -562,11 +561,13 @@ first and then run 'git rebase --continue' again."
git var GIT_COMMITTER_IDENT >/dev/null ||
die "You need to set your committer info first"
+ UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+ run_pre_rebase_hook ${1+"$@"}
+
comment_for_reflog start
require_clean_work_tree
- UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
test -z "$ONTO" && ONTO=$UPSTREAM
if test ! -z "$2"
--
1.6.1.71.gaaa47.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v3 2/4] rebase: learn to rebase root commit
2009-01-02 22:28 ` [PATCH v3 1/4] rebase -i: execute hook only after argument checking Thomas Rast
@ 2009-01-02 22:28 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
` (2 more replies)
0 siblings, 3 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:28 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>. This option must be used with
--onto <newbase>, and causes commits that already exist in <newbase>
to be skipped. (Normal operation skips commits that already exist in
<upstream> instead.)
The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN. You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection. This previously had to be done by
cherry-picking the root commit manually.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
git-rebase.sh | 50 +++++++++++++++++++--------
t/t3412-rebase-root.sh | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+), 15 deletions(-)
create mode 100755 t/t3412-rebase-root.sh
diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..9437e51 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
git_am_opt=
+rebase_root=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
-C*)
git_am_opt="$git_am_opt $1"
;;
+ --root)
+ rebase_root=t
+ ;;
-*)
usage
;;
@@ -344,17 +348,26 @@ case "$diff" in
;;
esac
+if test -z "$rebase_root"; then
# The upstream head must be given. Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ upstream_name="$1"
+ shift
+ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ die "invalid upstream $upstream_name"
+ unset root_flag
+else
+ test -z "$newbase" && die "--root must be used with --onto"
+ unset upstream_name
+ unset upstream
+ root_flag="--root"
+fi
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook $root_flag $upstream_name "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +375,16 @@ run_pre_rebase_hook ${1+"$@"}
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
-2)
+1)
# Is it "rebase other $branchname" or "rebase other $commit"?
- branch_name="$2"
- switch_to="$2"
+ branch_name="$1"
+ switch_to="$1"
- if git show-ref --verify --quiet -- "refs/heads/$2" &&
- branch=$(git rev-parse -q --verify "refs/heads/$2")
+ if git show-ref --verify --quiet -- "refs/heads/$1" &&
+ branch=$(git rev-parse -q --verify "refs/heads/$1")
then
- head_name="refs/heads/$2"
- elif branch=$(git rev-parse -q --verify "$2")
+ head_name="refs/heads/$1"
+ elif branch=$(git rev-parse -q --verify "$1")
then
head_name="detached HEAD"
else
@@ -393,7 +406,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or with --root,
+# everything leading up to $branch) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -429,10 +443,16 @@ then
exit 0
fi
+if test ! -z "$rebase_root"; then
+ revisions="$onto..$orig_head"
+else
+ revisions="$upstream..$orig_head"
+fi
+
if test -z "$do_merge"
then
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- "$upstream..$orig_head" |
+ $root_flag "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -455,7 +475,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..1978512
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1 &&
+ echo 2 > A &&
+ git add A &&
+ git commit -m 2 &&
+ git symbolic-ref HEAD refs/heads/other &&
+ rm .git/index &&
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1b &&
+ echo 3 > B &&
+ git add B &&
+ git commit -m 3 &&
+ echo 4 > B &&
+ git add B &&
+ git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+ test_must_fail git rebase --root
+'
+
+test_expect_success 'setup pre-rebase hook' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+ git checkout -b work &&
+ git rebase --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased &&
+ test_cmp expect rebased
+'
+
+test_expect_success 'pre-rebase got correct input (1)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+ git branch work2 other &&
+ git rebase --root --onto master work2 &&
+ git log --pretty=tformat:"%s" > rebased2 &&
+ test_cmp expect rebased2
+'
+
+test_expect_success 'pre-rebase got correct input (2)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+ git checkout -b stops1 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
+test_done
--
1.6.1.71.gaaa47.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v3 3/4] rebase -i: learn to rebase root commit
2009-01-02 22:28 ` [PATCH v3 2/4] rebase: learn to rebase root commit Thomas Rast
@ 2009-01-02 22:28 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 4/4] rebase: update documentation for --root Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 3/4] rebase -i: learn to rebase root commit Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 2/4] rebase: " Thomas Rast
2009-01-02 23:06 ` [PATCH " Junio C Hamano
2 siblings, 2 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:28 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
Teach git-rebase -i a new option --root, which instructs it to rebase
the entire history leading up to <branch>. This is mainly for
symmetry with ordinary git-rebase; it cannot be used to edit the root
commit in-place (it requires --onto <newbase>). Commits that already
exist in <newbase> are skipped.
In the normal mode of operation, this is fairly straightforward. We
run cherry-pick in a loop, and cherry-pick has supported picking the
root commit since f95ebf7 (Allow cherry-picking root commits,
2008-07-04).
In --preserve-merges mode, we track the mapping from old to rewritten
commits and use it to update the parent list of each commit. In this
case, we define 'rebase -i -p --root --onto $onto $branch' to rewrite
the parent list of all root commit(s) on $branch to contain $onto
instead.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
git-rebase--interactive.sh | 109 +++++++++++++++++++++++++++++++------------
t/t3412-rebase-root.sh | 101 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 179 insertions(+), 31 deletions(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 2c668cd..14d3e38 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -27,6 +27,7 @@ continue continue rebasing process
abort abort rebasing process and restore original branch
skip skip current patch and continue rebasing process
no-verify override pre-rebase hook from stopping the operation
+root rebase all reachable commmits up to the root(s)
"
. git-sh-setup
@@ -44,6 +45,7 @@ STRATEGY=
ONTO=
VERBOSE=
OK_TO_SKIP_PRE_REBASE=
+REBASE_ROOT=
GIT_CHERRY_PICK_HELP=" After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
@@ -154,6 +156,11 @@ pick_one () {
output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
test -d "$REWRITTEN" &&
pick_one_preserving_merges "$@" && return
+ if test ! -z "$REBASE_ROOT"
+ then
+ output git cherry-pick "$@"
+ return
+ fi
parent_sha1=$(git rev-parse --verify $sha1^) ||
die "Could not get the parent of $sha1"
current_sha1=$(git rev-parse --verify HEAD)
@@ -197,7 +204,11 @@ pick_one_preserving_merges () {
# rewrite parents; if none were rewritten, we can fast-forward.
new_parents=
- pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)"
+ pend=" $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)"
+ if test "$pend" = " "
+ then
+ pend=" root"
+ fi
while [ "$pend" != "" ]
do
p=$(expr "$pend" : ' \([^ ]*\)')
@@ -227,7 +238,9 @@ pick_one_preserving_merges () {
if test -f "$DROPPED"/$p
then
fast_forward=f
- pend=" $(cat "$DROPPED"/$p)$pend"
+ replacement="$(cat "$DROPPED"/$p)"
+ test -z "$replacement" && replacement=root
+ pend=" $replacement$pend"
else
new_parents="$new_parents $p"
fi
@@ -443,6 +456,7 @@ get_saved_options () {
test -d "$REWRITTEN" && PRESERVE_MERGES=t
test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
test -f "$DOTEST"/verbose && VERBOSE=t
+ test ! -s "$DOTEST"/upstream && REBASE_ROOT=t
}
while test $# != 0
@@ -547,6 +561,9 @@ first and then run 'git rebase --continue' again."
-i)
# yeah, we know
;;
+ --root)
+ REBASE_ROOT=t
+ ;;
--onto)
shift
ONTO=$(git rev-parse --verify "$1") ||
@@ -554,28 +571,36 @@ first and then run 'git rebase --continue' again."
;;
--)
shift
- test $# -eq 1 -o $# -eq 2 || usage
+ test ! -z "$REBASE_ROOT" -o $# -eq 1 -o $# -eq 2 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
git var GIT_COMMITTER_IDENT >/dev/null ||
die "You need to set your committer info first"
- UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
- run_pre_rebase_hook ${1+"$@"}
+ if test -z "$REBASE_ROOT"
+ then
+ UPSTREAM_ARG="$1"
+ UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
+ test -z "$ONTO" && ONTO=$UPSTREAM
+ shift
+ else
+ UPSTREAM_ARG=--root
+ test -z "$ONTO" &&
+ die "You must specify --onto when using --root"
+ fi
+ run_pre_rebase_hook "$UPSTREAM_ARG" "$@"
comment_for_reflog start
require_clean_work_tree
- test -z "$ONTO" && ONTO=$UPSTREAM
-
- if test ! -z "$2"
+ if test ! -z "$1"
then
- output git show-ref --verify --quiet "refs/heads/$2" ||
- die "Invalid branchname: $2"
- output git checkout "$2" ||
- die "Could not checkout $2"
+ output git show-ref --verify --quiet "refs/heads/$1" ||
+ die "Invalid branchname: $1"
+ output git checkout "$1" ||
+ die "Could not checkout $1"
fi
HEAD=$(git rev-parse --verify HEAD) || die "No HEAD?"
@@ -599,12 +624,19 @@ first and then run 'git rebase --continue' again."
# This ensures that commits on merged, but otherwise
# unrelated side branches are left alone. (Think "X"
# in the man page's example.)
- mkdir "$REWRITTEN" &&
- for c in $(git merge-base --all $HEAD $UPSTREAM)
- do
- echo $ONTO > "$REWRITTEN"/$c ||
+ if test -z "$REBASE_ROOT"
+ then
+ mkdir "$REWRITTEN" &&
+ for c in $(git merge-base --all $HEAD $UPSTREAM)
+ do
+ echo $ONTO > "$REWRITTEN"/$c ||
+ die "Could not init rewritten commits"
+ done
+ else
+ mkdir "$REWRITTEN" &&
+ echo $ONTO > "$REWRITTEN"/root ||
die "Could not init rewritten commits"
- done
+ fi
# No cherry-pick because our first pass is to determine
# parents to rewrite and skipping dropped commits would
# prematurely end our probe
@@ -614,12 +646,21 @@ first and then run 'git rebase --continue' again."
MERGES_OPTION="--no-merges --cherry-pick"
fi
- SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
SHORTHEAD=$(git rev-parse --short $HEAD)
SHORTONTO=$(git rev-parse --short $ONTO)
+ if test -z "$REBASE_ROOT"
+ # this is now equivalent to ! -z "$UPSTREAM"
+ then
+ SHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)
+ REVISIONS=$UPSTREAM...$HEAD
+ SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
+ else
+ REVISIONS=$ONTO...$HEAD
+ SHORTREVISIONS=$SHORTHEAD
+ fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
--abbrev=7 --reverse --left-right --topo-order \
- $UPSTREAM...$HEAD | \
+ $REVISIONS | \
sed -n "s/^>//p" | while read shortsha1 rest
do
if test t != "$PRESERVE_MERGES"
@@ -627,14 +668,19 @@ first and then run 'git rebase --continue' again."
echo "pick $shortsha1 $rest" >> "$TODO"
else
sha1=$(git rev-parse $shortsha1)
- preserve=t
- for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)
- do
- if test -f "$REWRITTEN"/$p -a \( $p != $UPSTREAM -o $sha1 = $first_after_upstream \)
- then
- preserve=f
- fi
- done
+ if test -z "$REBASE_ROOT"
+ then
+ preserve=t
+ for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
+ do
+ if test -f "$REWRITTEN"/$p -a \( $p != $UPSTREAM -o $sha1 = $first_after_upstream \)
+ then
+ preserve=f
+ fi
+ done
+ else
+ preserve=f
+ fi
if test f = "$preserve"
then
touch "$REWRITTEN"/$sha1
@@ -648,11 +694,11 @@ first and then run 'git rebase --continue' again."
then
mkdir "$DROPPED"
# Save all non-cherry-picked changes
- git rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \
+ git rev-list $REVISIONS --left-right --cherry-pick | \
sed -n "s/^>//p" > "$DOTEST"/not-cherry-picks
# Now all commits and note which ones are missing in
# not-cherry-picks and hence being dropped
- git rev-list $UPSTREAM..$HEAD |
+ git rev-list $REVISIONS |
while read rev
do
if test -f "$REWRITTEN"/$rev -a "$(grep "$rev" "$DOTEST"/not-cherry-picks)" = ""
@@ -661,17 +707,18 @@ first and then run 'git rebase --continue' again."
# not worthwhile, we don't want to track its multiple heads,
# just the history of its first-parent for others that will
# be rebasing on top of it
- git rev-list --parents -1 $rev | cut -d' ' -f2 > "$DROPPED"/$rev
+ git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$DROPPED"/$rev
short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
grep -v "^[a-z][a-z]* $short" <"$TODO" > "${TODO}2" ; mv "${TODO}2" "$TODO"
rm "$REWRITTEN"/$rev
fi
done
fi
+
test -s "$TODO" || echo noop >> "$TODO"
cat >> "$TODO" << EOF
-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
+# Rebase $SHORTREVISIONS onto $SHORTONTO
#
# Commands:
# p, pick = use commit
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 1978512..cbf3414 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -67,6 +67,100 @@ test_expect_success 'pre-rebase got correct input (2)' '
test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
'
+test_expect_success 'rebase -i --root --onto <newbase>' '
+ git checkout -b work3 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased3 &&
+ test_cmp expect rebased3
+'
+
+test_expect_success 'pre-rebase got correct input (3)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '
+ git branch work4 other &&
+ GIT_EDITOR=: git rebase -i --root --onto master work4 &&
+ git log --pretty=tformat:"%s" > rebased4 &&
+ test_cmp expect rebased4
+'
+
+test_expect_success 'pre-rebase got correct input (4)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work4
+'
+
+test_expect_success 'rebase -i -p with linear history' '
+ git checkout -b work5 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased5 &&
+ test_cmp expect rebased5
+'
+
+test_expect_success 'pre-rebase got correct input (5)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'set up merge history' '
+ git checkout other^ &&
+ git checkout -b side &&
+ echo 5 > C &&
+ git add C &&
+ git commit -m 5 &&
+ git checkout other &&
+ git merge side
+'
+
+sed 's/#/ /g' > expect-side <<'EOF'
+* Merge branch 'side' into other
+|\##
+| * 5
+* | 4
+|/##
+* 3
+* 2
+* 1
+EOF
+
+test_expect_success 'rebase -i -p with merge' '
+ git checkout -b work6 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --graph --topo-order --pretty=tformat:"%s" > rebased6 &&
+ test_cmp expect-side rebased6
+'
+
+test_expect_success 'set up second root and merge' '
+ git symbolic-ref HEAD refs/heads/third &&
+ rm .git/index &&
+ rm A B C &&
+ echo 6 > D &&
+ git add D &&
+ git commit -m 6 &&
+ git checkout other &&
+ git merge third
+'
+
+sed 's/#/ /g' > expect-third <<'EOF'
+* Merge branch 'third' into other
+|\##
+| * 6
+* | Merge branch 'side' into other
+|\ \##
+| * | 5
+* | | 4
+|/ /##
+* | 3
+|/##
+* 2
+* 1
+EOF
+
+test_expect_success 'rebase -i -p with two roots' '
+ git checkout -b work7 other &&
+ GIT_EDITOR=: git rebase -i -p --root --onto master &&
+ git log --graph --topo-order --pretty=tformat:"%s" > rebased7 &&
+ test_cmp expect-third rebased7
+'
+
test_expect_success 'setup pre-rebase hook that fails' '
mkdir -p .git/hooks &&
cat >.git/hooks/pre-rebase <<EOF &&
@@ -83,4 +177,11 @@ test_expect_success 'pre-rebase hook stops rebase' '
test 0 = $(git rev-list other...stops1 | wc -l)
'
+test_expect_success 'pre-rebase hook stops rebase -i' '
+ git checkout -b stops2 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops2
+ test 0 = $(git rev-list other...stops2 | wc -l)
+'
+
test_done
--
1.6.1.71.gaaa47.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v3 4/4] rebase: update documentation for --root
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
@ 2009-01-02 22:28 ` Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 3/4] rebase -i: learn to rebase root commit Thomas Rast
1 sibling, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:28 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
Since the new option depends on --onto and omission of <upstream>, use
a separate invocation style, and omit most options to save space.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Documentation/git-rebase.txt | 21 ++++++++++++++++-----
1 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index c8ad86a..3d6d429 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head
SYNOPSIS
--------
[verse]
-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]
- [-s <strategy> | --strategy=<strategy>] [--no-verify]
- [-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]
- [--onto <newbase>] <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] [--onto <newbase>]
+ <upstream> [<branch>]
+'git rebase' [-i | --interactive] [options] --onto <newbase>
+ --root [<branch>]
+
'git rebase' --continue | --skip | --abort
DESCRIPTION
@@ -22,7 +23,8 @@ it remains on the current branch.
All changes made by commits in the current branch but that are not
in <upstream> are saved to a temporary area. This is the same set
-of commits that would be shown by `git log <upstream>..HEAD`.
+of commits that would be shown by `git log <upstream>..HEAD` (or
+`git log HEAD`, if --root is specified).
The current branch is reset to <upstream>, or <newbase> if the
--onto option was supplied. This has the exact same effect as
@@ -255,6 +257,15 @@ OPTIONS
--preserve-merges::
Instead of ignoring merges, try to recreate them.
+--root::
+ Rebase all commits reachable from <branch>, instead of
+ limiting them with an <upstream>. This allows you to rebase
+ the root commit(s) on a branch. Must be used with --onto, and
+ will skip changes already contained in <newbase> (instead of
+ <upstream>). When used together with --preserve-merges, 'all'
+ root commits will be rewritten to have <newbase> as parent
+ instead.
+
include::merge-strategies.txt[]
NOTES
--
1.6.1.71.gaaa47.dirty
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [INTERDIFF v3 2/4] rebase: learn to rebase root commit
2009-01-02 22:28 ` [PATCH v3 2/4] rebase: learn to rebase root commit Thomas Rast
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
@ 2009-01-02 22:41 ` Thomas Rast
2009-01-02 23:06 ` [PATCH " Junio C Hamano
2 siblings, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
The interdiff to v2.
diff --git a/git-rebase.sh b/git-rebase.sh
index 89de3c4..9437e51 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -354,17 +354,20 @@ if test -z "$rebase_root"; then
shift
upstream=`git rev-parse --verify "${upstream_name}^0"` ||
die "invalid upstream $upstream_name"
+ unset root_flag
+else
+ test -z "$newbase" && die "--root must be used with --onto"
+ unset upstream_name
+ unset upstream
+ root_flag="--root"
fi
-test ! -z "$rebase_root" -a -z "$newbase" &&
- die "--root must be used with --onto"
-
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${upstream_name+"$upstream_name"} "$@"
+run_pre_rebase_hook $root_flag $upstream_name "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -403,8 +406,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch (or simply $branch
-# with --root) on top of $onto
+# Now we are rebasing commits $upstream..$branch (or with --root,
+# everything leading up to $branch) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -441,17 +444,15 @@ then
fi
if test ! -z "$rebase_root"; then
- revisions="$orig_head"
- fp_flag="--root"
+ revisions="$onto..$orig_head"
else
revisions="$upstream..$orig_head"
- fp_flag="--ignore-if-in-upstream"
fi
if test -z "$do_merge"
then
- git format-patch -k --stdout --full-index "$fp_flag" \
- "$revisions" |
+ git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+ $root_flag "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index 63ec5e6..1978512 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -15,7 +15,9 @@ test_expect_success 'prepare repository' '
git commit -m 2 &&
git symbolic-ref HEAD refs/heads/other &&
rm .git/index &&
- rm A &&
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1b &&
echo 3 > B &&
git add B &&
git commit -m 3 &&
@@ -28,6 +30,14 @@ test_expect_success 'rebase --root expects --onto' '
test_must_fail git rebase --root
'
+test_expect_success 'setup pre-rebase hook' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
cat > expect <<EOF
4
3
@@ -42,6 +52,10 @@ test_expect_success 'rebase --root --onto <newbase>' '
test_cmp expect rebased
'
+test_expect_success 'pre-rebase got correct input (1)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
test_expect_success 'rebase --root --onto <newbase> <branch>' '
git branch work2 other &&
git rebase --root --onto master work2 &&
@@ -49,4 +63,24 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '
test_cmp expect rebased2
'
+test_expect_success 'pre-rebase got correct input (2)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+ git checkout -b stops1 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
test_done
--
Thomas Rast
trast@{inf,student}.ethz.ch
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [INTERDIFF v3 3/4] rebase -i: learn to rebase root commit
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
2009-01-02 22:28 ` [PATCH v3 4/4] rebase: update documentation for --root Thomas Rast
@ 2009-01-02 22:41 ` Thomas Rast
1 sibling, 0 replies; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:41 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, bss
This is the interdiff to v2. Some of the changes are noise from 1/4.
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index d6f54eb..14d3e38 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -238,7 +238,9 @@ pick_one_preserving_merges () {
if test -f "$DROPPED"/$p
then
fast_forward=f
- pend=" $(cat "$DROPPED"/$p)$pend"
+ replacement="$(cat "$DROPPED"/$p)"
+ test -z "$replacement" && replacement=root
+ pend=" $replacement$pend"
else
new_parents="$new_parents $p"
fi
@@ -569,7 +571,6 @@ first and then run 'git rebase --continue' again."
;;
--)
shift
- run_pre_rebase_hook ${1+"$@"}
test ! -z "$REBASE_ROOT" -o $# -eq 1 -o $# -eq 2 || usage
test -d "$DOTEST" &&
die "Interactive rebase already started"
@@ -577,19 +578,22 @@ first and then run 'git rebase --continue' again."
git var GIT_COMMITTER_IDENT >/dev/null ||
die "You need to set your committer info first"
- comment_for_reflog start
-
- require_clean_work_tree
-
if test -z "$REBASE_ROOT"
then
+ UPSTREAM_ARG="$1"
UPSTREAM=$(git rev-parse --verify "$1") || die "Invalid base"
test -z "$ONTO" && ONTO=$UPSTREAM
shift
else
+ UPSTREAM_ARG=--root
test -z "$ONTO" &&
die "You must specify --onto when using --root"
fi
+ run_pre_rebase_hook "$UPSTREAM_ARG" "$@"
+
+ comment_for_reflog start
+
+ require_clean_work_tree
if test ! -z "$1"
then
@@ -651,7 +655,7 @@ first and then run 'git rebase --continue' again."
REVISIONS=$UPSTREAM...$HEAD
SHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD
else
- REVISIONS=$HEAD
+ REVISIONS=$ONTO...$HEAD
SHORTREVISIONS=$SHORTHEAD
fi
git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
@@ -710,6 +714,7 @@ first and then run 'git rebase --continue' again."
fi
done
fi
+
test -s "$TODO" || echo noop >> "$TODO"
cat >> "$TODO" << EOF
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
index c845dfc..cbf3414 100755
--- a/t/t3412-rebase-root.sh
+++ b/t/t3412-rebase-root.sh
@@ -15,7 +15,9 @@ test_expect_success 'prepare repository' '
git commit -m 2 &&
git symbolic-ref HEAD refs/heads/other &&
rm .git/index &&
- rm A &&
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1b &&
echo 3 > B &&
git add B &&
git commit -m 3 &&
@@ -28,6 +30,14 @@ test_expect_success 'rebase --root expects --onto' '
test_must_fail git rebase --root
'
+test_expect_success 'setup pre-rebase hook' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
cat > expect <<EOF
4
3
@@ -42,6 +52,10 @@ test_expect_success 'rebase --root --onto <newbase>' '
test_cmp expect rebased
'
+test_expect_success 'pre-rebase got correct input (1)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
test_expect_success 'rebase --root --onto <newbase> <branch>' '
git branch work2 other &&
git rebase --root --onto master work2 &&
@@ -49,6 +63,10 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '
test_cmp expect rebased2
'
+test_expect_success 'pre-rebase got correct input (2)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
test_expect_success 'rebase -i --root --onto <newbase>' '
git checkout -b work3 other &&
GIT_EDITOR=: git rebase -i --root --onto master &&
@@ -56,6 +74,10 @@ test_expect_success 'rebase -i --root --onto <newbase>' '
test_cmp expect rebased3
'
+test_expect_success 'pre-rebase got correct input (3)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
test_expect_success 'rebase -i --root --onto <newbase> <branch>' '
git branch work4 other &&
GIT_EDITOR=: git rebase -i --root --onto master work4 &&
@@ -63,6 +85,10 @@ test_expect_success 'rebase -i --root --onto <newbase> <branch>' '
test_cmp expect rebased4
'
+test_expect_success 'pre-rebase got correct input (4)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work4
+'
+
test_expect_success 'rebase -i -p with linear history' '
git checkout -b work5 other &&
GIT_EDITOR=: git rebase -i -p --root --onto master &&
@@ -70,6 +96,10 @@ test_expect_success 'rebase -i -p with linear history' '
test_cmp expect rebased5
'
+test_expect_success 'pre-rebase got correct input (5)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
test_expect_success 'set up merge history' '
git checkout other^ &&
git checkout -b side &&
@@ -131,4 +161,27 @@ test_expect_success 'rebase -i -p with two roots' '
test_cmp expect-third rebased7
'
+test_expect_success 'setup pre-rebase hook that fails' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+ git checkout -b stops1 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
+test_expect_success 'pre-rebase hook stops rebase -i' '
+ git checkout -b stops2 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops2
+ test 0 = $(git rev-list other...stops2 | wc -l)
+'
+
test_done
--
Thomas Rast
trast@{inf,student}.ethz.ch
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2009-01-02 22:20 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 1/4] rebase -i: execute hook only after argument checking Thomas Rast
@ 2009-01-02 22:49 ` Junio C Hamano
2009-01-02 22:54 ` Thomas Rast
1 sibling, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2009-01-02 22:49 UTC (permalink / raw)
To: Thomas Rast; +Cc: git
Thomas Rast <trast@student.ethz.ch> writes:
> I'm still not sure what ${1+"$@"} was about by the way.
It is one of the many old-timer's portability idioms that let us work
around bugs in some ancient shell implementations.
${1+"$@"} should be equivalent to "$@" in modern Bourne shell variants
that are POSIX compliant.
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2009-01-02 22:49 ` [PATCH v2 1/3] " Junio C Hamano
@ 2009-01-02 22:54 ` Thomas Rast
2009-01-02 23:07 ` Junio C Hamano
0 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 22:54 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
[-- Attachment #1: Type: text/plain, Size: 477 bytes --]
Junio C Hamano wrote:
> Thomas Rast <trast@student.ethz.ch> writes:
>
> > I'm still not sure what ${1+"$@"} was about by the way.
>
> It is one of the many old-timer's portability idioms that let us work
> around bugs in some ancient shell implementations.
>
> ${1+"$@"} should be equivalent to "$@" in modern Bourne shell variants
> that are POSIX compliant.
So do you want me to change it back to ${1+"$@"}?
--
Thomas Rast
trast@{inf,student}.ethz.ch
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v3 2/4] rebase: learn to rebase root commit
2009-01-02 22:28 ` [PATCH v3 2/4] rebase: learn to rebase root commit Thomas Rast
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 2/4] rebase: " Thomas Rast
@ 2009-01-02 23:06 ` Junio C Hamano
2009-01-02 23:45 ` [PATCH v3.1] " Thomas Rast
2 siblings, 1 reply; 27+ messages in thread
From: Junio C Hamano @ 2009-01-02 23:06 UTC (permalink / raw)
To: Thomas Rast; +Cc: git, bss
> # If a hook exists, give it a chance to interrupt
> -run_pre_rebase_hook ${1+"$@"}
> +run_pre_rebase_hook $root_flag $upstream_name "$@"
You'd have to quote the $upstream_name properly here, because the original
command line could well have been:
$ git rebase 'master@{3 days ago}'
^ permalink raw reply [flat|nested] 27+ messages in thread
* Re: [PATCH v2 1/3] rebase: learn to rebase root commit
2009-01-02 22:54 ` Thomas Rast
@ 2009-01-02 23:07 ` Junio C Hamano
0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2009-01-02 23:07 UTC (permalink / raw)
To: Thomas Rast; +Cc: git
Thomas Rast <trast@student.ethz.ch> writes:
>> ${1+"$@"} should be equivalent to "$@" in modern Bourne shell variants
>> that are POSIX compliant.
>
> So do you want me to change it back to ${1+"$@"}?
No. I was merely answering your question.
^ permalink raw reply [flat|nested] 27+ messages in thread
* [PATCH v3.1] rebase: learn to rebase root commit
2009-01-02 23:06 ` [PATCH " Junio C Hamano
@ 2009-01-02 23:45 ` Thomas Rast
2009-01-05 17:35 ` [PATCH v3.2] " Thomas Rast
0 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2009-01-02 23:45 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>. This option must be used with
--onto <newbase>, and causes commits that already exist in <newbase>
to be skipped. (Normal operation skips commits that already exist in
<upstream> instead.)
The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN. You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection. This previously had to be done by
cherry-picking the root commit manually.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Junio C Hamano wrote:
>
> > # If a hook exists, give it a chance to interrupt
> > -run_pre_rebase_hook ${1+"$@"}
> > +run_pre_rebase_hook $root_flag $upstream_name "$@"
>
> You'd have to quote the $upstream_name properly here, because the original
> command line could well have been:
>
> $ git rebase 'master@{3 days ago}'
Right, thanks. Let's fix it like this, so I won't have to look up
what the various special parameter expansion characters mean.
($root_flag is still used further below.)
>> --- a/git-rebase.sh
>> +++ b/git-rebase.sh
>> @@ -355,11 +355,13 @@ if test -z "$rebase_root"; then
>> upstream=`git rev-parse --verify "${upstream_name}^0"` ||
>> die "invalid upstream $upstream_name"
>> unset root_flag
>> + upstream_arg="$upstream_name"
>> else
>> test -z "$newbase" && die "--root must be used with --onto"
>> unset upstream_name
>> unset upstream
>> root_flag="--root"
>> + upstream_arg="$root_flag"
>> fi
>>
>> # Make sure the branch to rebase onto is valid.
>> @@ -367,7 +369,7 @@ onto_name=${newbase-"$upstream_name"}
>> onto=$(git rev-parse --verify "${onto_name}^0") || exit
>>
>> # If a hook exists, give it a chance to interrupt
>> -run_pre_rebase_hook $root_flag $upstream_name "$@"
>> +run_pre_rebase_hook "$upstream_arg" "$@"
>>
>> # If the branch to rebase is given, that is the branch we will rebase
>> # $branch_name -- branch being rebased, or HEAD (already detached)
git-rebase.sh | 52 ++++++++++++++++++++--------
t/t3412-rebase-root.sh | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+), 15 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..d1083f1 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
git_am_opt=
+rebase_root=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
-C*)
git_am_opt="$git_am_opt $1"
;;
+ --root)
+ rebase_root=t
+ ;;
-*)
usage
;;
@@ -344,17 +348,28 @@ case "$diff" in
;;
esac
+if test -z "$rebase_root"; then
# The upstream head must be given. Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ upstream_name="$1"
+ shift
+ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ die "invalid upstream $upstream_name"
+ unset root_flag
+ upstream_arg="$upstream_name"
+else
+ test -z "$newbase" && die "--root must be used with --onto"
+ unset upstream_name
+ unset upstream
+ root_flag="--root"
+ upstream_arg="$root_flag"
+fi
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook "$upstream_arg" "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +377,16 @@ run_pre_rebase_hook ${1+"$@"}
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
-2)
+1)
# Is it "rebase other $branchname" or "rebase other $commit"?
- branch_name="$2"
- switch_to="$2"
+ branch_name="$1"
+ switch_to="$1"
- if git show-ref --verify --quiet -- "refs/heads/$2" &&
- branch=$(git rev-parse -q --verify "refs/heads/$2")
+ if git show-ref --verify --quiet -- "refs/heads/$1" &&
+ branch=$(git rev-parse -q --verify "refs/heads/$1")
then
- head_name="refs/heads/$2"
- elif branch=$(git rev-parse -q --verify "$2")
+ head_name="refs/heads/$1"
+ elif branch=$(git rev-parse -q --verify "$1")
then
head_name="detached HEAD"
else
@@ -393,7 +408,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or with --root,
+# everything leading up to $branch) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -429,10 +445,16 @@ then
exit 0
fi
+if test ! -z "$rebase_root"; then
+ revisions="$onto..$orig_head"
+else
+ revisions="$upstream..$orig_head"
+fi
+
if test -z "$do_merge"
then
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- "$upstream..$orig_head" |
+ $root_flag "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -455,7 +477,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..1978512
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1 &&
+ echo 2 > A &&
+ git add A &&
+ git commit -m 2 &&
+ git symbolic-ref HEAD refs/heads/other &&
+ rm .git/index &&
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1b &&
+ echo 3 > B &&
+ git add B &&
+ git commit -m 3 &&
+ echo 4 > B &&
+ git add B &&
+ git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+ test_must_fail git rebase --root
+'
+
+test_expect_success 'setup pre-rebase hook' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+ git checkout -b work &&
+ git rebase --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased &&
+ test_cmp expect rebased
+'
+
+test_expect_success 'pre-rebase got correct input (1)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+ git branch work2 other &&
+ git rebase --root --onto master work2 &&
+ git log --pretty=tformat:"%s" > rebased2 &&
+ test_cmp expect rebased2
+'
+
+test_expect_success 'pre-rebase got correct input (2)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+ git checkout -b stops1 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
+test_done
--
tg: (cb706e1..) t/rr-normal (depends on: origin/master t/rebase-hook-order)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* [PATCH v3.2] rebase: learn to rebase root commit
2009-01-02 23:45 ` [PATCH v3.1] " Thomas Rast
@ 2009-01-05 17:35 ` Thomas Rast
2009-01-06 8:19 ` Junio C Hamano
0 siblings, 1 reply; 27+ messages in thread
From: Thomas Rast @ 2009-01-05 17:35 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>. This option must be used with
--onto <newbase>, and causes commits that already exist in <newbase>
to be skipped. (Normal operation skips commits that already exist in
<upstream> instead.)
The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN. You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection. This previously had to be done by
cherry-picking the root commit manually.
Signed-off-by: Thomas Rast <trast@student.ethz.ch>
---
Since this is still in 'pu', can you replace it again? The test case
I designed for v3, to check that it also skips identical commits,
actually makes the _root_ commit a duplicate. I could sleep better at
night if the root commit was actually part of the rebase :-)
3/4 is not affected patch-wise, though it of course inherits the same
test history.
Thanks!
Interdiff:
>> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
>> index 1978512..dd91910 100755
>> --- a/t/t3412-rebase-root.sh
>> +++ b/t/t3412-rebase-root.sh
>> @@ -15,12 +15,12 @@ test_expect_success 'prepare repository' '
>> git commit -m 2 &&
>> git symbolic-ref HEAD refs/heads/other &&
>> rm .git/index &&
>> - echo 1 > A &&
>> - git add A &&
>> - git commit -m 1b &&
>> echo 3 > B &&
>> git add B &&
>> git commit -m 3 &&
>> + echo 1 > A &&
>> + git add A &&
>> + git commit -m 1b &&
>> echo 4 > B &&
>> git add B &&
>> git commit -m 4
git-rebase.sh | 52 ++++++++++++++++++++--------
t/t3412-rebase-root.sh | 86 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+), 15 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..d1083f1 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
# Copyright (c) 2005 Junio C Hamano.
#
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
LONG_USAGE='git-rebase replaces <branch> with a new branch of the
same name. When the --onto option is provided the new branch starts
out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
prec=4
verbose=
git_am_opt=
+rebase_root=
continue_merge () {
test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
-C*)
git_am_opt="$git_am_opt $1"
;;
+ --root)
+ rebase_root=t
+ ;;
-*)
usage
;;
@@ -344,17 +348,28 @@ case "$diff" in
;;
esac
+if test -z "$rebase_root"; then
# The upstream head must be given. Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
- die "invalid upstream $upstream_name"
+ upstream_name="$1"
+ shift
+ upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+ die "invalid upstream $upstream_name"
+ unset root_flag
+ upstream_arg="$upstream_name"
+else
+ test -z "$newbase" && die "--root must be used with --onto"
+ unset upstream_name
+ unset upstream
+ root_flag="--root"
+ upstream_arg="$root_flag"
+fi
# Make sure the branch to rebase onto is valid.
onto_name=${newbase-"$upstream_name"}
onto=$(git rev-parse --verify "${onto_name}^0") || exit
# If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook "$upstream_arg" "$@"
# If the branch to rebase is given, that is the branch we will rebase
# $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +377,16 @@ run_pre_rebase_hook ${1+"$@"}
# $head_name -- refs/heads/<that-branch> or "detached HEAD"
switch_to=
case "$#" in
-2)
+1)
# Is it "rebase other $branchname" or "rebase other $commit"?
- branch_name="$2"
- switch_to="$2"
+ branch_name="$1"
+ switch_to="$1"
- if git show-ref --verify --quiet -- "refs/heads/$2" &&
- branch=$(git rev-parse -q --verify "refs/heads/$2")
+ if git show-ref --verify --quiet -- "refs/heads/$1" &&
+ branch=$(git rev-parse -q --verify "refs/heads/$1")
then
- head_name="refs/heads/$2"
- elif branch=$(git rev-parse -q --verify "$2")
+ head_name="refs/heads/$1"
+ elif branch=$(git rev-parse -q --verify "$1")
then
head_name="detached HEAD"
else
@@ -393,7 +408,8 @@ case "$#" in
esac
orig_head=$branch
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or with --root,
+# everything leading up to $branch) on top of $onto
# Check if we are already based on $onto with linear history,
# but this should be done only when upstream and onto are the same.
@@ -429,10 +445,16 @@ then
exit 0
fi
+if test ! -z "$rebase_root"; then
+ revisions="$onto..$orig_head"
+else
+ revisions="$upstream..$orig_head"
+fi
+
if test -z "$do_merge"
then
git format-patch -k --stdout --full-index --ignore-if-in-upstream \
- "$upstream..$orig_head" |
+ $root_flag "$revisions" |
git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
move_to_original_branch
ret=$?
@@ -455,7 +477,7 @@ echo "$orig_head" > "$dotest/orig-head"
echo "$head_name" > "$dotest/head-name"
msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
do
msgnum=$(($msgnum + 1))
echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..dd91910
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1 &&
+ echo 2 > A &&
+ git add A &&
+ git commit -m 2 &&
+ git symbolic-ref HEAD refs/heads/other &&
+ rm .git/index &&
+ echo 3 > B &&
+ git add B &&
+ git commit -m 3 &&
+ echo 1 > A &&
+ git add A &&
+ git commit -m 1b &&
+ echo 4 > B &&
+ git add B &&
+ git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+ test_must_fail git rebase --root
+'
+
+test_expect_success 'setup pre-rebase hook' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+ git checkout -b work &&
+ git rebase --root --onto master &&
+ git log --pretty=tformat:"%s" > rebased &&
+ test_cmp expect rebased
+'
+
+test_expect_success 'pre-rebase got correct input (1)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+ git branch work2 other &&
+ git rebase --root --onto master work2 &&
+ git log --pretty=tformat:"%s" > rebased2 &&
+ test_cmp expect rebased2
+'
+
+test_expect_success 'pre-rebase got correct input (2)' '
+ test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+ mkdir -p .git/hooks &&
+ cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+ chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+ git checkout -b stops1 other &&
+ GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+ test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+ test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
+test_done
--
tg: (f62b77f..) t/rr-normal (depends on: origin/master t/rebase-hook-order)
^ permalink raw reply related [flat|nested] 27+ messages in thread
* Re: [PATCH v3.2] rebase: learn to rebase root commit
2009-01-05 17:35 ` [PATCH v3.2] " Thomas Rast
@ 2009-01-06 8:19 ` Junio C Hamano
0 siblings, 0 replies; 27+ messages in thread
From: Junio C Hamano @ 2009-01-06 8:19 UTC (permalink / raw)
To: Thomas Rast; +Cc: git
Thomas Rast <trast@student.ethz.ch> writes:
> Since this is still in 'pu', can you replace it again?
Thanks, done.
^ permalink raw reply [flat|nested] 27+ messages in thread
end of thread, other threads:[~2009-01-06 8:21 UTC | newest]
Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-29 16:45 [PATCH 0/3] rebase --root Thomas Rast
[not found] ` <cover.1230569041.git.trast@student.ethz.ch>
2008-12-29 16:45 ` rebase: learn to rebase root commit Thomas Rast
2008-12-29 16:45 ` rebase -i: " Thomas Rast
2008-12-29 21:49 ` Thomas Rast
2008-12-29 22:21 ` Boyd Stephen Smith Jr.
2008-12-30 12:23 ` Thomas Rast
2008-12-30 12:29 ` [PATCH v2 1/3] rebase: " Thomas Rast
2008-12-30 12:29 ` [PATCH v2 2/3] rebase -i: " Thomas Rast
2008-12-30 12:29 ` [PATCH v2 3/3] rebase: update documentation for --root Thomas Rast
2009-01-01 21:00 ` [PATCH v2 1/3] rebase: learn to rebase root commit Junio C Hamano
2009-01-02 18:58 ` Johannes Schindelin
2009-01-02 22:20 ` Thomas Rast
2009-01-02 22:28 ` [PATCH v3 1/4] rebase -i: execute hook only after argument checking Thomas Rast
2009-01-02 22:28 ` [PATCH v3 2/4] rebase: learn to rebase root commit Thomas Rast
2009-01-02 22:28 ` [PATCH v3 3/4] rebase -i: " Thomas Rast
2009-01-02 22:28 ` [PATCH v3 4/4] rebase: update documentation for --root Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 3/4] rebase -i: learn to rebase root commit Thomas Rast
2009-01-02 22:41 ` [INTERDIFF v3 2/4] rebase: " Thomas Rast
2009-01-02 23:06 ` [PATCH " Junio C Hamano
2009-01-02 23:45 ` [PATCH v3.1] " Thomas Rast
2009-01-05 17:35 ` [PATCH v3.2] " Thomas Rast
2009-01-06 8:19 ` Junio C Hamano
2009-01-02 22:49 ` [PATCH v2 1/3] " Junio C Hamano
2009-01-02 22:54 ` Thomas Rast
2009-01-02 23:07 ` Junio C Hamano
2008-12-30 8:22 ` rebase -i: " Junio C Hamano
2008-12-29 16:45 ` rebase: update documentation for --root Thomas Rast
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).