{"thread":{"id":"16911","subject":"rebase -i: learn to rebase root commit","startedAt":"2008-12-29T16:45:44Z","lastAt":"2009-01-06T08:19:22Z","messageCount":27,"participants":["Thomas Rast","Boyd Stephen Smith Jr.","Junio C Hamano","Johannes Schindelin"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"98899","messageId":"cover.1230568082.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":null,"subject":"[PATCH 0/3] rebase --root","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-29T16:45:44Z","receivedAt":"2008-12-29T16:45:44Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Inspired by f95ebf7 (Allow cherry-picking root commits, 2008-07-04),\nthis teaches git rebase to rebase everything up to the root commit(s).\n\nThe main use-case for this is if you hack on new history, then later\nnotice that you want to unroll the commits \"on\" a git-svn branch to\ndcommit them separately.  (If you just want to squash them, a merge\nwill do fine.)\n\nNote that --root (in both modes) requires --onto; you cannot rebase\n\"onto nothing\" to edit the root commit.  Such an option --onto-nothing\nmight be a worthwile feature however, since it would also allow\n\"detaching\" a set of commits from their parent history.\n\nBTW, while hacking this I noticed that there are two different tests\nt3409:\n\n  t3409-rebase-hook.sh\n  t3409-rebase-preserve-merges.sh\n\nIs this okay, or should one of them be renamed?\n\n\nThomas Rast (3):\n  rebase: learn to rebase root commit\n  rebase -i: learn to rebase root commit\n  rebase: update documentation for --root\n\n Documentation/git-rebase.txt |   17 +++++++---\n git-rebase--interactive.sh   |   53 +++++++++++++++++++++++++--------\n git-rebase.sh                |   51 ++++++++++++++++++++++----------\n t/t3412-rebase-root.sh       |   66 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 153 insertions(+), 34 deletions(-)\n create mode 100755 t/t3412-rebase-root.sh\n"},{"id":"98901","messageId":"e8008f8e16a28c83a4fc6984966c91733b138598.1230569041.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"cover.1230568082.git.trast@student.ethz.ch","subject":"rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-29T16:45:45Z","receivedAt":"2008-12-29T16:45:45Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase a new option --root, which instructs it to rebase the\nentire history leading up to <branch>.\n\nThe main use-case is with git-svn: suppose you start hacking (perhaps\noffline) on a new project, but later notice you want to commit this\nwork to SVN.  You will have to rebase the entire history, including\nthe root commit, on a (possibly empty) commit coming from git-svn, to\nestablish a history connection.  This previously had to be done by\ncherry-picking the root commit manually.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n git-rebase.sh          |   51 ++++++++++++++++++++++++++++++++--------------\n t/t3412-rebase-root.sh |   52 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 87 insertions(+), 16 deletions(-)\n create mode 100755 t/t3412-rebase-root.sh\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex ebd4df3..89de3c4 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2005 Junio C Hamano.\n #\n \n-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'\n+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'\n LONG_USAGE='git-rebase replaces <branch> with a new branch of the\n same name.  When the --onto option is provided the new branch starts\n out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>\n@@ -47,6 +47,7 @@ dotest=\"$GIT_DIR\"/rebase-merge\n prec=4\n verbose=\n git_am_opt=\n+rebase_root=\n \n continue_merge () {\n \ttest -n \"$prev_head\" || die \"prev_head must be defined\"\n@@ -297,6 +298,9 @@ do\n \t-C*)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -344,17 +348,23 @@ case \"$diff\" in\n \t;;\n esac\n \n+if test -z \"$rebase_root\"; then\n # The upstream head must be given.  Make sure it is valid.\n-upstream_name=\"$1\"\n-upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-    die \"invalid upstream $upstream_name\"\n+\tupstream_name=\"$1\"\n+\tshift\n+\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\tdie \"invalid upstream $upstream_name\"\n+fi\n+\n+test ! -z \"$rebase_root\" -a -z \"$newbase\" &&\n+\tdie \"--root must be used with --onto\"\n \n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${1+\"$@\"}\n+run_pre_rebase_hook ${upstream_name+\"$upstream_name\"} \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -362,16 +372,16 @@ run_pre_rebase_hook ${1+\"$@\"}\n # $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n switch_to=\n case \"$#\" in\n-2)\n+1)\n \t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n-\tbranch_name=\"$2\"\n-\tswitch_to=\"$2\"\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n \n-\tif git show-ref --verify --quiet -- \"refs/heads/$2\" &&\n-\t   branch=$(git rev-parse -q --verify \"refs/heads/$2\")\n+\tif git show-ref --verify --quiet -- \"refs/heads/$1\" &&\n+\t   branch=$(git rev-parse -q --verify \"refs/heads/$1\")\n \tthen\n-\t\thead_name=\"refs/heads/$2\"\n-\telif branch=$(git rev-parse -q --verify \"$2\")\n+\t\thead_name=\"refs/heads/$1\"\n+\telif branch=$(git rev-parse -q --verify \"$1\")\n \tthen\n \t\thead_name=\"detached HEAD\"\n \telse\n@@ -393,7 +403,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or simply $branch\n+# with --root) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -429,10 +440,18 @@ then\n \texit 0\n fi\n \n+if test ! -z \"$rebase_root\"; then\n+\trevisions=\"$orig_head\"\n+\tfp_flag=\"--root\"\n+else\n+\trevisions=\"$upstream..$orig_head\"\n+\tfp_flag=\"--ignore-if-in-upstream\"\n+fi\n+\n if test -z \"$do_merge\"\n then\n-\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t\t\"$upstream..$orig_head\" |\n+\tgit format-patch -k --stdout --full-index \"$fp_flag\" \\\n+\t\t\"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\n@@ -455,7 +474,7 @@ echo \"$orig_head\" > \"$dotest/orig-head\"\n echo \"$head_name\" > \"$dotest/head-name\"\n \n msgnum=0\n-for cmt in `git rev-list --reverse --no-merges \"$upstream..$orig_head\"`\n+for cmt in `git rev-list --reverse --no-merges \"$revisions\"`\n do\n \tmsgnum=$(($msgnum + 1))\n \techo \"$cmt\" > \"$dotest/cmt.$msgnum\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nnew file mode 100755\nindex 0000000..63ec5e6\n--- /dev/null\n+++ b/t/t3412-rebase-root.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='git rebase --root\n+\n+Tests if git rebase --root --onto <newparent> can rebase the root commit.\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'prepare repository' '\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1 &&\n+\techo 2 > A &&\n+\tgit add A &&\n+\tgit commit -m 2 &&\n+\tgit symbolic-ref HEAD refs/heads/other &&\n+\trm .git/index &&\n+\trm A &&\n+\techo 3 > B &&\n+\tgit add B &&\n+\tgit commit -m 3 &&\n+\techo 4 > B &&\n+\tgit add B &&\n+\tgit commit -m 4\n+'\n+\n+test_expect_success 'rebase --root expects --onto' '\n+\ttest_must_fail git rebase --root\n+'\n+\n+cat > expect <<EOF\n+4\n+3\n+2\n+1\n+EOF\n+\n+test_expect_success 'rebase --root --onto <newbase>' '\n+\tgit checkout -b work &&\n+\tgit rebase --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased &&\n+\ttest_cmp expect rebased\n+'\n+\n+test_expect_success 'rebase --root --onto <newbase> <branch>' '\n+\tgit branch work2 other &&\n+\tgit rebase --root --onto master work2 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased2 &&\n+\ttest_cmp expect rebased2\n+'\n+\n+test_done\n-- \n1.6.1.1.g4c1d9.dirty\n"},{"id":"98898","messageId":"5d0be6d15bbdaa8b95c1df161b67ecd4120d7ce4.1230569041.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"e8008f8e16a28c83a4fc6984966c91733b138598.1230569041.git.trast@student.ethz.ch","subject":"rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-29T16:45:46Z","receivedAt":"2008-12-29T16:45:46Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase -i a new option --root, which instructs it to rebase\nthe entire history leading up to <branch>.  This is mainly for\nsymmetry with ordinary git-rebase; it cannot be used to edit the root\ncommit in-place (it requires --onto).\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n git-rebase--interactive.sh |   53 +++++++++++++++++++++++++++++++++----------\n t/t3412-rebase-root.sh     |   14 +++++++++++\n 2 files changed, 54 insertions(+), 13 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c8b0861..f29b5ee 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -27,6 +27,7 @@ continue           continue rebasing process\n abort              abort rebasing process and restore original branch\n skip               skip current patch and continue rebasing process\n no-verify          override pre-rebase hook from stopping the operation\n+root               rebase all reachable commmits up to the root(s)\n \"\n \n . git-sh-setup\n@@ -44,6 +45,7 @@ STRATEGY=\n ONTO=\n VERBOSE=\n OK_TO_SKIP_PRE_REBASE=\n+REBASE_ROOT=\n \n GIT_CHERRY_PICK_HELP=\"  After resolving the conflicts,\n mark the corrected paths with 'git add <paths>', and\n@@ -154,6 +156,11 @@ pick_one () {\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$REWRITTEN\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n+\tif test ! -z \"$REBASE_ROOT\"\n+\tthen\n+\t\toutput git cherry-pick \"$@\"\n+\t\treturn\n+\tfi\n \tparent_sha1=$(git rev-parse --verify $sha1^) ||\n \t\tdie \"Could not get the parent of $sha1\"\n \tcurrent_sha1=$(git rev-parse --verify HEAD)\n@@ -443,6 +450,7 @@ get_saved_options () {\n \ttest -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n \ttest -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n \ttest -f \"$DOTEST\"/verbose && VERBOSE=t\n+\ttest ! -s \"$DOTEST\"/upstream && REBASE_ROOT=t\n }\n \n while test $# != 0\n@@ -547,6 +555,9 @@ first and then run 'git rebase --continue' again.\"\n \t-i)\n \t\t# yeah, we know\n \t\t;;\n+\t--root)\n+\t\tREBASE_ROOT=t\n+\t\t;;\n \t--onto)\n \t\tshift\n \t\tONTO=$(git rev-parse --verify \"$1\") ||\n@@ -555,7 +566,7 @@ first and then run 'git rebase --continue' again.\"\n \t--)\n \t\tshift\n \t\trun_pre_rebase_hook ${1+\"$@\"}\n-\t\ttest $# -eq 1 -o $# -eq 2 || usage\n+\t\ttest ! -z \"$REBASE_ROOT\" -o $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n \n@@ -566,15 +577,22 @@ first and then run 'git rebase --continue' again.\"\n \n \t\trequire_clean_work_tree\n \n-\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n-\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\tthen\n+\t\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n+\t\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n+\t\t\tshift\n+\t\telse\n+\t\t\ttest -z \"$ONTO\" &&\n+\t\t\t\tdie \"You must specify --onto when using --root\"\n+\t\tfi\n \n-\t\tif test ! -z \"$2\"\n+\t\tif test ! -z \"$1\"\n \t\tthen\n-\t\t\toutput git show-ref --verify --quiet \"refs/heads/$2\" ||\n-\t\t\t\tdie \"Invalid branchname: $2\"\n-\t\t\toutput git checkout \"$2\" ||\n-\t\t\t\tdie \"Could not checkout $2\"\n+\t\t\toutput git show-ref --verify --quiet \"refs/heads/$1\" ||\n+\t\t\t\tdie \"Invalid branchname: $1\"\n+\t\t\toutput git checkout \"$1\" ||\n+\t\t\t\tdie \"Could not checkout $1\"\n \t\tfi\n \n \t\tHEAD=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n@@ -613,12 +631,21 @@ first and then run 'git rebase --continue' again.\"\n \t\t\tMERGES_OPTION=\"--no-merges --cherry-pick\"\n \t\tfi\n \n-\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short $ONTO)\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\t# this is now equivalent to ! -z \"$UPSTREAM\"\n+\t\tthen\n+\t\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n+\t\t\tREVISIONS=$UPSTREAM...$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD\n+\t\telse\n+\t\t\tREVISIONS=$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTHEAD\n+\t\tfi\n \t\tgit rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \\\n \t\t\t--abbrev=7 --reverse --left-right --topo-order \\\n-\t\t\t$UPSTREAM...$HEAD | \\\n+\t\t\t$REVISIONS | \\\n \t\t\tsed -n \"s/^>//p\" | while read shortsha1 rest\n \t\tdo\n \t\t\tif test t != \"$PRESERVE_MERGES\"\n@@ -647,11 +674,11 @@ first and then run 'git rebase --continue' again.\"\n \t\tthen\n \t\t\tmkdir \"$DROPPED\"\n \t\t\t# Save all non-cherry-picked changes\n-\t\t\tgit rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \\\n+\t\t\tgit rev-list $REVISIONS --left-right --cherry-pick | \\\n \t\t\t\tsed -n \"s/^>//p\" > \"$DOTEST\"/not-cherry-picks\n \t\t\t# Now all commits and note which ones are missing in\n \t\t\t# not-cherry-picks and hence being dropped\n-\t\t\tgit rev-list $UPSTREAM..$HEAD |\n+\t\t\tgit rev-list $REVISIONS |\n \t\t\twhile read rev\n \t\t\tdo\n \t\t\t\tif test -f \"$REWRITTEN\"/$rev -a \"$(grep \"$rev\" \"$DOTEST\"/not-cherry-picks)\" = \"\"\n@@ -670,7 +697,7 @@ first and then run 'git rebase --continue' again.\"\n \t\ttest -s \"$TODO\" || echo noop >> \"$TODO\"\n \t\tcat >> \"$TODO\" << EOF\n \n-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n+# Rebase $SHORTREVISIONS onto $SHORTONTO\n #\n # Commands:\n #  p, pick = use commit\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 63ec5e6..bb44a52 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -49,4 +49,18 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \ttest_cmp expect rebased2\n '\n \n+test_expect_success 'rebase -i --root --onto <newbase>' '\n+\tgit checkout -b work3 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased3 &&\n+\ttest_cmp expect rebased3\n+'\n+\n+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '\n+\tgit branch work4 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master work4 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased4 &&\n+\ttest_cmp expect rebased4\n+'\n+\n test_done\n-- \n1.6.1.1.g4c1d9.dirty\n"},{"id":"98900","messageId":"17ca8054dfa6d82df9e7e7f40f2f9183d3039056.1230569041.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"5d0be6d15bbdaa8b95c1df161b67ecd4120d7ce4.1230569041.git.trast@student.ethz.ch","subject":"rebase: update documentation for --root","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-29T16:45:47Z","receivedAt":"2008-12-29T16:45:47Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since the new option depends on --onto and omission of <upstream>, use\na separate invocation style, and omit most options to save space.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/git-rebase.txt |   17 ++++++++++++-----\n 1 files changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex c8ad86a..3268cd2 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head\n SYNOPSIS\n --------\n [verse]\n-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n-\t[-s <strategy> | --strategy=<strategy>] [--no-verify]\n-\t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n-\t[--onto <newbase>] <upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] [--onto <newbase>]\n+\t<upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] --onto <newbase>\n+\t--root [<branch>]\n+\n 'git rebase' --continue | --skip | --abort\n \n DESCRIPTION\n@@ -22,7 +23,8 @@ it remains on the current branch.\n \n All changes made by commits in the current branch but that are not\n in <upstream> are saved to a temporary area.  This is the same set\n-of commits that would be shown by `git log <upstream>..HEAD`.\n+of commits that would be shown by `git log <upstream>..HEAD` (or\n+`git log HEAD`, if --root is specified).\n \n The current branch is reset to <upstream>, or <newbase> if the\n --onto option was supplied.  This has the exact same effect as\n@@ -255,6 +257,11 @@ OPTIONS\n --preserve-merges::\n \tInstead of ignoring merges, try to recreate them.\n \n+--root::\n+\tRebase all commits reachable from <branch>, instead of\n+\tlimiting them with an <upstream>.  This allows you to rebase\n+\tthe root commit(s) on a branch.  Must be used with --onto.\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n1.6.1.1.g4c1d9.dirty\n"},{"id":"98917","messageId":"200812292249.45900.trast@student.ethz.ch","threadId":"16911","inReplyTo":"5d0be6d15bbdaa8b95c1df161b67ecd4120d7ce4.1230569041.git.trast@student.ethz.ch","subject":"Re: rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-29T21:49:42Z","receivedAt":"2008-12-29T21:49:42Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Thomas Rast wrote:\n> Teach git-rebase -i a new option --root, which instructs it to rebase\n> the entire history leading up to <branch>.  This is mainly for\n> symmetry with ordinary git-rebase; it cannot be used to edit the root\n> commit in-place (it requires --onto).\n\nActually, I forgot the \"rebase -i -p\" code path, which dies if --root\nis used with -p.  Apologies.\n\nSo for now, consider this broken and RFC: is there any sensible\nuse/interpretation of -p --root that I'm missing?  Or should it just\ndisallow this combination?\n\n\n[I also seem to manage to shoot myself with format-patch & topgit\nevery time, no matter how trivial the issue.]\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n\n"},{"id":"98922","messageId":"200812291621.35732.bss@iguanasuicide.net","threadId":"16911","inReplyTo":"200812292249.45900.trast@student.ethz.ch","subject":"Re: rebase -i: learn to rebase root commit","fromName":"Boyd Stephen Smith Jr.","fromEmail":"bss@iguanasuicide.net","sentAt":"2008-12-29T22:21:31Z","receivedAt":"2008-12-29T22:21:31Z","isPatch":false,"sender":{"key":"bss@iguanasuicide.net","avatar":"https://gravatar.com/avatar/84b95eeff194b816c1568b1339e63e4b229825298664a9037b9f1ec713ead1e3?d=mp&s=160"},"body":"On Monday 2008 December 29 15:49:42 Thomas Rast wrote:\n> Thomas Rast wrote:\n> > Teach git-rebase -i a new option --root, which instructs it to rebase\n> > the entire history leading up to <branch>.  This is mainly for\n> > symmetry with ordinary git-rebase; it cannot be used to edit the root\n> > commit in-place (it requires --onto).\n>\n> Actually, I forgot the \"rebase -i -p\" code path, which dies if --root\n> is used with -p.  Apologies.\n>\n> So for now, consider this broken and RFC: is there any sensible\n> use/interpretation of -p --root that I'm missing?  Or should it just\n> disallow this combination?\n\nHere's the interpretation that *I* come up with for -p --root used together:\nThe commit with no parents (OLD_ROOT) is rebased as if -p were not given, call \nthe resulting commit NEW_ROOT.  Then, the rebase continues as if \"--onto \nNEW_ROOT OLD_ROOT <branch>\" was specified instead of \"--onto=NEW_ROOT^ --root \n<branch>\".\n\nBasically, --root only changes how the first commit is handled, which I think \nis consistent with other uses of --root.  It's also similar to cherry-picking \nthe first commit, follwed by a non-root rebase, which I think is also \nconsistent with the intention of --root.\n-- \nBoyd Stephen Smith Jr.                     ,= ,-_-. =. \nbss@iguanasuicide.net                     ((_/)o o(\\_))\nICQ: 514984 YM/AIM: DaTwinkDaddy           `-'(. .)`-' \nhttp://iguanasuicide.net/                      \\_/     \n"},{"id":"98955","messageId":"7vhc4m3we5.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"200812292249.45900.trast@student.ethz.ch","subject":"Re: rebase -i: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-12-30T08:22:26Z","receivedAt":"2008-12-30T08:22:26Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> ... is there any sensible\n> use/interpretation of -p --root that I'm missing?  Or should it just\n> disallow this combination?\n\nIf --root is about replaying all the history, wouldn't people want to use\nit together with -p to reconstruct the whole history as a substitute for\nfilter-branch?  IOW, I have a suspicion that they most likely should go\ntogether.\n\nI never felt a need to rebase deep down to --root myself anyway, so I am a\nbad judge for people's needs on this topic, though.\n"},{"id":"98966","messageId":"200812301323.30550.trast@student.ethz.ch","threadId":"16911","inReplyTo":"200812291621.35732.bss@iguanasuicide.net","subject":"Re: rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-30T12:23:27Z","receivedAt":"2008-12-30T12:23:27Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Boyd Stephen Smith Jr. wrote:\n> Here's the interpretation that *I* come up with for -p --root used together:\n> The commit with no parents (OLD_ROOT) is rebased as if -p were not given, call \n> the resulting commit NEW_ROOT.  Then, the rebase continues as if \"--onto \n> NEW_ROOT OLD_ROOT <branch>\" was specified instead of \"--onto=NEW_ROOT^ --root \n> <branch>\".\n\nI like this logic, but it feels inconsistent as soon as there are\nseveral root commits.  (This may be somewhat academic, since any repo\nwith several roots should also be able to cope with a merge...)\n\nSome digging into the -p code shows that it knows which commits were\nrewritten, and which were untouched.  It rewrites such that _all_\ncommits in $(git merge-base --all $branch $upstream) are rewritten to\nlook like $onto instead, i.e., all their occurrences in parent lists\nof commits are rewritten to $onto.  All other commits are only\nrewritten if they have a parent that was rewritten.\n\nSo I think one sane way is to define a virtual parent 'root', and\nthink of parentless commits as having the (sole) parent 'root'.  Then\nwe can rewrite such that 'root' becomes $onto, i.e., all occurrences\nof 'root' in parent lists become $onto, consistent with the normal\noperation.  (For the other commits, the same rule as above is\napplied.)\n\nOf course this just boils down to saying that _all_ root commits\nreachable from $branch are rewritten to have $onto as their parent.\nSubsequently, all other commits will also be rewritten because they\nall must have at least one rewritten parent.\n\n> Basically, --root only changes how the first commit is handled, which I think \n> is consistent with other uses of --root.  It's also similar to cherry-picking \n> the first commit, follwed by a non-root rebase, which I think is also \n> consistent with the intention of --root.\n\nI believe this remark still holds if there is only a single root\ncommit on $branch.\n\nI will reroll with an updated 2/3 shortly.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n\n"},{"id":"98969","messageId":"7b2902d36a4790670f20f786d4ea2e26052a6e71.1230639970.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"200812301323.30550.trast@student.ethz.ch","subject":"[PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-30T12:29:46Z","receivedAt":"2008-12-30T12:29:46Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase a new option --root, which instructs it to rebase the\nentire history leading up to <branch>.\n\nThe main use-case is with git-svn: suppose you start hacking (perhaps\noffline) on a new project, but later notice you want to commit this\nwork to SVN.  You will have to rebase the entire history, including\nthe root commit, on a (possibly empty) commit coming from git-svn, to\nestablish a history connection.  This previously had to be done by\ncherry-picking the root commit manually.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nNo changes since v1.\n\n git-rebase.sh          |   51 ++++++++++++++++++++++++++++++++--------------\n t/t3412-rebase-root.sh |   52 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 87 insertions(+), 16 deletions(-)\n create mode 100755 t/t3412-rebase-root.sh\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex ebd4df3..89de3c4 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2005 Junio C Hamano.\n #\n \n-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'\n+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'\n LONG_USAGE='git-rebase replaces <branch> with a new branch of the\n same name.  When the --onto option is provided the new branch starts\n out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>\n@@ -47,6 +47,7 @@ dotest=\"$GIT_DIR\"/rebase-merge\n prec=4\n verbose=\n git_am_opt=\n+rebase_root=\n \n continue_merge () {\n \ttest -n \"$prev_head\" || die \"prev_head must be defined\"\n@@ -297,6 +298,9 @@ do\n \t-C*)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -344,17 +348,23 @@ case \"$diff\" in\n \t;;\n esac\n \n+if test -z \"$rebase_root\"; then\n # The upstream head must be given.  Make sure it is valid.\n-upstream_name=\"$1\"\n-upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-    die \"invalid upstream $upstream_name\"\n+\tupstream_name=\"$1\"\n+\tshift\n+\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\tdie \"invalid upstream $upstream_name\"\n+fi\n+\n+test ! -z \"$rebase_root\" -a -z \"$newbase\" &&\n+\tdie \"--root must be used with --onto\"\n \n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${1+\"$@\"}\n+run_pre_rebase_hook ${upstream_name+\"$upstream_name\"} \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -362,16 +372,16 @@ run_pre_rebase_hook ${1+\"$@\"}\n # $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n switch_to=\n case \"$#\" in\n-2)\n+1)\n \t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n-\tbranch_name=\"$2\"\n-\tswitch_to=\"$2\"\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n \n-\tif git show-ref --verify --quiet -- \"refs/heads/$2\" &&\n-\t   branch=$(git rev-parse -q --verify \"refs/heads/$2\")\n+\tif git show-ref --verify --quiet -- \"refs/heads/$1\" &&\n+\t   branch=$(git rev-parse -q --verify \"refs/heads/$1\")\n \tthen\n-\t\thead_name=\"refs/heads/$2\"\n-\telif branch=$(git rev-parse -q --verify \"$2\")\n+\t\thead_name=\"refs/heads/$1\"\n+\telif branch=$(git rev-parse -q --verify \"$1\")\n \tthen\n \t\thead_name=\"detached HEAD\"\n \telse\n@@ -393,7 +403,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or simply $branch\n+# with --root) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -429,10 +440,18 @@ then\n \texit 0\n fi\n \n+if test ! -z \"$rebase_root\"; then\n+\trevisions=\"$orig_head\"\n+\tfp_flag=\"--root\"\n+else\n+\trevisions=\"$upstream..$orig_head\"\n+\tfp_flag=\"--ignore-if-in-upstream\"\n+fi\n+\n if test -z \"$do_merge\"\n then\n-\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t\t\"$upstream..$orig_head\" |\n+\tgit format-patch -k --stdout --full-index \"$fp_flag\" \\\n+\t\t\"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\n@@ -455,7 +474,7 @@ echo \"$orig_head\" > \"$dotest/orig-head\"\n echo \"$head_name\" > \"$dotest/head-name\"\n \n msgnum=0\n-for cmt in `git rev-list --reverse --no-merges \"$upstream..$orig_head\"`\n+for cmt in `git rev-list --reverse --no-merges \"$revisions\"`\n do\n \tmsgnum=$(($msgnum + 1))\n \techo \"$cmt\" > \"$dotest/cmt.$msgnum\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nnew file mode 100755\nindex 0000000..63ec5e6\n--- /dev/null\n+++ b/t/t3412-rebase-root.sh\n@@ -0,0 +1,52 @@\n+#!/bin/sh\n+\n+test_description='git rebase --root\n+\n+Tests if git rebase --root --onto <newparent> can rebase the root commit.\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'prepare repository' '\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1 &&\n+\techo 2 > A &&\n+\tgit add A &&\n+\tgit commit -m 2 &&\n+\tgit symbolic-ref HEAD refs/heads/other &&\n+\trm .git/index &&\n+\trm A &&\n+\techo 3 > B &&\n+\tgit add B &&\n+\tgit commit -m 3 &&\n+\techo 4 > B &&\n+\tgit add B &&\n+\tgit commit -m 4\n+'\n+\n+test_expect_success 'rebase --root expects --onto' '\n+\ttest_must_fail git rebase --root\n+'\n+\n+cat > expect <<EOF\n+4\n+3\n+2\n+1\n+EOF\n+\n+test_expect_success 'rebase --root --onto <newbase>' '\n+\tgit checkout -b work &&\n+\tgit rebase --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased &&\n+\ttest_cmp expect rebased\n+'\n+\n+test_expect_success 'rebase --root --onto <newbase> <branch>' '\n+\tgit branch work2 other &&\n+\tgit rebase --root --onto master work2 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased2 &&\n+\ttest_cmp expect rebased2\n+'\n+\n+test_done\n-- \n1.6.1.20.g7f5c5.dirty\n"},{"id":"98967","messageId":"3c7d0d7e84b6841041d23e16bf04d65ebea503a4.1230639970.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"7b2902d36a4790670f20f786d4ea2e26052a6e71.1230639970.git.trast@student.ethz.ch","subject":"[PATCH v2 2/3] rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-30T12:29:47Z","receivedAt":"2008-12-30T12:29:47Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase -i a new option --root, which instructs it to rebase\nthe entire history leading up to <branch>.  This is mainly for\nsymmetry with ordinary git-rebase; it cannot be used to edit the root\ncommit in-place (it requires --onto).\n\nIn the normal mode of operation, this is fairly straightforward.  We\nrun cherry-pick in a loop, and cherry-pick has supported picking the\nroot commit since f95ebf7 (Allow cherry-picking root commits,\n2008-07-04).\n\nIn --preserve-merges mode, we track the mapping from old to rewritten\ncommits and use it to update the parent list of each commit.  In this\ncase, we define 'rebase -i -p --root --onto $onto $branch' to rewrite\nthe parent list of all root commit(s) on $branch to contain $onto\ninstead.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nChanges since v1: also supports -p --root, with tests.\n\n git-rebase--interactive.sh |   99 +++++++++++++++++++++++++++++++------------\n t/t3412-rebase-root.sh     |   82 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 153 insertions(+), 28 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c8b0861..d6f54eb 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -27,6 +27,7 @@ continue           continue rebasing process\n abort              abort rebasing process and restore original branch\n skip               skip current patch and continue rebasing process\n no-verify          override pre-rebase hook from stopping the operation\n+root               rebase all reachable commmits up to the root(s)\n \"\n \n . git-sh-setup\n@@ -44,6 +45,7 @@ STRATEGY=\n ONTO=\n VERBOSE=\n OK_TO_SKIP_PRE_REBASE=\n+REBASE_ROOT=\n \n GIT_CHERRY_PICK_HELP=\"  After resolving the conflicts,\n mark the corrected paths with 'git add <paths>', and\n@@ -154,6 +156,11 @@ pick_one () {\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$REWRITTEN\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n+\tif test ! -z \"$REBASE_ROOT\"\n+\tthen\n+\t\toutput git cherry-pick \"$@\"\n+\t\treturn\n+\tfi\n \tparent_sha1=$(git rev-parse --verify $sha1^) ||\n \t\tdie \"Could not get the parent of $sha1\"\n \tcurrent_sha1=$(git rev-parse --verify HEAD)\n@@ -197,7 +204,11 @@ pick_one_preserving_merges () {\n \n \t# rewrite parents; if none were rewritten, we can fast-forward.\n \tnew_parents=\n-\tpend=\" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\"\n+\tpend=\" $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)\"\n+\tif test \"$pend\" = \" \"\n+\tthen\n+\t\tpend=\" root\"\n+\tfi\n \twhile [ \"$pend\" != \"\" ]\n \tdo\n \t\tp=$(expr \"$pend\" : ' \\([^ ]*\\)')\n@@ -443,6 +454,7 @@ get_saved_options () {\n \ttest -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n \ttest -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n \ttest -f \"$DOTEST\"/verbose && VERBOSE=t\n+\ttest ! -s \"$DOTEST\"/upstream && REBASE_ROOT=t\n }\n \n while test $# != 0\n@@ -547,6 +559,9 @@ first and then run 'git rebase --continue' again.\"\n \t-i)\n \t\t# yeah, we know\n \t\t;;\n+\t--root)\n+\t\tREBASE_ROOT=t\n+\t\t;;\n \t--onto)\n \t\tshift\n \t\tONTO=$(git rev-parse --verify \"$1\") ||\n@@ -555,7 +570,7 @@ first and then run 'git rebase --continue' again.\"\n \t--)\n \t\tshift\n \t\trun_pre_rebase_hook ${1+\"$@\"}\n-\t\ttest $# -eq 1 -o $# -eq 2 || usage\n+\t\ttest ! -z \"$REBASE_ROOT\" -o $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n \n@@ -566,15 +581,22 @@ first and then run 'git rebase --continue' again.\"\n \n \t\trequire_clean_work_tree\n \n-\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n-\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\tthen\n+\t\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n+\t\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n+\t\t\tshift\n+\t\telse\n+\t\t\ttest -z \"$ONTO\" &&\n+\t\t\t\tdie \"You must specify --onto when using --root\"\n+\t\tfi\n \n-\t\tif test ! -z \"$2\"\n+\t\tif test ! -z \"$1\"\n \t\tthen\n-\t\t\toutput git show-ref --verify --quiet \"refs/heads/$2\" ||\n-\t\t\t\tdie \"Invalid branchname: $2\"\n-\t\t\toutput git checkout \"$2\" ||\n-\t\t\t\tdie \"Could not checkout $2\"\n+\t\t\toutput git show-ref --verify --quiet \"refs/heads/$1\" ||\n+\t\t\t\tdie \"Invalid branchname: $1\"\n+\t\t\toutput git checkout \"$1\" ||\n+\t\t\t\tdie \"Could not checkout $1\"\n \t\tfi\n \n \t\tHEAD=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n@@ -598,12 +620,19 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t# This ensures that commits on merged, but otherwise\n \t\t\t# unrelated side branches are left alone. (Think \"X\"\n \t\t\t# in the man page's example.)\n-\t\t\tmkdir \"$REWRITTEN\" &&\n-\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n-\t\t\tdo\n-\t\t\t\techo $ONTO > \"$REWRITTEN\"/$c ||\n+\t\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\tthen\n+\t\t\t\tmkdir \"$REWRITTEN\" &&\n+\t\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n+\t\t\t\tdo\n+\t\t\t\t\techo $ONTO > \"$REWRITTEN\"/$c ||\n+\t\t\t\t\t\tdie \"Could not init rewritten commits\"\n+\t\t\t\tdone\n+\t\t\telse\n+\t\t\t\tmkdir \"$REWRITTEN\" &&\n+\t\t\t\techo $ONTO > \"$REWRITTEN\"/root ||\n \t\t\t\t\tdie \"Could not init rewritten commits\"\n-\t\t\tdone\n+\t\t\tfi\n \t\t\t# No cherry-pick because our first pass is to determine\n \t\t\t# parents to rewrite and skipping dropped commits would\n \t\t\t# prematurely end our probe\n@@ -613,12 +642,21 @@ first and then run 'git rebase --continue' again.\"\n \t\t\tMERGES_OPTION=\"--no-merges --cherry-pick\"\n \t\tfi\n \n-\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short $ONTO)\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\t# this is now equivalent to ! -z \"$UPSTREAM\"\n+\t\tthen\n+\t\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n+\t\t\tREVISIONS=$UPSTREAM...$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD\n+\t\telse\n+\t\t\tREVISIONS=$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTHEAD\n+\t\tfi\n \t\tgit rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \\\n \t\t\t--abbrev=7 --reverse --left-right --topo-order \\\n-\t\t\t$UPSTREAM...$HEAD | \\\n+\t\t\t$REVISIONS | \\\n \t\t\tsed -n \"s/^>//p\" | while read shortsha1 rest\n \t\tdo\n \t\t\tif test t != \"$PRESERVE_MERGES\"\n@@ -626,14 +664,19 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\techo \"pick $shortsha1 $rest\" >> \"$TODO\"\n \t\t\telse\n \t\t\t\tsha1=$(git rev-parse $shortsha1)\n-\t\t\t\tpreserve=t\n-\t\t\t\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n-\t\t\t\tdo\n-\t\t\t\t\tif test -f \"$REWRITTEN\"/$p -a \\( $p != $UPSTREAM -o $sha1 = $first_after_upstream \\)\n-\t\t\t\t\tthen\n-\t\t\t\t\t\tpreserve=f\n-\t\t\t\t\tfi\n-\t\t\t\tdone\n+\t\t\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\t\tthen\n+\t\t\t\t\tpreserve=t\n+\t\t\t\t\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)\n+\t\t\t\t\tdo\n+\t\t\t\t\t\tif test -f \"$REWRITTEN\"/$p -a \\( $p != $UPSTREAM -o $sha1 = $first_after_upstream \\)\n+\t\t\t\t\t\tthen\n+\t\t\t\t\t\t\tpreserve=f\n+\t\t\t\t\t\tfi\n+\t\t\t\t\tdone\n+\t\t\t\telse\n+\t\t\t\t\tpreserve=f\n+\t\t\t\tfi\n \t\t\t\tif test f = \"$preserve\"\n \t\t\t\tthen\n \t\t\t\t\ttouch \"$REWRITTEN\"/$sha1\n@@ -647,11 +690,11 @@ first and then run 'git rebase --continue' again.\"\n \t\tthen\n \t\t\tmkdir \"$DROPPED\"\n \t\t\t# Save all non-cherry-picked changes\n-\t\t\tgit rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \\\n+\t\t\tgit rev-list $REVISIONS --left-right --cherry-pick | \\\n \t\t\t\tsed -n \"s/^>//p\" > \"$DOTEST\"/not-cherry-picks\n \t\t\t# Now all commits and note which ones are missing in\n \t\t\t# not-cherry-picks and hence being dropped\n-\t\t\tgit rev-list $UPSTREAM..$HEAD |\n+\t\t\tgit rev-list $REVISIONS |\n \t\t\twhile read rev\n \t\t\tdo\n \t\t\t\tif test -f \"$REWRITTEN\"/$rev -a \"$(grep \"$rev\" \"$DOTEST\"/not-cherry-picks)\" = \"\"\n@@ -660,7 +703,7 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\t\t# not worthwhile, we don't want to track its multiple heads,\n \t\t\t\t\t# just the history of its first-parent for others that will\n \t\t\t\t\t# be rebasing on top of it\n-\t\t\t\t\tgit rev-list --parents -1 $rev | cut -d' ' -f2 > \"$DROPPED\"/$rev\n+\t\t\t\t\tgit rev-list --parents -1 $rev | cut -d' ' -s -f2 > \"$DROPPED\"/$rev\n \t\t\t\t\tshort=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)\n \t\t\t\t\tgrep -v \"^[a-z][a-z]* $short\" <\"$TODO\" > \"${TODO}2\" ; mv \"${TODO}2\" \"$TODO\"\n \t\t\t\t\trm \"$REWRITTEN\"/$rev\n@@ -670,7 +713,7 @@ first and then run 'git rebase --continue' again.\"\n \t\ttest -s \"$TODO\" || echo noop >> \"$TODO\"\n \t\tcat >> \"$TODO\" << EOF\n \n-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n+# Rebase $SHORTREVISIONS onto $SHORTONTO\n #\n # Commands:\n #  p, pick = use commit\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 63ec5e6..c845dfc 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -49,4 +49,86 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \ttest_cmp expect rebased2\n '\n \n+test_expect_success 'rebase -i --root --onto <newbase>' '\n+\tgit checkout -b work3 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased3 &&\n+\ttest_cmp expect rebased3\n+'\n+\n+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '\n+\tgit branch work4 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master work4 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased4 &&\n+\ttest_cmp expect rebased4\n+'\n+\n+test_expect_success 'rebase -i -p with linear history' '\n+\tgit checkout -b work5 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased5 &&\n+\ttest_cmp expect rebased5\n+'\n+\n+test_expect_success 'set up merge history' '\n+\tgit checkout other^ &&\n+\tgit checkout -b side &&\n+\techo 5 > C &&\n+\tgit add C &&\n+\tgit commit -m 5 &&\n+\tgit checkout other &&\n+\tgit merge side\n+'\n+\n+sed 's/#/ /g' > expect-side <<'EOF'\n+*   Merge branch 'side' into other\n+|\\##\n+| * 5\n+* | 4\n+|/##\n+* 3\n+* 2\n+* 1\n+EOF\n+\n+test_expect_success 'rebase -i -p with merge' '\n+\tgit checkout -b work6 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --graph --topo-order --pretty=tformat:\"%s\" > rebased6 &&\n+\ttest_cmp expect-side rebased6\n+'\n+\n+test_expect_success 'set up second root and merge' '\n+\tgit symbolic-ref HEAD refs/heads/third &&\n+\trm .git/index &&\n+\trm A B C &&\n+\techo 6 > D &&\n+\tgit add D &&\n+\tgit commit -m 6 &&\n+\tgit checkout other &&\n+\tgit merge third\n+'\n+\n+sed 's/#/ /g' > expect-third <<'EOF'\n+*   Merge branch 'third' into other\n+|\\##\n+| * 6\n+* |   Merge branch 'side' into other\n+|\\ \\##\n+| * | 5\n+* | | 4\n+|/ /##\n+* | 3\n+|/##\n+* 2\n+* 1\n+EOF\n+\n+test_expect_success 'rebase -i -p with two roots' '\n+\tgit checkout -b work7 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --graph --topo-order --pretty=tformat:\"%s\" > rebased7 &&\n+\ttest_cmp expect-third rebased7\n+'\n+\n test_done\n-- \n1.6.1.20.g7f5c5.dirty\n"},{"id":"98968","messageId":"e9bb872d202b13ac41cffe11f3ebf768cd40dd41.1230639970.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"3c7d0d7e84b6841041d23e16bf04d65ebea503a4.1230639970.git.trast@student.ethz.ch","subject":"[PATCH v2 3/3] rebase: update documentation for --root","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2008-12-30T12:29:48Z","receivedAt":"2008-12-30T12:29:48Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since the new option depends on --onto and omission of <upstream>, use\na separate invocation style, and omit most options to save space.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nChanged since v1: remark about the effect of --root --preserve-merges.\n\n Documentation/git-rebase.txt |   19 ++++++++++++++-----\n 1 files changed, 14 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex c8ad86a..e3b4b83 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head\n SYNOPSIS\n --------\n [verse]\n-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n-\t[-s <strategy> | --strategy=<strategy>] [--no-verify]\n-\t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n-\t[--onto <newbase>] <upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] [--onto <newbase>]\n+\t<upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] --onto <newbase>\n+\t--root [<branch>]\n+\n 'git rebase' --continue | --skip | --abort\n \n DESCRIPTION\n@@ -22,7 +23,8 @@ it remains on the current branch.\n \n All changes made by commits in the current branch but that are not\n in <upstream> are saved to a temporary area.  This is the same set\n-of commits that would be shown by `git log <upstream>..HEAD`.\n+of commits that would be shown by `git log <upstream>..HEAD` (or\n+`git log HEAD`, if --root is specified).\n \n The current branch is reset to <upstream>, or <newbase> if the\n --onto option was supplied.  This has the exact same effect as\n@@ -255,6 +257,13 @@ OPTIONS\n --preserve-merges::\n \tInstead of ignoring merges, try to recreate them.\n \n+--root::\n+\tRebase all commits reachable from <branch>, instead of\n+\tlimiting them with an <upstream>.  This allows you to rebase\n+\tthe root commit(s) on a branch.  Must be used with --onto.\n+\tWhen used together with --preserve-merges, 'all' root commits\n+\twill be rewritten to have <newbase> as parent instead.\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n1.6.1.20.g7f5c5.dirty\n"},{"id":"99109","messageId":"7v4p0iivwh.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"7b2902d36a4790670f20f786d4ea2e26052a6e71.1230639970.git.trast@student.ethz.ch","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-01T21:00:46Z","receivedAt":"2009-01-01T21:00:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Teach git-rebase a new option --root, which instructs it to rebase the\n> entire history leading up to <branch>.\n>\n> The main use-case is with git-svn: suppose you start hacking (perhaps\n> offline) on a new project, but later notice you want to commit this\n> work to SVN.  You will have to rebase the entire history, including\n> the root commit, on a (possibly empty) commit coming from git-svn, to\n> establish a history connection.  This previously had to be done by\n> cherry-picking the root commit manually.\n\nI like what this series tries to do.  Using the --root option is probably\na more natural way to do what people often do with the \"add graft and\nfilter-branch the whole history once\" procedure.\n\nBut it somewhat feels sad if the \"main\" use-case for this is to start your\nproject in git and then migrate away by feeding your history to subversion\n;-).\n\n> @@ -344,17 +348,23 @@ case \"$diff\" in\n>  \t;;\n>  esac\n>  \n> +if test -z \"$rebase_root\"; then\n>  # The upstream head must be given.  Make sure it is valid.\n> -upstream_name=\"$1\"\n> -upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n> -    die \"invalid upstream $upstream_name\"\n> +\tupstream_name=\"$1\"\n> +\tshift\n> +\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n> +\tdie \"invalid upstream $upstream_name\"\n> +fi\n> +\n> +test ! -z \"$rebase_root\" -a -z \"$newbase\" &&\n> +\tdie \"--root must be used with --onto\"\n\nThis is much easier to read if it were:\n\n\tif test -z \"$rebase_root\"\n        then\n        \t... do the upstream_name/upstream thing, such as\n                upstream_name=\"$1\"\n                ...\n\telse\n        \t... do the rebase_root thing, including\n                unset upstream\n                unset upstream_name\n                test -z \"$newbase\" && die \"--root without --onto\"\n                ...\n\tfi\n\n(Mental note.  You shifted positional parameters and the remainders need\nto be adjusted, which you seem to have done).\n\n>  # Make sure the branch to rebase onto is valid.\n>  onto_name=${newbase-\"$upstream_name\"}\n>  onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n>  \n>  # If a hook exists, give it a chance to interrupt\n> -run_pre_rebase_hook ${1+\"$@\"}\n> +run_pre_rebase_hook ${upstream_name+\"$upstream_name\"} \"$@\"\n\nI do not think ${upstream_name+\"$upstream_name\"} is a good check to begin\nwith, because presense of it does not necessarily mean the command was\ninvoked without --root; it could have come from the environment of the\ninvoker (hence the suggestion to unset the variable explicitly).\n\nAnd I do not think this is a good way to extend the calling convention of\nthe hook, either.  pre-rebase-hook used to always take upstream and\noptionally the explicit branch name.  When --root is given, your code will\ngive the hook a single parameter which is the explicit branch name\n(i.e. \"we will switch to this branch and rebase it, are you Ok with it?\"),\nbut the hook will mistakenly think you are feeding the fork-point commit.\n\nBecause an old pre-rebase-hook cannot verify --root case correctly anyway\nand needs to be updated, how about doing 'run_pre_rebase_hook --root \"$@\"'\nwhen --root was given?\n\n> @@ -393,7 +403,8 @@ case \"$#\" in\n>  esac\n>  orig_head=$branch\n>  \n> -# Now we are rebasing commits $upstream..$branch on top of $onto\n> +# Now we are rebasing commits $upstream..$branch (or simply $branch\n> +# with --root) on top of $onto\n\n\"or simply everything leading to $branch if --root is given\"?\n\n>  # Check if we are already based on $onto with linear history,\n>  # but this should be done only when upstream and onto are the same.\n> @@ -429,10 +440,18 @@ then\n>  \texit 0\n>  fi\n>  \n> +if test ! -z \"$rebase_root\"; then\n> +\trevisions=\"$orig_head\"\n> +\tfp_flag=\"--root\"\n> +else\n> +\trevisions=\"$upstream..$orig_head\"\n> +\tfp_flag=\"--ignore-if-in-upstream\"\n> +fi\n\nHmph, the reason why --ignore-if-in-upstream is irrelevant when --root is\ngiven is because...?\n\n> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\n> new file mode 100755\n> index 0000000..63ec5e6\n> --- /dev/null\n> +++ b/t/t3412-rebase-root.sh\n> @@ -0,0 +1,52 @@\n> +#!/bin/sh\n> +\n> +test_description='git rebase --root\n> ...\n> +test_done\n\nIncluding tests for the pre-rebase-hook would be nice.\n"},{"id":"99191","messageId":"alpine.DEB.1.00.0901021957400.30769@pacific.mpi-cbg.de","threadId":"16911","inReplyTo":"7v4p0iivwh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-01-02T18:58:59Z","receivedAt":"2009-01-02T18:58:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Thu, 1 Jan 2009, Junio C Hamano wrote:\n\n> Thomas Rast <trast@student.ethz.ch> writes:\n> \n> > Teach git-rebase a new option --root, which instructs it to rebase the\n> > entire history leading up to <branch>.\n> >\n> > The main use-case is with git-svn: suppose you start hacking (perhaps\n> > offline) on a new project, but later notice you want to commit this\n> > work to SVN.  You will have to rebase the entire history, including\n> > the root commit, on a (possibly empty) commit coming from git-svn, to\n> > establish a history connection.  This previously had to be done by\n> > cherry-picking the root commit manually.\n> \n> I like what this series tries to do.  Using the --root option is probably\n> a more natural way to do what people often do with the \"add graft and\n> filter-branch the whole history once\" procedure.\n> \n> But it somewhat feels sad if the \"main\" use-case for this is to start your\n> project in git and then migrate away by feeding your history to subversion\n> ;-).\n\nFWIW I had a single case where I could have used something like this \nmyself, in my whole life.  It was when I started to write \ngit-edit-patch-series.sh in its own repository, only to realize at the end \nthat I should have started it in a topic branch in my git.git tree.\n\nCiao,\nDscho\n"},{"id":"99215","messageId":"200901022320.14055.trast@student.ethz.ch","threadId":"16911","inReplyTo":"7v4p0iivwh.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:20:02Z","receivedAt":"2009-01-02T22:20:02Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> > The main use-case is with git-svn: [...]\n> \n> I like what this series tries to do.  Using the --root option is probably\n> a more natural way to do what people often do with the \"add graft and\n> filter-branch the whole history once\" procedure.\n\nTheir uses are somewhat disjoint, as grafting only works if the\ngrafted parent has an empty tree.  Otherwise the grafted child will\nappear to revert the entire history leading to it.  Rebase OTOH\nchanges the committers.\n\n> But it somewhat feels sad if the \"main\" use-case for this is to start your\n> project in git and then migrate away by feeding your history to subversion\n> ;-).\n\nYou can remove that paragraph if you don't want to \"support\" SVN in\ngit.git ;-)\n\n> >  # Make sure the branch to rebase onto is valid.\n> >  onto_name=${newbase-\"$upstream_name\"}\n> >  onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n> >  \n> >  # If a hook exists, give it a chance to interrupt\n> > -run_pre_rebase_hook ${1+\"$@\"}\n> > +run_pre_rebase_hook ${upstream_name+\"$upstream_name\"} \"$@\"\n> \n> I do not think ${upstream_name+\"$upstream_name\"} is a good check to begin\n> with, because presense of it does not necessarily mean the command was\n> invoked without --root; it could have come from the environment of the\n> invoker (hence the suggestion to unset the variable explicitly).\n\nGood catch, thanks.\n\nI'm still not sure what ${1+\"$@\"} was about by the way.  The most\nauthoritative reference I can find is\n\n  http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_02\n\nwhich says\n\n  If there are no positional parameters, the expansion of '@' shall\n  generate zero fields, even when '@' is double-quoted.\n\n('man bash' agrees.)\n\n> And I do not think this is a good way to extend the calling convention of\n> the hook, either.  pre-rebase-hook used to always take upstream and\n> optionally the explicit branch name.  When --root is given, your code will\n> give the hook a single parameter which is the explicit branch name\n> (i.e. \"we will switch to this branch and rebase it, are you Ok with it?\"),\n> but the hook will mistakenly think you are feeding the fork-point commit.\n> \n> Because an old pre-rebase-hook cannot verify --root case correctly anyway\n> and needs to be updated, how about doing 'run_pre_rebase_hook --root \"$@\"'\n> when --root was given?\n\nTrue.  I noticed that I had to fix the positionals, but forgot about\nthe hook afterwards.  v3 implements this as you suggested.\n\n> > +if test ! -z \"$rebase_root\"; then\n> > +\trevisions=\"$orig_head\"\n> > +\tfp_flag=\"--root\"\n> > +else\n> > +\trevisions=\"$upstream..$orig_head\"\n> > +\tfp_flag=\"--ignore-if-in-upstream\"\n> > +fi\n> \n> Hmph, the reason why --ignore-if-in-upstream is irrelevant when --root is\n> given is because...?\n\nWell, originally because format-patch didn't like the argument.\nThanks for prodding however, $onto..$head makes sort of makes sense\nhere and I discovered that even $onto...$head works, which is used in\n'rebase -i'.\n\nHowever, it's still a change of semantics: With --root we now ignore\npatches that are already contained in $onto, as opposed to patches\nthat were already in $upstream in normal operation.  It seems sensible\nto do it this way, and perhaps even normal rebase should do it the\nsame way... if only format-patch would support it.\n\nThanks for the review! v3 upcoming.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n\n"},{"id":"99216","messageId":"6a754e4198413c4051a6085c5e5baab163835463.1230935095.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"200901022320.14055.trast@student.ethz.ch","subject":"[PATCH v3 1/4] rebase -i: execute hook only after argument checking","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:28:26Z","receivedAt":"2009-01-02T22:28:26Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Previously, the pre-rebase-hook would be launched before we knew if\nthe <upstream> [<branch>] arguments were supplied.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThis is a quick fix and not really part of the series.  2/4 textually\ndepends on it, however, so I'm sending it along.\n\n git-rebase--interactive.sh |    5 +++--\n 1 files changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex c8b0861..2c668cd 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -554,7 +554,6 @@ first and then run 'git rebase --continue' again.\"\n \t\t;;\n \t--)\n \t\tshift\n-\t\trun_pre_rebase_hook ${1+\"$@\"}\n \t\ttest $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n@@ -562,11 +561,13 @@ first and then run 'git rebase --continue' again.\"\n \t\tgit var GIT_COMMITTER_IDENT >/dev/null ||\n \t\t\tdie \"You need to set your committer info first\"\n \n+\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n+\t\trun_pre_rebase_hook ${1+\"$@\"}\n+\n \t\tcomment_for_reflog start\n \n \t\trequire_clean_work_tree\n \n-\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n \t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n \n \t\tif test ! -z \"$2\"\n-- \n1.6.1.71.gaaa47.dirty\n"},{"id":"99218","messageId":"7c74d8be216b4667f470e34644c4aa26dcfe0cfb.1230935095.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"6a754e4198413c4051a6085c5e5baab163835463.1230935095.git.trast@student.ethz.ch","subject":"[PATCH v3 2/4] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:28:27Z","receivedAt":"2009-01-02T22:28:27Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase a new option --root, which instructs it to rebase the\nentire history leading up to <branch>.  This option must be used with\n--onto <newbase>, and causes commits that already exist in <newbase>\nto be skipped.  (Normal operation skips commits that already exist in\n<upstream> instead.)\n\nThe main use-case is with git-svn: suppose you start hacking (perhaps\noffline) on a new project, but later notice you want to commit this\nwork to SVN.  You will have to rebase the entire history, including\nthe root commit, on a (possibly empty) commit coming from git-svn, to\nestablish a history connection.  This previously had to be done by\ncherry-picking the root commit manually.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n git-rebase.sh          |   50 +++++++++++++++++++--------\n t/t3412-rebase-root.sh |   86 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 121 insertions(+), 15 deletions(-)\n create mode 100755 t/t3412-rebase-root.sh\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex ebd4df3..9437e51 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2005 Junio C Hamano.\n #\n \n-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'\n+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'\n LONG_USAGE='git-rebase replaces <branch> with a new branch of the\n same name.  When the --onto option is provided the new branch starts\n out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>\n@@ -47,6 +47,7 @@ dotest=\"$GIT_DIR\"/rebase-merge\n prec=4\n verbose=\n git_am_opt=\n+rebase_root=\n \n continue_merge () {\n \ttest -n \"$prev_head\" || die \"prev_head must be defined\"\n@@ -297,6 +298,9 @@ do\n \t-C*)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -344,17 +348,26 @@ case \"$diff\" in\n \t;;\n esac\n \n+if test -z \"$rebase_root\"; then\n # The upstream head must be given.  Make sure it is valid.\n-upstream_name=\"$1\"\n-upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-    die \"invalid upstream $upstream_name\"\n+\tupstream_name=\"$1\"\n+\tshift\n+\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\tdie \"invalid upstream $upstream_name\"\n+\tunset root_flag\n+else\n+\ttest -z \"$newbase\" && die \"--root must be used with --onto\"\n+\tunset upstream_name\n+\tunset upstream\n+\troot_flag=\"--root\"\n+fi\n \n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${1+\"$@\"}\n+run_pre_rebase_hook $root_flag $upstream_name \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -362,16 +375,16 @@ run_pre_rebase_hook ${1+\"$@\"}\n # $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n switch_to=\n case \"$#\" in\n-2)\n+1)\n \t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n-\tbranch_name=\"$2\"\n-\tswitch_to=\"$2\"\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n \n-\tif git show-ref --verify --quiet -- \"refs/heads/$2\" &&\n-\t   branch=$(git rev-parse -q --verify \"refs/heads/$2\")\n+\tif git show-ref --verify --quiet -- \"refs/heads/$1\" &&\n+\t   branch=$(git rev-parse -q --verify \"refs/heads/$1\")\n \tthen\n-\t\thead_name=\"refs/heads/$2\"\n-\telif branch=$(git rev-parse -q --verify \"$2\")\n+\t\thead_name=\"refs/heads/$1\"\n+\telif branch=$(git rev-parse -q --verify \"$1\")\n \tthen\n \t\thead_name=\"detached HEAD\"\n \telse\n@@ -393,7 +406,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or with --root,\n+# everything leading up to $branch) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -429,10 +443,16 @@ then\n \texit 0\n fi\n \n+if test ! -z \"$rebase_root\"; then\n+\trevisions=\"$onto..$orig_head\"\n+else\n+\trevisions=\"$upstream..$orig_head\"\n+fi\n+\n if test -z \"$do_merge\"\n then\n \tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t\t\"$upstream..$orig_head\" |\n+\t\t$root_flag \"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\n@@ -455,7 +475,7 @@ echo \"$orig_head\" > \"$dotest/orig-head\"\n echo \"$head_name\" > \"$dotest/head-name\"\n \n msgnum=0\n-for cmt in `git rev-list --reverse --no-merges \"$upstream..$orig_head\"`\n+for cmt in `git rev-list --reverse --no-merges \"$revisions\"`\n do\n \tmsgnum=$(($msgnum + 1))\n \techo \"$cmt\" > \"$dotest/cmt.$msgnum\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nnew file mode 100755\nindex 0000000..1978512\n--- /dev/null\n+++ b/t/t3412-rebase-root.sh\n@@ -0,0 +1,86 @@\n+#!/bin/sh\n+\n+test_description='git rebase --root\n+\n+Tests if git rebase --root --onto <newparent> can rebase the root commit.\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'prepare repository' '\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1 &&\n+\techo 2 > A &&\n+\tgit add A &&\n+\tgit commit -m 2 &&\n+\tgit symbolic-ref HEAD refs/heads/other &&\n+\trm .git/index &&\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1b &&\n+\techo 3 > B &&\n+\tgit add B &&\n+\tgit commit -m 3 &&\n+\techo 4 > B &&\n+\tgit add B &&\n+\tgit commit -m 4\n+'\n+\n+test_expect_success 'rebase --root expects --onto' '\n+\ttest_must_fail git rebase --root\n+'\n+\n+test_expect_success 'setup pre-rebase hook' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+cat > expect <<EOF\n+4\n+3\n+2\n+1\n+EOF\n+\n+test_expect_success 'rebase --root --onto <newbase>' '\n+\tgit checkout -b work &&\n+\tgit rebase --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased &&\n+\ttest_cmp expect rebased\n+'\n+\n+test_expect_success 'pre-rebase got correct input (1)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n+test_expect_success 'rebase --root --onto <newbase> <branch>' '\n+\tgit branch work2 other &&\n+\tgit rebase --root --onto master work2 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased2 &&\n+\ttest_cmp expect rebased2\n+'\n+\n+test_expect_success 'pre-rebase got correct input (2)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n+'\n+\n+test_expect_success 'setup pre-rebase hook that fails' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+false\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase' '\n+\tgit checkout -b stops1 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops1\n+\ttest 0 = $(git rev-list other...stops1 | wc -l)\n+'\n+\n+test_done\n-- \n1.6.1.71.gaaa47.dirty\n"},{"id":"99219","messageId":"43e09eaf2b9a9a3805b9262957ece32190ae4c32.1230935095.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"7c74d8be216b4667f470e34644c4aa26dcfe0cfb.1230935095.git.trast@student.ethz.ch","subject":"[PATCH v3 3/4] rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:28:28Z","receivedAt":"2009-01-02T22:28:28Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase -i a new option --root, which instructs it to rebase\nthe entire history leading up to <branch>.  This is mainly for\nsymmetry with ordinary git-rebase; it cannot be used to edit the root\ncommit in-place (it requires --onto <newbase>).  Commits that already\nexist in <newbase> are skipped.\n\nIn the normal mode of operation, this is fairly straightforward.  We\nrun cherry-pick in a loop, and cherry-pick has supported picking the\nroot commit since f95ebf7 (Allow cherry-picking root commits,\n2008-07-04).\n\nIn --preserve-merges mode, we track the mapping from old to rewritten\ncommits and use it to update the parent list of each commit.  In this\ncase, we define 'rebase -i -p --root --onto $onto $branch' to rewrite\nthe parent list of all root commit(s) on $branch to contain $onto\ninstead.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n git-rebase--interactive.sh |  109 +++++++++++++++++++++++++++++++------------\n t/t3412-rebase-root.sh     |  101 ++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 179 insertions(+), 31 deletions(-)\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 2c668cd..14d3e38 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -27,6 +27,7 @@ continue           continue rebasing process\n abort              abort rebasing process and restore original branch\n skip               skip current patch and continue rebasing process\n no-verify          override pre-rebase hook from stopping the operation\n+root               rebase all reachable commmits up to the root(s)\n \"\n \n . git-sh-setup\n@@ -44,6 +45,7 @@ STRATEGY=\n ONTO=\n VERBOSE=\n OK_TO_SKIP_PRE_REBASE=\n+REBASE_ROOT=\n \n GIT_CHERRY_PICK_HELP=\"  After resolving the conflicts,\n mark the corrected paths with 'git add <paths>', and\n@@ -154,6 +156,11 @@ pick_one () {\n \toutput git rev-parse --verify $sha1 || die \"Invalid commit name: $sha1\"\n \ttest -d \"$REWRITTEN\" &&\n \t\tpick_one_preserving_merges \"$@\" && return\n+\tif test ! -z \"$REBASE_ROOT\"\n+\tthen\n+\t\toutput git cherry-pick \"$@\"\n+\t\treturn\n+\tfi\n \tparent_sha1=$(git rev-parse --verify $sha1^) ||\n \t\tdie \"Could not get the parent of $sha1\"\n \tcurrent_sha1=$(git rev-parse --verify HEAD)\n@@ -197,7 +204,11 @@ pick_one_preserving_merges () {\n \n \t# rewrite parents; if none were rewritten, we can fast-forward.\n \tnew_parents=\n-\tpend=\" $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\"\n+\tpend=\" $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)\"\n+\tif test \"$pend\" = \" \"\n+\tthen\n+\t\tpend=\" root\"\n+\tfi\n \twhile [ \"$pend\" != \"\" ]\n \tdo\n \t\tp=$(expr \"$pend\" : ' \\([^ ]*\\)')\n@@ -227,7 +238,9 @@ pick_one_preserving_merges () {\n \t\t\tif test -f \"$DROPPED\"/$p\n \t\t\tthen\n \t\t\t\tfast_forward=f\n-\t\t\t\tpend=\" $(cat \"$DROPPED\"/$p)$pend\"\n+\t\t\t\treplacement=\"$(cat \"$DROPPED\"/$p)\"\n+\t\t\t\ttest -z \"$replacement\" && replacement=root\n+\t\t\t\tpend=\" $replacement$pend\"\n \t\t\telse\n \t\t\t\tnew_parents=\"$new_parents $p\"\n \t\t\tfi\n@@ -443,6 +456,7 @@ get_saved_options () {\n \ttest -d \"$REWRITTEN\" && PRESERVE_MERGES=t\n \ttest -f \"$DOTEST\"/strategy && STRATEGY=\"$(cat \"$DOTEST\"/strategy)\"\n \ttest -f \"$DOTEST\"/verbose && VERBOSE=t\n+\ttest ! -s \"$DOTEST\"/upstream && REBASE_ROOT=t\n }\n \n while test $# != 0\n@@ -547,6 +561,9 @@ first and then run 'git rebase --continue' again.\"\n \t-i)\n \t\t# yeah, we know\n \t\t;;\n+\t--root)\n+\t\tREBASE_ROOT=t\n+\t\t;;\n \t--onto)\n \t\tshift\n \t\tONTO=$(git rev-parse --verify \"$1\") ||\n@@ -554,28 +571,36 @@ first and then run 'git rebase --continue' again.\"\n \t\t;;\n \t--)\n \t\tshift\n-\t\ttest $# -eq 1 -o $# -eq 2 || usage\n+\t\ttest ! -z \"$REBASE_ROOT\" -o $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n \n \t\tgit var GIT_COMMITTER_IDENT >/dev/null ||\n \t\t\tdie \"You need to set your committer info first\"\n \n-\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n-\t\trun_pre_rebase_hook ${1+\"$@\"}\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\tthen\n+\t\t\tUPSTREAM_ARG=\"$1\"\n+\t\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n+\t\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n+\t\t\tshift\n+\t\telse\n+\t\t\tUPSTREAM_ARG=--root\n+\t\t\ttest -z \"$ONTO\" &&\n+\t\t\t\tdie \"You must specify --onto when using --root\"\n+\t\tfi\n+\t\trun_pre_rebase_hook \"$UPSTREAM_ARG\" \"$@\"\n \n \t\tcomment_for_reflog start\n \n \t\trequire_clean_work_tree\n \n-\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n-\n-\t\tif test ! -z \"$2\"\n+\t\tif test ! -z \"$1\"\n \t\tthen\n-\t\t\toutput git show-ref --verify --quiet \"refs/heads/$2\" ||\n-\t\t\t\tdie \"Invalid branchname: $2\"\n-\t\t\toutput git checkout \"$2\" ||\n-\t\t\t\tdie \"Could not checkout $2\"\n+\t\t\toutput git show-ref --verify --quiet \"refs/heads/$1\" ||\n+\t\t\t\tdie \"Invalid branchname: $1\"\n+\t\t\toutput git checkout \"$1\" ||\n+\t\t\t\tdie \"Could not checkout $1\"\n \t\tfi\n \n \t\tHEAD=$(git rev-parse --verify HEAD) || die \"No HEAD?\"\n@@ -599,12 +624,19 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t# This ensures that commits on merged, but otherwise\n \t\t\t# unrelated side branches are left alone. (Think \"X\"\n \t\t\t# in the man page's example.)\n-\t\t\tmkdir \"$REWRITTEN\" &&\n-\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n-\t\t\tdo\n-\t\t\t\techo $ONTO > \"$REWRITTEN\"/$c ||\n+\t\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\tthen\n+\t\t\t\tmkdir \"$REWRITTEN\" &&\n+\t\t\t\tfor c in $(git merge-base --all $HEAD $UPSTREAM)\n+\t\t\t\tdo\n+\t\t\t\t\techo $ONTO > \"$REWRITTEN\"/$c ||\n+\t\t\t\t\t\tdie \"Could not init rewritten commits\"\n+\t\t\t\tdone\n+\t\t\telse\n+\t\t\t\tmkdir \"$REWRITTEN\" &&\n+\t\t\t\techo $ONTO > \"$REWRITTEN\"/root ||\n \t\t\t\t\tdie \"Could not init rewritten commits\"\n-\t\t\tdone\n+\t\t\tfi\n \t\t\t# No cherry-pick because our first pass is to determine\n \t\t\t# parents to rewrite and skipping dropped commits would\n \t\t\t# prematurely end our probe\n@@ -614,12 +646,21 @@ first and then run 'git rebase --continue' again.\"\n \t\t\tMERGES_OPTION=\"--no-merges --cherry-pick\"\n \t\tfi\n \n-\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n \t\tSHORTHEAD=$(git rev-parse --short $HEAD)\n \t\tSHORTONTO=$(git rev-parse --short $ONTO)\n+\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\t# this is now equivalent to ! -z \"$UPSTREAM\"\n+\t\tthen\n+\t\t\tSHORTUPSTREAM=$(git rev-parse --short $UPSTREAM)\n+\t\t\tREVISIONS=$UPSTREAM...$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD\n+\t\telse\n+\t\t\tREVISIONS=$ONTO...$HEAD\n+\t\t\tSHORTREVISIONS=$SHORTHEAD\n+\t\tfi\n \t\tgit rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \\\n \t\t\t--abbrev=7 --reverse --left-right --topo-order \\\n-\t\t\t$UPSTREAM...$HEAD | \\\n+\t\t\t$REVISIONS | \\\n \t\t\tsed -n \"s/^>//p\" | while read shortsha1 rest\n \t\tdo\n \t\t\tif test t != \"$PRESERVE_MERGES\"\n@@ -627,14 +668,19 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\techo \"pick $shortsha1 $rest\" >> \"$TODO\"\n \t\t\telse\n \t\t\t\tsha1=$(git rev-parse $shortsha1)\n-\t\t\t\tpreserve=t\n-\t\t\t\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)\n-\t\t\t\tdo\n-\t\t\t\t\tif test -f \"$REWRITTEN\"/$p -a \\( $p != $UPSTREAM -o $sha1 = $first_after_upstream \\)\n-\t\t\t\t\tthen\n-\t\t\t\t\t\tpreserve=f\n-\t\t\t\t\tfi\n-\t\t\t\tdone\n+\t\t\t\tif test -z \"$REBASE_ROOT\"\n+\t\t\t\tthen\n+\t\t\t\t\tpreserve=t\n+\t\t\t\t\tfor p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)\n+\t\t\t\t\tdo\n+\t\t\t\t\t\tif test -f \"$REWRITTEN\"/$p -a \\( $p != $UPSTREAM -o $sha1 = $first_after_upstream \\)\n+\t\t\t\t\t\tthen\n+\t\t\t\t\t\t\tpreserve=f\n+\t\t\t\t\t\tfi\n+\t\t\t\t\tdone\n+\t\t\t\telse\n+\t\t\t\t\tpreserve=f\n+\t\t\t\tfi\n \t\t\t\tif test f = \"$preserve\"\n \t\t\t\tthen\n \t\t\t\t\ttouch \"$REWRITTEN\"/$sha1\n@@ -648,11 +694,11 @@ first and then run 'git rebase --continue' again.\"\n \t\tthen\n \t\t\tmkdir \"$DROPPED\"\n \t\t\t# Save all non-cherry-picked changes\n-\t\t\tgit rev-list $UPSTREAM...$HEAD --left-right --cherry-pick | \\\n+\t\t\tgit rev-list $REVISIONS --left-right --cherry-pick | \\\n \t\t\t\tsed -n \"s/^>//p\" > \"$DOTEST\"/not-cherry-picks\n \t\t\t# Now all commits and note which ones are missing in\n \t\t\t# not-cherry-picks and hence being dropped\n-\t\t\tgit rev-list $UPSTREAM..$HEAD |\n+\t\t\tgit rev-list $REVISIONS |\n \t\t\twhile read rev\n \t\t\tdo\n \t\t\t\tif test -f \"$REWRITTEN\"/$rev -a \"$(grep \"$rev\" \"$DOTEST\"/not-cherry-picks)\" = \"\"\n@@ -661,17 +707,18 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\t\t# not worthwhile, we don't want to track its multiple heads,\n \t\t\t\t\t# just the history of its first-parent for others that will\n \t\t\t\t\t# be rebasing on top of it\n-\t\t\t\t\tgit rev-list --parents -1 $rev | cut -d' ' -f2 > \"$DROPPED\"/$rev\n+\t\t\t\t\tgit rev-list --parents -1 $rev | cut -d' ' -s -f2 > \"$DROPPED\"/$rev\n \t\t\t\t\tshort=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)\n \t\t\t\t\tgrep -v \"^[a-z][a-z]* $short\" <\"$TODO\" > \"${TODO}2\" ; mv \"${TODO}2\" \"$TODO\"\n \t\t\t\t\trm \"$REWRITTEN\"/$rev\n \t\t\t\tfi\n \t\t\tdone\n \t\tfi\n+\n \t\ttest -s \"$TODO\" || echo noop >> \"$TODO\"\n \t\tcat >> \"$TODO\" << EOF\n \n-# Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO\n+# Rebase $SHORTREVISIONS onto $SHORTONTO\n #\n # Commands:\n #  p, pick = use commit\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 1978512..cbf3414 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -67,6 +67,100 @@ test_expect_success 'pre-rebase got correct input (2)' '\n \ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n '\n \n+test_expect_success 'rebase -i --root --onto <newbase>' '\n+\tgit checkout -b work3 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased3 &&\n+\ttest_cmp expect rebased3\n+'\n+\n+test_expect_success 'pre-rebase got correct input (3)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n+test_expect_success 'rebase -i --root --onto <newbase> <branch>' '\n+\tgit branch work4 other &&\n+\tGIT_EDITOR=: git rebase -i --root --onto master work4 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased4 &&\n+\ttest_cmp expect rebased4\n+'\n+\n+test_expect_success 'pre-rebase got correct input (4)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work4\n+'\n+\n+test_expect_success 'rebase -i -p with linear history' '\n+\tgit checkout -b work5 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased5 &&\n+\ttest_cmp expect rebased5\n+'\n+\n+test_expect_success 'pre-rebase got correct input (5)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n+test_expect_success 'set up merge history' '\n+\tgit checkout other^ &&\n+\tgit checkout -b side &&\n+\techo 5 > C &&\n+\tgit add C &&\n+\tgit commit -m 5 &&\n+\tgit checkout other &&\n+\tgit merge side\n+'\n+\n+sed 's/#/ /g' > expect-side <<'EOF'\n+*   Merge branch 'side' into other\n+|\\##\n+| * 5\n+* | 4\n+|/##\n+* 3\n+* 2\n+* 1\n+EOF\n+\n+test_expect_success 'rebase -i -p with merge' '\n+\tgit checkout -b work6 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --graph --topo-order --pretty=tformat:\"%s\" > rebased6 &&\n+\ttest_cmp expect-side rebased6\n+'\n+\n+test_expect_success 'set up second root and merge' '\n+\tgit symbolic-ref HEAD refs/heads/third &&\n+\trm .git/index &&\n+\trm A B C &&\n+\techo 6 > D &&\n+\tgit add D &&\n+\tgit commit -m 6 &&\n+\tgit checkout other &&\n+\tgit merge third\n+'\n+\n+sed 's/#/ /g' > expect-third <<'EOF'\n+*   Merge branch 'third' into other\n+|\\##\n+| * 6\n+* |   Merge branch 'side' into other\n+|\\ \\##\n+| * | 5\n+* | | 4\n+|/ /##\n+* | 3\n+|/##\n+* 2\n+* 1\n+EOF\n+\n+test_expect_success 'rebase -i -p with two roots' '\n+\tgit checkout -b work7 other &&\n+\tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n+\tgit log --graph --topo-order --pretty=tformat:\"%s\" > rebased7 &&\n+\ttest_cmp expect-third rebased7\n+'\n+\n test_expect_success 'setup pre-rebase hook that fails' '\n \tmkdir -p .git/hooks &&\n \tcat >.git/hooks/pre-rebase <<EOF &&\n@@ -83,4 +177,11 @@ test_expect_success 'pre-rebase hook stops rebase' '\n \ttest 0 = $(git rev-list other...stops1 | wc -l)\n '\n \n+test_expect_success 'pre-rebase hook stops rebase -i' '\n+\tgit checkout -b stops2 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops2\n+\ttest 0 = $(git rev-list other...stops2 | wc -l)\n+'\n+\n test_done\n-- \n1.6.1.71.gaaa47.dirty\n"},{"id":"99217","messageId":"9d771e75cb9b50937d968995ed33a6f483b0567b.1230935095.git.trast@student.ethz.ch","threadId":"16911","inReplyTo":"43e09eaf2b9a9a3805b9262957ece32190ae4c32.1230935095.git.trast@student.ethz.ch","subject":"[PATCH v3 4/4] rebase: update documentation for --root","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:28:29Z","receivedAt":"2009-01-02T22:28:29Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Since the new option depends on --onto and omission of <upstream>, use\na separate invocation style, and omit most options to save space.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/git-rebase.txt |   21 ++++++++++++++++-----\n 1 files changed, 16 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex c8ad86a..3d6d429 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -8,10 +8,11 @@ git-rebase - Forward-port local commits to the updated upstream head\n SYNOPSIS\n --------\n [verse]\n-'git rebase' [-i | --interactive] [-v | --verbose] [-m | --merge]\n-\t[-s <strategy> | --strategy=<strategy>] [--no-verify]\n-\t[-C<n>] [ --whitespace=<option>] [-p | --preserve-merges]\n-\t[--onto <newbase>] <upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] [--onto <newbase>]\n+\t<upstream> [<branch>]\n+'git rebase' [-i | --interactive] [options] --onto <newbase>\n+\t--root [<branch>]\n+\n 'git rebase' --continue | --skip | --abort\n \n DESCRIPTION\n@@ -22,7 +23,8 @@ it remains on the current branch.\n \n All changes made by commits in the current branch but that are not\n in <upstream> are saved to a temporary area.  This is the same set\n-of commits that would be shown by `git log <upstream>..HEAD`.\n+of commits that would be shown by `git log <upstream>..HEAD` (or\n+`git log HEAD`, if --root is specified).\n \n The current branch is reset to <upstream>, or <newbase> if the\n --onto option was supplied.  This has the exact same effect as\n@@ -255,6 +257,15 @@ OPTIONS\n --preserve-merges::\n \tInstead of ignoring merges, try to recreate them.\n \n+--root::\n+\tRebase all commits reachable from <branch>, instead of\n+\tlimiting them with an <upstream>.  This allows you to rebase\n+\tthe root commit(s) on a branch.  Must be used with --onto, and\n+\twill skip changes already contained in <newbase> (instead of\n+\t<upstream>).  When used together with --preserve-merges, 'all'\n+\troot commits will be rewritten to have <newbase> as parent\n+\tinstead.\n+\n include::merge-strategies.txt[]\n \n NOTES\n-- \n1.6.1.71.gaaa47.dirty\n"},{"id":"99222","messageId":"200901022341.36562.trast@student.ethz.ch","threadId":"16911","inReplyTo":"7c74d8be216b4667f470e34644c4aa26dcfe0cfb.1230935095.git.trast@student.ethz.ch","subject":"[INTERDIFF v3 2/4] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:41:32Z","receivedAt":"2009-01-02T22:41:32Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"The interdiff to v2.\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex 89de3c4..9437e51 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -354,17 +354,20 @@ if test -z \"$rebase_root\"; then\n \tshift\n \tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n \tdie \"invalid upstream $upstream_name\"\n+\tunset root_flag\n+else\n+\ttest -z \"$newbase\" && die \"--root must be used with --onto\"\n+\tunset upstream_name\n+\tunset upstream\n+\troot_flag=\"--root\"\n fi\n \n-test ! -z \"$rebase_root\" -a -z \"$newbase\" &&\n-\tdie \"--root must be used with --onto\"\n-\n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${upstream_name+\"$upstream_name\"} \"$@\"\n+run_pre_rebase_hook $root_flag $upstream_name \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -403,8 +406,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch (or simply $branch\n-# with --root) on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or with --root,\n+# everything leading up to $branch) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -441,17 +444,15 @@ then\n fi\n \n if test ! -z \"$rebase_root\"; then\n-\trevisions=\"$orig_head\"\n-\tfp_flag=\"--root\"\n+\trevisions=\"$onto..$orig_head\"\n else\n \trevisions=\"$upstream..$orig_head\"\n-\tfp_flag=\"--ignore-if-in-upstream\"\n fi\n \n if test -z \"$do_merge\"\n then\n-\tgit format-patch -k --stdout --full-index \"$fp_flag\" \\\n-\t\t\"$revisions\" |\n+\tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n+\t\t$root_flag \"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 63ec5e6..1978512 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -15,7 +15,9 @@ test_expect_success 'prepare repository' '\n \tgit commit -m 2 &&\n \tgit symbolic-ref HEAD refs/heads/other &&\n \trm .git/index &&\n-\trm A &&\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1b &&\n \techo 3 > B &&\n \tgit add B &&\n \tgit commit -m 3 &&\n@@ -28,6 +30,14 @@ test_expect_success 'rebase --root expects --onto' '\n \ttest_must_fail git rebase --root\n '\n \n+test_expect_success 'setup pre-rebase hook' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n cat > expect <<EOF\n 4\n 3\n@@ -42,6 +52,10 @@ test_expect_success 'rebase --root --onto <newbase>' '\n \ttest_cmp expect rebased\n '\n \n+test_expect_success 'pre-rebase got correct input (1)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \tgit branch work2 other &&\n \tgit rebase --root --onto master work2 &&\n@@ -49,4 +63,24 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \ttest_cmp expect rebased2\n '\n \n+test_expect_success 'pre-rebase got correct input (2)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n+'\n+\n+test_expect_success 'setup pre-rebase hook that fails' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+false\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase' '\n+\tgit checkout -b stops1 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops1\n+\ttest 0 = $(git rev-list other...stops1 | wc -l)\n+'\n+\n test_done\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"99221","messageId":"200901022341.40667.trast@student.ethz.ch","threadId":"16911","inReplyTo":"43e09eaf2b9a9a3805b9262957ece32190ae4c32.1230935095.git.trast@student.ethz.ch","subject":"[INTERDIFF v3 3/4] rebase -i: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:41:39Z","receivedAt":"2009-01-02T22:41:39Z","isPatch":false,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"This is the interdiff to v2.  Some of the changes are noise from 1/4.\n\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex d6f54eb..14d3e38 100755\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -238,7 +238,9 @@ pick_one_preserving_merges () {\n \t\t\tif test -f \"$DROPPED\"/$p\n \t\t\tthen\n \t\t\t\tfast_forward=f\n-\t\t\t\tpend=\" $(cat \"$DROPPED\"/$p)$pend\"\n+\t\t\t\treplacement=\"$(cat \"$DROPPED\"/$p)\"\n+\t\t\t\ttest -z \"$replacement\" && replacement=root\n+\t\t\t\tpend=\" $replacement$pend\"\n \t\t\telse\n \t\t\t\tnew_parents=\"$new_parents $p\"\n \t\t\tfi\n@@ -569,7 +571,6 @@ first and then run 'git rebase --continue' again.\"\n \t\t;;\n \t--)\n \t\tshift\n-\t\trun_pre_rebase_hook ${1+\"$@\"}\n \t\ttest ! -z \"$REBASE_ROOT\" -o $# -eq 1 -o $# -eq 2 || usage\n \t\ttest -d \"$DOTEST\" &&\n \t\t\tdie \"Interactive rebase already started\"\n@@ -577,19 +578,22 @@ first and then run 'git rebase --continue' again.\"\n \t\tgit var GIT_COMMITTER_IDENT >/dev/null ||\n \t\t\tdie \"You need to set your committer info first\"\n \n-\t\tcomment_for_reflog start\n-\n-\t\trequire_clean_work_tree\n-\n \t\tif test -z \"$REBASE_ROOT\"\n \t\tthen\n+\t\t\tUPSTREAM_ARG=\"$1\"\n \t\t\tUPSTREAM=$(git rev-parse --verify \"$1\") || die \"Invalid base\"\n \t\t\ttest -z \"$ONTO\" && ONTO=$UPSTREAM\n \t\t\tshift\n \t\telse\n+\t\t\tUPSTREAM_ARG=--root\n \t\t\ttest -z \"$ONTO\" &&\n \t\t\t\tdie \"You must specify --onto when using --root\"\n \t\tfi\n+\t\trun_pre_rebase_hook \"$UPSTREAM_ARG\" \"$@\"\n+\n+\t\tcomment_for_reflog start\n+\n+\t\trequire_clean_work_tree\n \n \t\tif test ! -z \"$1\"\n \t\tthen\n@@ -651,7 +655,7 @@ first and then run 'git rebase --continue' again.\"\n \t\t\tREVISIONS=$UPSTREAM...$HEAD\n \t\t\tSHORTREVISIONS=$SHORTUPSTREAM..$SHORTHEAD\n \t\telse\n-\t\t\tREVISIONS=$HEAD\n+\t\t\tREVISIONS=$ONTO...$HEAD\n \t\t\tSHORTREVISIONS=$SHORTHEAD\n \t\tfi\n \t\tgit rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \\\n@@ -710,6 +714,7 @@ first and then run 'git rebase --continue' again.\"\n \t\t\t\tfi\n \t\t\tdone\n \t\tfi\n+\n \t\ttest -s \"$TODO\" || echo noop >> \"$TODO\"\n \t\tcat >> \"$TODO\" << EOF\n \ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex c845dfc..cbf3414 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -15,7 +15,9 @@ test_expect_success 'prepare repository' '\n \tgit commit -m 2 &&\n \tgit symbolic-ref HEAD refs/heads/other &&\n \trm .git/index &&\n-\trm A &&\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1b &&\n \techo 3 > B &&\n \tgit add B &&\n \tgit commit -m 3 &&\n@@ -28,6 +30,14 @@ test_expect_success 'rebase --root expects --onto' '\n \ttest_must_fail git rebase --root\n '\n \n+test_expect_success 'setup pre-rebase hook' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n cat > expect <<EOF\n 4\n 3\n@@ -42,6 +52,10 @@ test_expect_success 'rebase --root --onto <newbase>' '\n \ttest_cmp expect rebased\n '\n \n+test_expect_success 'pre-rebase got correct input (1)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \tgit branch work2 other &&\n \tgit rebase --root --onto master work2 &&\n@@ -49,6 +63,10 @@ test_expect_success 'rebase --root --onto <newbase> <branch>' '\n \ttest_cmp expect rebased2\n '\n \n+test_expect_success 'pre-rebase got correct input (2)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n+'\n+\n test_expect_success 'rebase -i --root --onto <newbase>' '\n \tgit checkout -b work3 other &&\n \tGIT_EDITOR=: git rebase -i --root --onto master &&\n@@ -56,6 +74,10 @@ test_expect_success 'rebase -i --root --onto <newbase>' '\n \ttest_cmp expect rebased3\n '\n \n+test_expect_success 'pre-rebase got correct input (3)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n test_expect_success 'rebase -i --root --onto <newbase> <branch>' '\n \tgit branch work4 other &&\n \tGIT_EDITOR=: git rebase -i --root --onto master work4 &&\n@@ -63,6 +85,10 @@ test_expect_success 'rebase -i --root --onto <newbase> <branch>' '\n \ttest_cmp expect rebased4\n '\n \n+test_expect_success 'pre-rebase got correct input (4)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work4\n+'\n+\n test_expect_success 'rebase -i -p with linear history' '\n \tgit checkout -b work5 other &&\n \tGIT_EDITOR=: git rebase -i -p --root --onto master &&\n@@ -70,6 +96,10 @@ test_expect_success 'rebase -i -p with linear history' '\n \ttest_cmp expect rebased5\n '\n \n+test_expect_success 'pre-rebase got correct input (5)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n test_expect_success 'set up merge history' '\n \tgit checkout other^ &&\n \tgit checkout -b side &&\n@@ -131,4 +161,27 @@ test_expect_success 'rebase -i -p with two roots' '\n \ttest_cmp expect-third rebased7\n '\n \n+test_expect_success 'setup pre-rebase hook that fails' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+false\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase' '\n+\tgit checkout -b stops1 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops1\n+\ttest 0 = $(git rev-list other...stops1 | wc -l)\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase -i' '\n+\tgit checkout -b stops2 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops2\n+\ttest 0 = $(git rev-list other...stops2 | wc -l)\n+'\n+\n test_done\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"99224","messageId":"7vzli9b9y6.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"200901022320.14055.trast@student.ethz.ch","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-02T22:49:05Z","receivedAt":"2009-01-02T22:49:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> I'm still not sure what ${1+\"$@\"} was about by the way.\n\nIt is one of the many old-timer's portability idioms that let us work\naround bugs in some ancient shell implementations.\n\n${1+\"$@\"} should be equivalent to \"$@\" in modern Bourne shell variants\nthat are POSIX compliant.\n"},{"id":"99227","messageId":"200901022354.17922.trast@student.ethz.ch","threadId":"16911","inReplyTo":"7vzli9b9y6.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T22:54:15Z","receivedAt":"2009-01-02T22:54:15Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Junio C Hamano wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> \n> > I'm still not sure what ${1+\"$@\"} was about by the way.\n> \n> It is one of the many old-timer's portability idioms that let us work\n> around bugs in some ancient shell implementations.\n> \n> ${1+\"$@\"} should be equivalent to \"$@\" in modern Bourne shell variants\n> that are POSIX compliant.\n\nSo do you want me to change it back to ${1+\"$@\"}?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n\n"},{"id":"99230","messageId":"7vljttb95u.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"7c74d8be216b4667f470e34644c4aa26dcfe0cfb.1230935095.git.trast@student.ethz.ch","subject":"Re: [PATCH v3 2/4] rebase: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-02T23:06:05Z","receivedAt":"2009-01-02T23:06:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\n>  # If a hook exists, give it a chance to interrupt\n> -run_pre_rebase_hook ${1+\"$@\"}\n> +run_pre_rebase_hook $root_flag $upstream_name \"$@\"\n\nYou'd have to quote the $upstream_name properly here, because the original\ncommand line could well have been:\n\n\t$ git rebase 'master@{3 days ago}'\n"},{"id":"99231","messageId":"7vhc4hb92r.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"200901022354.17922.trast@student.ethz.ch","subject":"Re: [PATCH v2 1/3] rebase: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-02T23:07:56Z","receivedAt":"2009-01-02T23:07:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n>> ${1+\"$@\"} should be equivalent to \"$@\" in modern Bourne shell variants\n>> that are POSIX compliant.\n>\n> So do you want me to change it back to ${1+\"$@\"}?\n\nNo.  I was merely answering your question.\n"},{"id":"99232","messageId":"1230939915-3638-1-git-send-email-trast@student.ethz.ch","threadId":"16911","inReplyTo":"7vljttb95u.fsf@gitster.siamese.dyndns.org","subject":"[PATCH v3.1] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-02T23:45:15Z","receivedAt":"2009-01-02T23:45:15Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase a new option --root, which instructs it to rebase the\nentire history leading up to <branch>.  This option must be used with\n--onto <newbase>, and causes commits that already exist in <newbase>\nto be skipped.  (Normal operation skips commits that already exist in\n<upstream> instead.)\n\nThe main use-case is with git-svn: suppose you start hacking (perhaps\noffline) on a new project, but later notice you want to commit this\nwork to SVN.  You will have to rebase the entire history, including\nthe root commit, on a (possibly empty) commit coming from git-svn, to\nestablish a history connection.  This previously had to be done by\ncherry-picking the root commit manually.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n\n---\n\nJunio C Hamano wrote:\n> \n> >  # If a hook exists, give it a chance to interrupt\n> > -run_pre_rebase_hook ${1+\"$@\"}\n> > +run_pre_rebase_hook $root_flag $upstream_name \"$@\"\n> \n> You'd have to quote the $upstream_name properly here, because the original\n> command line could well have been:\n> \n> \t$ git rebase 'master@{3 days ago}'\n\nRight, thanks.  Let's fix it like this, so I won't have to look up\nwhat the various special parameter expansion characters mean.\n($root_flag is still used further below.)\n\n>> --- a/git-rebase.sh\n>> +++ b/git-rebase.sh\n>> @@ -355,11 +355,13 @@ if test -z \"$rebase_root\"; then\n>>         upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n>>         die \"invalid upstream $upstream_name\"\n>>         unset root_flag\n>> +       upstream_arg=\"$upstream_name\"\n>>  else\n>>         test -z \"$newbase\" && die \"--root must be used with --onto\"\n>>         unset upstream_name\n>>         unset upstream\n>>         root_flag=\"--root\"\n>> +       upstream_arg=\"$root_flag\"\n>>  fi\n>>  \n>>  # Make sure the branch to rebase onto is valid.\n>> @@ -367,7 +369,7 @@ onto_name=${newbase-\"$upstream_name\"}\n>>  onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n>>  \n>>  # If a hook exists, give it a chance to interrupt\n>> -run_pre_rebase_hook $root_flag $upstream_name \"$@\"\n>> +run_pre_rebase_hook \"$upstream_arg\" \"$@\"\n>>  \n>>  # If the branch to rebase is given, that is the branch we will rebase\n>>  # $branch_name -- branch being rebased, or HEAD (already detached)\n\n git-rebase.sh          |   52 ++++++++++++++++++++--------\n t/t3412-rebase-root.sh |   86 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 123 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex ebd4df3..d1083f1 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2005 Junio C Hamano.\n #\n \n-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'\n+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'\n LONG_USAGE='git-rebase replaces <branch> with a new branch of the\n same name.  When the --onto option is provided the new branch starts\n out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>\n@@ -47,6 +47,7 @@ dotest=\"$GIT_DIR\"/rebase-merge\n prec=4\n verbose=\n git_am_opt=\n+rebase_root=\n \n continue_merge () {\n \ttest -n \"$prev_head\" || die \"prev_head must be defined\"\n@@ -297,6 +298,9 @@ do\n \t-C*)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -344,17 +348,28 @@ case \"$diff\" in\n \t;;\n esac\n \n+if test -z \"$rebase_root\"; then\n # The upstream head must be given.  Make sure it is valid.\n-upstream_name=\"$1\"\n-upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-    die \"invalid upstream $upstream_name\"\n+\tupstream_name=\"$1\"\n+\tshift\n+\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\tdie \"invalid upstream $upstream_name\"\n+\tunset root_flag\n+\tupstream_arg=\"$upstream_name\"\n+else\n+\ttest -z \"$newbase\" && die \"--root must be used with --onto\"\n+\tunset upstream_name\n+\tunset upstream\n+\troot_flag=\"--root\"\n+\tupstream_arg=\"$root_flag\"\n+fi\n \n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${1+\"$@\"}\n+run_pre_rebase_hook \"$upstream_arg\" \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -362,16 +377,16 @@ run_pre_rebase_hook ${1+\"$@\"}\n # $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n switch_to=\n case \"$#\" in\n-2)\n+1)\n \t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n-\tbranch_name=\"$2\"\n-\tswitch_to=\"$2\"\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n \n-\tif git show-ref --verify --quiet -- \"refs/heads/$2\" &&\n-\t   branch=$(git rev-parse -q --verify \"refs/heads/$2\")\n+\tif git show-ref --verify --quiet -- \"refs/heads/$1\" &&\n+\t   branch=$(git rev-parse -q --verify \"refs/heads/$1\")\n \tthen\n-\t\thead_name=\"refs/heads/$2\"\n-\telif branch=$(git rev-parse -q --verify \"$2\")\n+\t\thead_name=\"refs/heads/$1\"\n+\telif branch=$(git rev-parse -q --verify \"$1\")\n \tthen\n \t\thead_name=\"detached HEAD\"\n \telse\n@@ -393,7 +408,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or with --root,\n+# everything leading up to $branch) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -429,10 +445,16 @@ then\n \texit 0\n fi\n \n+if test ! -z \"$rebase_root\"; then\n+\trevisions=\"$onto..$orig_head\"\n+else\n+\trevisions=\"$upstream..$orig_head\"\n+fi\n+\n if test -z \"$do_merge\"\n then\n \tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t\t\"$upstream..$orig_head\" |\n+\t\t$root_flag \"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\n@@ -455,7 +477,7 @@ echo \"$orig_head\" > \"$dotest/orig-head\"\n echo \"$head_name\" > \"$dotest/head-name\"\n \n msgnum=0\n-for cmt in `git rev-list --reverse --no-merges \"$upstream..$orig_head\"`\n+for cmt in `git rev-list --reverse --no-merges \"$revisions\"`\n do\n \tmsgnum=$(($msgnum + 1))\n \techo \"$cmt\" > \"$dotest/cmt.$msgnum\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nnew file mode 100755\nindex 0000000..1978512\n--- /dev/null\n+++ b/t/t3412-rebase-root.sh\n@@ -0,0 +1,86 @@\n+#!/bin/sh\n+\n+test_description='git rebase --root\n+\n+Tests if git rebase --root --onto <newparent> can rebase the root commit.\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'prepare repository' '\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1 &&\n+\techo 2 > A &&\n+\tgit add A &&\n+\tgit commit -m 2 &&\n+\tgit symbolic-ref HEAD refs/heads/other &&\n+\trm .git/index &&\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1b &&\n+\techo 3 > B &&\n+\tgit add B &&\n+\tgit commit -m 3 &&\n+\techo 4 > B &&\n+\tgit add B &&\n+\tgit commit -m 4\n+'\n+\n+test_expect_success 'rebase --root expects --onto' '\n+\ttest_must_fail git rebase --root\n+'\n+\n+test_expect_success 'setup pre-rebase hook' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+cat > expect <<EOF\n+4\n+3\n+2\n+1\n+EOF\n+\n+test_expect_success 'rebase --root --onto <newbase>' '\n+\tgit checkout -b work &&\n+\tgit rebase --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased &&\n+\ttest_cmp expect rebased\n+'\n+\n+test_expect_success 'pre-rebase got correct input (1)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n+test_expect_success 'rebase --root --onto <newbase> <branch>' '\n+\tgit branch work2 other &&\n+\tgit rebase --root --onto master work2 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased2 &&\n+\ttest_cmp expect rebased2\n+'\n+\n+test_expect_success 'pre-rebase got correct input (2)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n+'\n+\n+test_expect_success 'setup pre-rebase hook that fails' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+false\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase' '\n+\tgit checkout -b stops1 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops1\n+\ttest 0 = $(git rev-list other...stops1 | wc -l)\n+'\n+\n+test_done\n-- \ntg: (cb706e1..) t/rr-normal (depends on: origin/master t/rebase-hook-order)\n"},{"id":"99372","messageId":"1231176916-14929-1-git-send-email-trast@student.ethz.ch","threadId":"16911","inReplyTo":"1230939915-3638-1-git-send-email-trast@student.ethz.ch","subject":"[PATCH v3.2] rebase: learn to rebase root commit","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-01-05T17:35:16Z","receivedAt":"2009-01-05T17:35:16Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Teach git-rebase a new option --root, which instructs it to rebase the\nentire history leading up to <branch>.  This option must be used with\n--onto <newbase>, and causes commits that already exist in <newbase>\nto be skipped.  (Normal operation skips commits that already exist in\n<upstream> instead.)\n\nThe main use-case is with git-svn: suppose you start hacking (perhaps\noffline) on a new project, but later notice you want to commit this\nwork to SVN.  You will have to rebase the entire history, including\nthe root commit, on a (possibly empty) commit coming from git-svn, to\nestablish a history connection.  This previously had to be done by\ncherry-picking the root commit manually.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n\n---\n\nSince this is still in 'pu', can you replace it again?  The test case\nI designed for v3, to check that it also skips identical commits,\nactually makes the _root_ commit a duplicate.  I could sleep better at\nnight if the root commit was actually part of the rebase :-)\n\n3/4 is not affected patch-wise, though it of course inherits the same\ntest history.\n\nThanks!\n\n\nInterdiff:\n\n>> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\n>> index 1978512..dd91910 100755\n>> --- a/t/t3412-rebase-root.sh\n>> +++ b/t/t3412-rebase-root.sh\n>> @@ -15,12 +15,12 @@ test_expect_success 'prepare repository' '\n>>         git commit -m 2 &&\n>>         git symbolic-ref HEAD refs/heads/other &&\n>>         rm .git/index &&\n>> -       echo 1 > A &&\n>> -       git add A &&\n>> -       git commit -m 1b &&\n>>         echo 3 > B &&\n>>         git add B &&\n>>         git commit -m 3 &&\n>> +       echo 1 > A &&\n>> +       git add A &&\n>> +       git commit -m 1b &&\n>>         echo 4 > B &&\n>>         git add B &&\n>>         git commit -m 4\n\n\n git-rebase.sh          |   52 ++++++++++++++++++++--------\n t/t3412-rebase-root.sh |   86 ++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 123 insertions(+), 15 deletions(-)\n\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex ebd4df3..d1083f1 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -3,7 +3,7 @@\n # Copyright (c) 2005 Junio C Hamano.\n #\n \n-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'\n+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'\n LONG_USAGE='git-rebase replaces <branch> with a new branch of the\n same name.  When the --onto option is provided the new branch starts\n out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>\n@@ -47,6 +47,7 @@ dotest=\"$GIT_DIR\"/rebase-merge\n prec=4\n verbose=\n git_am_opt=\n+rebase_root=\n \n continue_merge () {\n \ttest -n \"$prev_head\" || die \"prev_head must be defined\"\n@@ -297,6 +298,9 @@ do\n \t-C*)\n \t\tgit_am_opt=\"$git_am_opt $1\"\n \t\t;;\n+\t--root)\n+\t\trebase_root=t\n+\t\t;;\n \t-*)\n \t\tusage\n \t\t;;\n@@ -344,17 +348,28 @@ case \"$diff\" in\n \t;;\n esac\n \n+if test -z \"$rebase_root\"; then\n # The upstream head must be given.  Make sure it is valid.\n-upstream_name=\"$1\"\n-upstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n-    die \"invalid upstream $upstream_name\"\n+\tupstream_name=\"$1\"\n+\tshift\n+\tupstream=`git rev-parse --verify \"${upstream_name}^0\"` ||\n+\tdie \"invalid upstream $upstream_name\"\n+\tunset root_flag\n+\tupstream_arg=\"$upstream_name\"\n+else\n+\ttest -z \"$newbase\" && die \"--root must be used with --onto\"\n+\tunset upstream_name\n+\tunset upstream\n+\troot_flag=\"--root\"\n+\tupstream_arg=\"$root_flag\"\n+fi\n \n # Make sure the branch to rebase onto is valid.\n onto_name=${newbase-\"$upstream_name\"}\n onto=$(git rev-parse --verify \"${onto_name}^0\") || exit\n \n # If a hook exists, give it a chance to interrupt\n-run_pre_rebase_hook ${1+\"$@\"}\n+run_pre_rebase_hook \"$upstream_arg\" \"$@\"\n \n # If the branch to rebase is given, that is the branch we will rebase\n # $branch_name -- branch being rebased, or HEAD (already detached)\n@@ -362,16 +377,16 @@ run_pre_rebase_hook ${1+\"$@\"}\n # $head_name -- refs/heads/<that-branch> or \"detached HEAD\"\n switch_to=\n case \"$#\" in\n-2)\n+1)\n \t# Is it \"rebase other $branchname\" or \"rebase other $commit\"?\n-\tbranch_name=\"$2\"\n-\tswitch_to=\"$2\"\n+\tbranch_name=\"$1\"\n+\tswitch_to=\"$1\"\n \n-\tif git show-ref --verify --quiet -- \"refs/heads/$2\" &&\n-\t   branch=$(git rev-parse -q --verify \"refs/heads/$2\")\n+\tif git show-ref --verify --quiet -- \"refs/heads/$1\" &&\n+\t   branch=$(git rev-parse -q --verify \"refs/heads/$1\")\n \tthen\n-\t\thead_name=\"refs/heads/$2\"\n-\telif branch=$(git rev-parse -q --verify \"$2\")\n+\t\thead_name=\"refs/heads/$1\"\n+\telif branch=$(git rev-parse -q --verify \"$1\")\n \tthen\n \t\thead_name=\"detached HEAD\"\n \telse\n@@ -393,7 +408,8 @@ case \"$#\" in\n esac\n orig_head=$branch\n \n-# Now we are rebasing commits $upstream..$branch on top of $onto\n+# Now we are rebasing commits $upstream..$branch (or with --root,\n+# everything leading up to $branch) on top of $onto\n \n # Check if we are already based on $onto with linear history,\n # but this should be done only when upstream and onto are the same.\n@@ -429,10 +445,16 @@ then\n \texit 0\n fi\n \n+if test ! -z \"$rebase_root\"; then\n+\trevisions=\"$onto..$orig_head\"\n+else\n+\trevisions=\"$upstream..$orig_head\"\n+fi\n+\n if test -z \"$do_merge\"\n then\n \tgit format-patch -k --stdout --full-index --ignore-if-in-upstream \\\n-\t\t\"$upstream..$orig_head\" |\n+\t\t$root_flag \"$revisions\" |\n \tgit am $git_am_opt --rebasing --resolvemsg=\"$RESOLVEMSG\" &&\n \tmove_to_original_branch\n \tret=$?\n@@ -455,7 +477,7 @@ echo \"$orig_head\" > \"$dotest/orig-head\"\n echo \"$head_name\" > \"$dotest/head-name\"\n \n msgnum=0\n-for cmt in `git rev-list --reverse --no-merges \"$upstream..$orig_head\"`\n+for cmt in `git rev-list --reverse --no-merges \"$revisions\"`\n do\n \tmsgnum=$(($msgnum + 1))\n \techo \"$cmt\" > \"$dotest/cmt.$msgnum\"\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nnew file mode 100755\nindex 0000000..dd91910\n--- /dev/null\n+++ b/t/t3412-rebase-root.sh\n@@ -0,0 +1,86 @@\n+#!/bin/sh\n+\n+test_description='git rebase --root\n+\n+Tests if git rebase --root --onto <newparent> can rebase the root commit.\n+'\n+. ./test-lib.sh\n+\n+test_expect_success 'prepare repository' '\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1 &&\n+\techo 2 > A &&\n+\tgit add A &&\n+\tgit commit -m 2 &&\n+\tgit symbolic-ref HEAD refs/heads/other &&\n+\trm .git/index &&\n+\techo 3 > B &&\n+\tgit add B &&\n+\tgit commit -m 3 &&\n+\techo 1 > A &&\n+\tgit add A &&\n+\tgit commit -m 1b &&\n+\techo 4 > B &&\n+\tgit add B &&\n+\tgit commit -m 4\n+'\n+\n+test_expect_success 'rebase --root expects --onto' '\n+\ttest_must_fail git rebase --root\n+'\n+\n+test_expect_success 'setup pre-rebase hook' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+echo \"\\$1,\\$2\" >.git/PRE-REBASE-INPUT\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+cat > expect <<EOF\n+4\n+3\n+2\n+1\n+EOF\n+\n+test_expect_success 'rebase --root --onto <newbase>' '\n+\tgit checkout -b work &&\n+\tgit rebase --root --onto master &&\n+\tgit log --pretty=tformat:\"%s\" > rebased &&\n+\ttest_cmp expect rebased\n+'\n+\n+test_expect_success 'pre-rebase got correct input (1)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,\n+'\n+\n+test_expect_success 'rebase --root --onto <newbase> <branch>' '\n+\tgit branch work2 other &&\n+\tgit rebase --root --onto master work2 &&\n+\tgit log --pretty=tformat:\"%s\" > rebased2 &&\n+\ttest_cmp expect rebased2\n+'\n+\n+test_expect_success 'pre-rebase got correct input (2)' '\n+\ttest \"z$(cat .git/PRE-REBASE-INPUT)\" = z--root,work2\n+'\n+\n+test_expect_success 'setup pre-rebase hook that fails' '\n+\tmkdir -p .git/hooks &&\n+\tcat >.git/hooks/pre-rebase <<EOF &&\n+#!$SHELL_PATH\n+false\n+EOF\n+\tchmod +x .git/hooks/pre-rebase\n+'\n+\n+test_expect_success 'pre-rebase hook stops rebase' '\n+\tgit checkout -b stops1 other &&\n+\tGIT_EDITOR=: test_must_fail git rebase --root --onto master &&\n+\ttest \"z$(git symbolic-ref HEAD)\" = zrefs/heads/stops1\n+\ttest 0 = $(git rev-list other...stops1 | wc -l)\n+'\n+\n+test_done\n-- \ntg: (f62b77f..) t/rr-normal (depends on: origin/master t/rebase-hook-order)\n"},{"id":"99446","messageId":"7vvdssj185.fsf@gitster.siamese.dyndns.org","threadId":"16911","inReplyTo":"1231176916-14929-1-git-send-email-trast@student.ethz.ch","subject":"Re: [PATCH v3.2] rebase: learn to rebase root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-01-06T08:19:22Z","receivedAt":"2009-01-06T08:19:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Since this is still in 'pu', can you replace it again?\n\nThanks, done.\n"}]}