{"thread":{"id":"30911","subject":"[PATCH v2 1/2] rebase -i: support --root without --onto","startedAt":"2012-06-26T21:55:23Z","lastAt":"2012-06-26T22:09:19Z","messageCount":3,"participants":["Chris Webb","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":2},"messages":[{"id":"194318","messageId":"8d50b9665c6b31af25464f92ada57da90c2ca8a7.1340747724.git.chris@arachsys.com","threadId":"30911","inReplyTo":null,"subject":"[PATCH v2 1/2] rebase -i: support --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T21:55:23Z","receivedAt":"2012-06-26T21:55:23Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Allow --root to be specified to rebase -i without --onto, making it\npossible to edit and re-order all commits right back to the root(s).\n\nIf there is a conflict to be resolved when applying the first change,\nthe user will expect a sane index and working tree to get sensible\nbehaviour from git-diff and friends, so create a sentinel commit with an\nempty tree to rebase onto. Automatically squash the sentinel with any\ncommits rebased directly onto it, so they end up as root commits in\ntheir own right and retain their authorship and commit message.\n\nImplicitly use rebase -i for non-interactive rebase of --root without\nan --onto argument now that rebase -i can correctly do this.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n Documentation/git-rebase.txt |    9 +++++----\n git-rebase--interactive.sh   |   32 ++++++++++++++++++++++++++------\n git-rebase.sh                |   14 ++++++++++++--\n 3 files changed, 43 insertions(+), 12 deletions(-)\n\ndiff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt\nindex 147fa1a..85b5e44 100644\n--- a/Documentation/git-rebase.txt\n+++ b/Documentation/git-rebase.txt\n@@ -10,7 +10,7 @@ SYNOPSIS\n [verse]\n 'git rebase' [-i | --interactive] [options] [--onto <newbase>]\n \t[<upstream>] [<branch>]\n-'git rebase' [-i | --interactive] [options] --onto <newbase>\n+'git rebase' [-i | --interactive] [options] [--onto <newbase>]\n \t--root [<branch>]\n 'git rebase' --continue | --skip | --abort\n \n@@ -348,10 +348,11 @@ idea unless you know what you are doing (see BUGS below).\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+\tthe root commit(s) on a branch.  When used with --onto, it\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+\t<upstream>) whereas without --onto it will operate on every change.\n+\tWhen used together with both --onto and --preserve-merges,\n+\t'all' root commits will be rewritten to have <newbase> as parent\n \tinstead.\n \n --autosquash::\ndiff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh\nindex 0c19b7c..fcb5f61 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -417,6 +417,29 @@ record_in_rewritten() {\n \tesac\n }\n \n+do_pick () {\n+\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n+\tthen\n+\t\t# Set the correct commit message and author info on the\n+\t\t# sentinel root before cherry-picking the original changes\n+\t\t# without committing (-n).  Finally, update the sentinel again\n+\t\t# to include these changes.  If the cherry-pick results in a\n+\t\t# conflict, this means our behaviour is similar to a standard\n+\t\t# failed cherry-pick during rebase, with a dirty index to\n+\t\t# resolve before manually running git commit --amend then git\n+\t\t# rebase --continue.\n+\t\tgit commit --allow-empty --allow-empty-message --amend \\\n+\t\t\t   --no-post-rewrite -n -q -C $1 &&\n+\t\t\tpick_one -n $1 &&\n+\t\t\tgit commit --allow-empty --allow-empty-message \\\n+\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 ||\n+\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\telse\n+\t\tpick_one $1 ||\n+\t\t\tdie_with_patch $1 \"Could not apply $1... $2\"\n+\tfi\n+}\n+\n do_next () {\n \trm -f \"$msg\" \"$author_script\" \"$amend\" || exit\n \tread -r command sha1 rest < \"$todo\"\n@@ -428,16 +451,14 @@ do_next () {\n \t\tcomment_for_reflog pick\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n-\t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick $sha1 \"$rest\"\n \t\trecord_in_rewritten $sha1\n \t\t;;\n \treword|r)\n \t\tcomment_for_reflog reword\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n-\t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick $sha1 \"$rest\"\n \t\tgit commit --amend --no-post-rewrite || {\n \t\t\twarn \"Could not amend commit after successfully picking $sha1... $rest\"\n \t\t\twarn \"This is most likely due to an empty commit message, or the pre-commit hook\"\n@@ -451,8 +472,7 @@ do_next () {\n \t\tcomment_for_reflog edit\n \n \t\tmark_action_done\n-\t\tpick_one $sha1 ||\n-\t\t\tdie_with_patch $sha1 \"Could not apply $sha1... $rest\"\n+\t\tdo_pick $sha1 \"$rest\"\n \t\twarn \"Stopped at $sha1... $rest\"\n \t\texit_with_patch $sha1 0\n \t\t;;\ndiff --git a/git-rebase.sh b/git-rebase.sh\nindex e616737..bde2be8 100755\n--- a/git-rebase.sh\n+++ b/git-rebase.sh\n@@ -31,7 +31,7 @@ SUBDIRECTORY_OK=Yes\n OPTIONS_KEEPDASHDASH=\n OPTIONS_SPEC=\"\\\n git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>]\n-git rebase [-i] [options] --onto <newbase> --root [<branch>]\n+git rebase [-i] [options] [--onto <newbase>] --root [<branch>]\n git-rebase [-i] --continue | --abort | --skip\n --\n  Available options are\n@@ -364,6 +364,11 @@ and run me again.  I am stopping in case you still have something\n valuable there.'\n fi\n \n+if test -n \"$rebase_root\" && test -z \"$onto\"\n+then\n+\ttest -z \"$interactive_rebase\" && interactive_rebase=implied\n+fi\n+\n if test -n \"$interactive_rebase\"\n then\n \ttype=interactive\n@@ -397,7 +402,12 @@ then\n \tdie \"invalid upstream $upstream_name\"\n \tupstream_arg=\"$upstream_name\"\n else\n-\ttest -z \"$onto\" && die \"You must specify --onto when using --root\"\n+\tif test -z \"$onto\"\n+\tthen\n+\t\tempty_tree=`git hash-object -t tree /dev/null`\n+\t\tonto=`git commit-tree $empty_tree </dev/null`\n+\t\tsquash_onto=\"$onto\"\n+\tfi\n \tunset upstream_name\n \tunset upstream\n \tupstream_arg=--root\n-- \n1.7.10\n"},{"id":"194319","messageId":"f4be13ed5005aefce11e21cbba47b0dc2f743d3e.1340747724.git.chris@arachsys.com","threadId":"30911","inReplyTo":"8d50b9665c6b31af25464f92ada57da90c2ca8a7.1340747724.git.chris@arachsys.com","subject":"[PATCH v2 2/2] Add tests for rebase -i --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T21:55:24Z","receivedAt":"2012-06-26T21:55:24Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Test for likely breakages in t3404, including successful reordering of\nnon-conflicting changes with a new root, correct preservation of commit\nmessage and author in a root commit when it is squashed with the\nsentinel, and presence of the sentinel following a conflicting\ncherry-pick of a new root.\n\nRemove test_must_fail for git rebase --root without --onto from t3412 as\nthis case will now be successfully handled by an implicit git rebase -i.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n t/t3404-rebase-interactive.sh |   27 +++++++++++++++++++++++++++\n t/t3412-rebase-root.sh        |    4 ----\n 2 files changed, 27 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh\nindex 025c1c6..6ffc9c2 100755\n--- a/t/t3404-rebase-interactive.sh\n+++ b/t/t3404-rebase-interactive.sh\n@@ -755,4 +755,31 @@ test_expect_success 'rebase-i history with funny messages' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'rebase -i --root re-order and drop commits' '\n+\tgit checkout E &&\n+\tFAKE_LINES=\"3 1 2 5\" git rebase -i --root &&\n+\ttest E = $(git cat-file commit HEAD | sed -ne \\$p) &&\n+\ttest B = $(git cat-file commit HEAD^ | sed -ne \\$p) &&\n+\ttest A = $(git cat-file commit HEAD^^ | sed -ne \\$p) &&\n+\ttest C = $(git cat-file commit HEAD^^^ | sed -ne \\$p) &&\n+\ttest 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\\ )\n+'\n+\n+test_expect_success 'rebase -i --root retain root commit author and message' '\n+\tgit checkout A &&\n+\techo B >file7 &&\n+\tgit add file7 &&\n+\tGIT_AUTHOR_NAME=\"Twerp Snog\" git commit -m \"different author\" &&\n+\tFAKE_LINES=\"2\" git rebase -i --root &&\n+\tgit cat-file commit HEAD | grep -q \"^author Twerp Snog\" &&\n+\tgit cat-file commit HEAD | grep -q \"^different author$\"\n+'\n+\n+test_expect_success 'rebase -i --root temporary sentinel commit' '\n+\tgit checkout B &&\n+\tFAKE_LINES=\"2\" test_must_fail git rebase -i --root &&\n+\tgit cat-file commit HEAD | grep \"^tree 4b825dc642cb\" &&\n+\tgit rebase --abort\n+'\n+\n test_done\ndiff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh\nindex 086c91c..e4f9da8 100755\n--- a/t/t3412-rebase-root.sh\n+++ b/t/t3412-rebase-root.sh\n@@ -22,10 +22,6 @@ test_expect_success 'prepare repository' '\n \ttest_commit 4 B\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-- \n1.7.10\n"},{"id":"194322","messageId":"7vbok5afow.fsf@alter.siamese.dyndns.org","threadId":"30911","inReplyTo":"8d50b9665c6b31af25464f92ada57da90c2ca8a7.1340747724.git.chris@arachsys.com","subject":"Re: [PATCH v2 1/2] rebase -i: support --root without --onto","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-26T22:09:19Z","receivedAt":"2012-06-26T22:09:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> +\t\t# Set the correct commit message and author info on the\n> +\t\t# sentinel root before cherry-picking the original changes\n> +\t\t# without committing (-n).  Finally, update the sentinel again\n> +\t\t# to include these changes.  If the cherry-pick results in a\n> +\t\t# conflict, this means our behaviour is similar to a standard\n> +\t\t# failed cherry-pick during rebase, with a dirty index to\n> +\t\t# resolve before manually running git commit --amend then git\n> +\t\t# rebase --continue.\n\nThanks; very readable and understandable.\n"}]}