{"thread":{"id":"30838","subject":"Editing the root commit","startedAt":"2012-06-19T09:16:58Z","lastAt":"2012-06-26T21:27:11Z","messageCount":29,"participants":["Chris Webb","Junio C Hamano","jaseem abid","Jeff King","Martin von Zweigbergk"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"193826","messageId":"20120619091657.GA28005@arachsys.com","threadId":"30838","inReplyTo":null,"subject":"Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-19T09:16:58Z","receivedAt":"2012-06-19T09:16:58Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"I've recently been polishing up some private code for release, using git\nrebase --interactive to expand on some commit messages.\n\nIn a couple of cases, I wanted to edit the root commit. (Adding a COPYING\nfile, for example.) I've been successfully doing this with an explicit\n\n  ROOT=$(git log --pretty=format:%H | tail -n 1)\n  git checkout $ROOT\n  git commit --amend --message='Initial import modified' # for example\n  git rebase --onto HEAD $ROOT master\n\nHowever, this brought two questions to mind.\n\nThe first is whether there's a clever symbolic way to refer to the root of\nthe current branch, rather than tailing git log output? gitrevisions(7)\ndoesn't obviously suggest one.\n\nThe second question is whether it's possible to use git rebase --interactive\nto edit the root commit along with some subsequent ones in one fell swoop?\n\nMy fingers half-remember doing something like\n\n  git checkout --orphan rewritten\n  git rm -rf\n  git rebase --interactive --root --onto rewritten master\n\na year or so ago, but this now fails (on git 1.7.10) with the somewhat\nsurprising error\n\n  $ git rebase --root --onto rewritten master\n  fatal: Needed a single revision\n  Does not point to a valid commit: master\n\nAm I misremembering the recipe here, or has the behaviour changed? It seems\nto fail identically with or without --interactive.\n\nBest wishes,\n\nChris.\n"},{"id":"193829","messageId":"7vy5nj1uld.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120619091657.GA28005@arachsys.com","subject":"Re: Editing the root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-19T10:09:34Z","receivedAt":"2012-06-19T10:09:34Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> The first is whether there's a clever symbolic way to refer to the root of\n> the current branch, rather than tailing git log output? gitrevisions(7)\n> doesn't obviously suggest one.\n\nThere is not, for a few good reasons.\n\nThe very first commit is no more special than any other commit in\nthe history.  Some projects may start with \"the first working\nversion\", in which case there may be some value to be able to refer\nto it, while some other projects may start with \"the initial\nsnapshot\" whose specialness comes _only_ from it being the first\none.\n\n\"The first working version\" specialness may deserve to be tagged,\nand in that case you would already have a name to refer to it.  If\non the other hand the first one isn't even worth to be tagged, it\ndoes not deserve to waste a short-hand to refer to it at the\nmachinery level.  So there is nothing listed in the gitrevisions(7)\nfor it.\n\nAlso there is a more important question: Which root commit?  There\ndoes not necessarily have to be a single \"the root\" commit in the\nhistory.\n\n>   git checkout --orphan rewritten\n>   git rm -rf\n>   git rebase --interactive --root --onto rewritten master\n\nThe argument to \"--onto\" must be a commit, but \"checkout --orphan\"\nis not a way to create a commit; it is a way to bring you to a state\nwithout any commit.\n\nI personally think \"git rebase -i --root\" should be made to just\nwork without requiring \"--onto\" and let you \"edit\" even the first\none in the history. It is understandable that nobody bothered, as\npeople are a lot less often rewriting near the very beginning of the\nhistory than otherwise.\n\nEven though I wouldn't bother doing this myself, I wouldn't mind\nreviewing a patch series ;-)\n"},{"id":"193833","messageId":"20120619111709.GC10692@arachsys.com","threadId":"30838","inReplyTo":"7vy5nj1uld.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-19T11:17:10Z","receivedAt":"2012-06-19T11:17:10Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n[symbolic reference to root commit]\n> Also there is a more important question: Which root commit?  There\n> does not necessarily have to be a single \"the root\" commit in the\n> history.\n\nAh yes, very good point. Anything with a subtree merge would have several\nroots, for example.\n\nI suppose the thing that makes root commits special is their lack of\nparents, so the most direct way to get a list of root commits for the\ncurrent branch would just be\n\n  git rev-list --max-parents=0 HEAD\n\nmaking the recipe\n\n  ROOT=$(git rev-list --max-parents=0 master)\n  git checkout \"$ROOT\" -- # will fail if more than one root\n  git commit --amend\n  git rebase [--interactive] --onto HEAD \"$ROOT\" master\n\n> I personally think \"git rebase -i --root\" should be made to just\n> work without requiring \"--onto\" and let you \"edit\" even the first\n> one in the history. It is understandable that nobody bothered, as\n> people are a lot less often rewriting near the very beginning of the\n> history than otherwise.\n> \n> Even though I wouldn't bother doing this myself, I wouldn't mind\n> reviewing a patch series ;-)\n\nOkay, I'll take a look when I finish my current project!\n\nBest wishes,\n\nChris.\n"},{"id":"193835","messageId":"CAH-tXsAZXfVshXi8GH+pW8rMbeFK1_LuSLNBp5=bjutN67K9bQ@mail.gmail.com","threadId":"30838","inReplyTo":"20120619091657.GA28005@arachsys.com","subject":"Re: Editing the root commit","fromName":"jaseem abid","fromEmail":"jaseemabid@gmail.com","sentAt":"2012-06-19T11:50:48Z","receivedAt":"2012-06-19T11:50:48Z","isPatch":false,"sender":{"key":"jaseemabid@gmail.com","avatar":"https://gravatar.com/avatar/8b0432c96e4d3c8a9a96c9961ee842df7b7a869744da9c25187a51a992eabd81?d=mp&s=160"},"body":"On Tue, Jun 19, 2012 at 2:46 PM, Chris Webb <chris@arachsys.com> wrote:\n>\n> I've recently been polishing up some private code for release, using git\n> rebase --interactive to expand on some commit messages.\n>\n> In a couple of cases, I wanted to edit the root commit. (Adding a COPYING\n> file, for example.) I've been successfully doing this with an explicit\n>\n>  ROOT=$(git log --pretty=format:%H | tail -n 1)\n>  git checkout $ROOT\n>  git commit --amend --message='Initial import modified' # for example\n>  git rebase --onto HEAD $ROOT master\n>\n> However, this brought two questions to mind.\n>\n> The first is whether there's a clever symbolic way to refer to the root of\n> the current branch, rather than tailing git log output? gitrevisions(7)\n> doesn't obviously suggest one.\n>\n> The second question is whether it's possible to use git rebase\n> --interactive\n> to edit the root commit along with some subsequent ones in one fell swoop?\n>\n> My fingers half-remember doing something like\n>\n>  git checkout --orphan rewritten\n>  git rm -rf\n>  git rebase --interactive --root --onto rewritten master\n>\n> a year or so ago, but this now fails (on git 1.7.10) with the somewhat\n> surprising error\n>\n>  $ git rebase --root --onto rewritten master\n>  fatal: Needed a single revision\n>  Does not point to a valid commit: master\n>\n> Am I misremembering the recipe here, or has the behaviour changed? It\n> seems\n> to fail identically with or without --interactive.\n\nI was trying to do something very similar yesterday. I was cleaning up\na lot of commits with a rebase -i when I figured out that I cant do\nthat on the root commit.\n\nThe man on interactive rebase says,\n\n        Start it with the last commit you want to retain as-is:\n        git rebase -i <after-this-commit>\n\nwhich means root cant be included. Finally I had to settle for some\nsolution like what you mentioned.\n\nIf possible Junio, can a feature be added to include root commit also\nto git rebase -i somehow so that a rewrite including root is easier\nand more straightforward ?\n\n--\nJaseem Abid\nhttp://jaseemabid.github.com\n"},{"id":"193925","messageId":"20120620093205.GB10579@arachsys.com","threadId":"30838","inReplyTo":"20120619111709.GC10692@arachsys.com","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-20T09:32:05Z","receivedAt":"2012-06-20T09:32:05Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n> > Even though I wouldn't bother doing this myself, I wouldn't mind\n> > reviewing a patch series ;-)\n> \n> Okay, I'll take a look when I finish my current project!\n\nI had a bit of spare time this morning and had a quick look through\ngit-rebase--interactive.sh.\n\nApart from the validation, message and reflog code in git-rebase.sh and\ngit-rebase--interactive.sh that would need fixing up to know about this\ncase, the essence of this seems to be starting with an orphan commit instead\nof a commit descended from $onto right at the end of --interactive.\n\nI'd love to write something like\n\n  git checkout ${onto:---orphan}\n\n(or a variant) but can git be persuaded to have an orphan detached HEAD like\nthat?\n\nAn orphan branch appears to involve HEAD containing 'ref: refs/heads/foo'\nwhere refs/heads/foo doesn't exist yet, but I get 'not a git repo' instead\nof an orphan detached HEAD with either :>.git/HEAD or rm .git/HEAD.\n\nCheers,\n\nChris.\n"},{"id":"193950","messageId":"7vy5nhvo0z.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120620093205.GB10579@arachsys.com","subject":"Re: Editing the root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-20T18:25:32Z","receivedAt":"2012-06-20T18:25:32Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Chris Webb <chris@arachsys.com> writes:\n>\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>> > Even though I wouldn't bother doing this myself, I wouldn't mind\n>> > reviewing a patch series ;-)\n>> \n>> Okay, I'll take a look when I finish my current project!\n>\n> I had a bit of spare time this morning and had a quick look through\n> git-rebase--interactive.sh.\n>\n> Apart from the validation, message and reflog code in git-rebase.sh and\n> git-rebase--interactive.sh that would need fixing up to know about this\n> case, the essence of this seems to be starting with an orphan commit instead\n> of a commit descended from $onto right at the end of --interactive.\n>\n> I'd love to write something like\n>\n>   git checkout ${onto:---orphan}\n>\n> (or a variant) but can git be persuaded to have an orphan detached HEAD like\n> that?\n\nFor the root commit in the history, you check it out on the detached\nHEAD.  Under \"--interactive\" if the insn sheet tells you to allow\nthe user to \"edit/amend/reword\" it, give control back the user after\nyou have detached HEAD at that commit.  The user experience should\nbe identical to the case you are replaying on an existing commit\nafter that point.\n\nBut lets step back a bit and look at the whole picture, to make sure\nwe are on the same page.\n\n    $ git rebase [-i] frotz\n\nlooks at where you are, finds where you forked from 'frotz', and\nreplays everything you have done since you forked onto the tip of\n'frotz'.\n\n    $ git rebase [-i] --onto nitfol frotz\n\nreplays the same history onto the tip of 'nitfol' instead.\n\n    $ git rebase [-i] --root --onto nitfol\n\nlooks at the entire history leading to where you are, and replays\neverything you have done onto the tip of 'nitfol'.\n\nWhat if we do not say --onto here?  I am not asking what the current\nimplementation does (we get an error message saying \"I want 'onto'\nspecified\").  What _should_ this command mean to a naïve user?\n\n    $ git rebase [-i] --root\n\nI think it should mean \"replay all my history down to root\".  The\noriginal root commit should become the new root commit in the\nrewritten history.\n"},{"id":"193971","messageId":"20120620192938.GC31520@sigill.intra.peff.net","threadId":"30838","inReplyTo":"7vy5nhvo0z.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-20T19:29:38Z","receivedAt":"2012-06-20T19:29:38Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jun 20, 2012 at 11:25:32AM -0700, Junio C Hamano wrote:\n\n> What if we do not say --onto here?  I am not asking what the current\n> implementation does (we get an error message saying \"I want 'onto'\n> specified\").  What _should_ this command mean to a naïve user?\n> \n>     $ git rebase [-i] --root\n> \n> I think it should mean \"replay all my history down to root\".  The\n> original root commit should become the new root commit in the\n> rewritten history.\n\nI think that is the only thing that makes sense. And it should be easy\nwith non-interactive rebase, because we always start with the root commit,\nand it always applies cleanly.\n\nFor interactive rebase, though, it's a little trickier. Earlier you\nsaid:\n\n> For the root commit in the history, you check it out on the detached\n> HEAD.  Under \"--interactive\" if the insn sheet tells you to allow\n> the user to \"edit/amend/reword\" it, give control back the user after\n> you have detached HEAD at that commit.  The user experience should\n> be identical to the case you are replaying on an existing commit\n> after that point.\n\nThat makes sense if the first instruction involves picking that first\ncommit. But if the first commit is deleted (or reordered), then it is\nnot appropriate to detach to the root; we must detach to the first\npicked commit, which we can only do after we see the final instruction\nsheet.\n\nGit-rebase tries to do the rewind before dropping to run_specific_rebase.\nHowever, I think we might be OK, as it seems that there is a special\nexception for \"interactive\", and we drop to run_specific_rebase early in\nthat case.\n\n-Peff\n\nPS I have no clue how multiple roots would do. Without --preserve merges,\n   I would except history to be flattened, and that should be OK (the root\n   commit will become a non-root, just as it would if you were actually\n   going --onto something else).  But I suspect --preserve-merges might be\n   tricky, as you might have to create several root commits during the\n   course of processing the instruction sheet.\n"},{"id":"193976","messageId":"20120620193513.GA3192@arachsys.com","threadId":"30838","inReplyTo":"7vy5nhvo0z.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-20T19:35:14Z","receivedAt":"2012-06-20T19:35:14Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> What if we do not say --onto here?  I am not asking what the current\n> implementation does (we get an error message saying \"I want 'onto'\n> specified\").  What _should_ this command mean to a na??ve user?\n> \n>     $ git rebase [-i] --root\n> \n> I think it should mean \"replay all my history down to root\".  The\n> original root commit should become the new root commit in the\n> rewritten history.\n\nYes, I definitely agree with everything you say here. That's exactly what\nI'd expect from git rebase --root without --onto, and what I'd hope to be\nable to implement in a patch series.\n\n> For the root commit in the history, you check it out on the detached\n> HEAD.  Under \"--interactive\" if the insn sheet tells you to allow\n> the user to \"edit/amend/reword\" it, give control back the user after\n> you have detached HEAD at that commit.  The user experience should\n> be identical to the case you are replaying on an existing commit\n> after that point.\n\nI think it might a little more complicated than detecting when we have to do\na commit --amend on the root commit though? The user might have reordered\nthe first commit (introducing A and B, say) with the second commit\n(introducing C and D), or dropped the original root commit entirely.\n\nMy understanding of the way --interactive works at the moment is that it\nchecks out the starting commit (whether given explicitly by --onto or taken\nfrom <upstream>) and then 'plays out' the commits as described in the\ninstruction sheet.\n\nI could re-use this unchanged if I could do a git checkout --orphan without\nhaving to create a new branch, but I don't think this is allowed: I can have\na detached head or make an orphan checkout onto a new branch, but not both\nat the same time? Would you prefer that I create a temporary branch just to\nbe able to git checkout --orphan onto it here, or that I add support for\nthis kind of 'detached HEAD with no parent' state, or is there a natural way\nto rework --interactive without needing to do this which I'm missing?\n\nBest wishes,\n\nChris.\n"},{"id":"193978","messageId":"20120620193922.GB3192@arachsys.com","threadId":"30838","inReplyTo":"20120620192938.GC31520@sigill.intra.peff.net","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-20T19:39:23Z","receivedAt":"2012-06-20T19:39:23Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> But if the first commit is deleted (or reordered), then it is not\n> appropriate to detach to the root; we must detach to the first picked\n> commit, which we can only do after we see the final instruction sheet.\n\nIt's worse than that isn't it? If you have\n\n  A -- B -- C\n\nand the sheet says drop A, pick B, pick C, you can't detach to B. You want\nthe commit B as a root (i.e. with no parent), not the commit B with parent\nA. You need to have the patch from A to B replayed as the first commit on an\nempty branch (only without the branch).\n\nCheers,\n\nChris.\n"},{"id":"193982","messageId":"20120620194824.GA32228@sigill.intra.peff.net","threadId":"30838","inReplyTo":"20120620193922.GB3192@arachsys.com","subject":"Re: Editing the root commit","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2012-06-20T19:48:24Z","receivedAt":"2012-06-20T19:48:24Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Jun 20, 2012 at 08:39:23PM +0100, Chris Webb wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > But if the first commit is deleted (or reordered), then it is not\n> > appropriate to detach to the root; we must detach to the first picked\n> > commit, which we can only do after we see the final instruction sheet.\n> \n> It's worse than that isn't it? If you have\n> \n>   A -- B -- C\n> \n> and the sheet says drop A, pick B, pick C, you can't detach to B. You want\n> the commit B as a root (i.e. with no parent), not the commit B with parent\n> A. You need to have the patch from A to B replayed as the first commit on an\n> empty branch (only without the branch).\n\nOh, you're right. I think you would have to do some custom magic to make\nthe first commit without looking at HEAD, like:\n\n  1. Erase the index and working tree.\n\n  2. Apply the patch from B^ to B (where B is the first picked commit).\n\n  3. git-commit-tree manually with no parents.\n\n  4. Point HEAD to the newly made commit.\n\nBut there is a very good chance of step (2) causing conflicts, at which\npoint you would have to give control back to the user. And what is in\nHEAD at that point that would give them a meaningful answer to \"git diff\n--cached\" or similar?\n\nI think the only thing you can do is make a fake sentinel commit (with\nan empty tree) to put in HEAD, and then remove the sentinel immediately\nafter the first commit is put in place (making sure not to include it in\nthe first commit's parent list). Yuck.\n\n-Peff\n"},{"id":"194101","messageId":"20120622205026.GI32205@arachsys.com","threadId":"30838","inReplyTo":"20120620194824.GA32228@sigill.intra.peff.net","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-22T20:50:27Z","receivedAt":"2012-06-22T20:50:27Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I think the only thing you can do is make a fake sentinel commit (with\n> an empty tree) to put in HEAD, and then remove the sentinel immediately\n> after the first commit is put in place (making sure not to include it in\n> the first commit's parent list). Yuck.\n\nIf I do this:\n\ndiff --git a/path.c b/path.c\nindex 6f2aa69..1b3b6f3 100644\n--- a/path.c\n+++ b/path.c\n@@ -169,8 +169,9 @@ int validate_headref(const char *path)\n \tint fd;\n \tssize_t len;\n \n+\t/* Allow HEAD to be entirely missing for detached orphan state */\n \tif (lstat(path, &st) < 0)\n-\t\treturn -1;\n+\t\treturn errno == ENOENT ? 0 : -1;\n \n \t/* Make sure it is a \"refs/..\" symlink */\n \tif (S_ISLNK(st.st_mode)) {\n\n\nto thwart the sanity check, I can do 'rm $GIT_DIR/HEAD' to put my HEAD into a\nstate where it is both detached and unborn, i.e. so that my next commit will\nresult in a detached HEAD pointing at a root commit.\n\nSurprisingly, this check appears to be the only thing disallowing such a state,\nand the result behaves as sanely as a normal git-checkout --orphan <branch>\ndoes! Using a detached unborn HEAD like this would avoid any need for sentinel\ncommits or the like in generalising rebase: we'd just do\n\n  git rm -rf .\n  rm -f $GIT_DIR/index $GIT_DIR/HEAD\n\ninstead of git checkout $onto, and be away replaying the commits or executing\nthe instruction sheet as normal.\n\nIf I prepared a proper patch series with docs and tests, would allowing this be\nacceptable? I don't want to work on it if there's an intentional design\ndecision to explicitly disallow it. However, apart from just rebase and\nrebase--interactive, I suspect other scripts which operate on history will be\nmore easily generalised to work on history right up to the root commit if such\na state were allowed.\n\nPS Whilst experimenting, I also noticed a (presumably unintentional) behaviour:\n\n  $ git init .\n  Initialized empty Git repository in /tmp/foo/.git/\n  $ git checkout --detach\n  $ touch bar\n  $ git add bar\n  $ git commit -m test\n  [(null) (root-commit) 17b5bf9] test\n   0 files changed\n   create mode 100644 bar\n  $ ls .git/refs/heads/\n  (null)\n  $\n\nHere we've created a branch with the strange name '(null)' instead of actually\ndetaching, or refusing to detach because we're on an unborn branch.\n\nAssuming this is a bug, I'll cook up a patch to fix it either way, either by\nentering a detached unborn state if we're allowing that, or to refuse to detach\nif we're not allowing that state.\n\nBest wishes,\n\nChris.\n"},{"id":"194106","messageId":"7vobobm3mi.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120622205026.GI32205@arachsys.com","subject":"Re: Editing the root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-22T21:35:33Z","receivedAt":"2012-06-22T21:35:33Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Jeff King <peff@peff.net> writes:\n>\n>> I think the only thing you can do is make a fake sentinel commit (with\n>> an empty tree) to put in HEAD, and then remove the sentinel immediately\n>> after the first commit is put in place (making sure not to include it in\n>> the first commit's parent list). Yuck.\n>\n> If I do this:\n>\n> diff --git a/path.c b/path.c\n> index 6f2aa69..1b3b6f3 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -169,8 +169,9 @@ int validate_headref(const char *path)\n>  \tint fd;\n>  \tssize_t len;\n>  \n> +\t/* Allow HEAD to be entirely missing for detached orphan state */\n>  \tif (lstat(path, &st) < 0)\n> -\t\treturn -1;\n> +\t\treturn errno == ENOENT ? 0 : -1;\n>  \n>  \t/* Make sure it is a \"refs/..\" symlink */\n>  \tif (S_ISLNK(st.st_mode)) {\n>\n>\n> to thwart the sanity check, I can do 'rm $GIT_DIR/HEAD' to put my HEAD into a\n> state where it is both detached and unborn, i.e. so that my next commit will\n> result in a detached HEAD pointing at a root commit.\n\nNo thanks.  It will be too big a change to the fundamental invariant\nfor what a git directory is (and isn't).  It is simply unacceptable\nto suddenly start treating a random directory that does not even\nhave HEAD as a git directory.\n\nIt would be a lot more palatable approach to teach \"rebase -i\" defer\nits \"detaching HEAD to the onto commit\" step before starting to read\nthe insn sheet.  Would such a change be too involved for it to be\nworth supporting \"rebase --root -i\"?\n"},{"id":"194107","messageId":"20120622220231.GG25478@arachsys.com","threadId":"30838","inReplyTo":"7vobobm3mi.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-22T22:02:32Z","receivedAt":"2012-06-22T22:02:32Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n[detached unborn HEAD]\n> No thanks.  It will be too big a change to the fundamental invariant\n> for what a git directory is (and isn't).  It is simply unacceptable\n> to suddenly start treating a random directory that does not even\n> have HEAD as a git directory.\n\nNo problem. I imagine you wouldn't be keen on other representations of the\nsame state either, e.g. a null sha1 in HEAD, and would prefer to disallow\nit altogether?\n\nIn that case, would you like me to do a test and a fix for the '(null)'\nbranch behaviour of\n\n  git checkout --orphan dummy && git checkout --detach\n\n? I assume that can't be intentional: looks from the code like it was\nintended to tell me I'm on an unborn branch and can't do that.\n\n> It would be a lot more palatable approach to teach \"rebase -i\" defer\n> its \"detaching HEAD to the onto commit\" step before starting to read\n> the insn sheet.  Would such a change be too involved for it to be\n> worth supporting \"rebase --root -i\"?\n\nI'm not sure as I don't really know the rebase shell scripts well at all,\nbut I'm happy to take a look and see. I imagine we wouldn't want to make\nrebase -i much more complicated (and consequently harder to work on) just to\ncover this rarely needed variant, but if it's relatively self-contained\n(e.g. detect we're supposed to be making an orphan commit and do it by hand\ninstead of with git commit, maybe?) it would presumably be worthwhile?\n\nCheers,\n\nChris.\n"},{"id":"194109","messageId":"20120622222633.GH25478@arachsys.com","threadId":"30838","inReplyTo":"20120622220231.GG25478@arachsys.com","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-22T22:26:34Z","receivedAt":"2012-06-22T22:26:34Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n> > It would be a lot more palatable approach to teach \"rebase -i\" defer\n> > its \"detaching HEAD to the onto commit\" step before starting to read\n> > the insn sheet.  Would such a change be too involved for it to be\n> > worth supporting \"rebase --root -i\"?\n> \n> I'm not sure as I don't really know the rebase shell scripts well at all,\n> but I'm happy to take a look and see.\n\nIgnoring the implementation, I think the nastiest bit here is what happens\nfor the user if there's a conflict, as Peff pointed out. Ideally, we want to\ncheckout a state we're going to replay the patch onto, so that if we drop\nout because there's conflict (e.g. the patch modifies a file which doesn't\nexist yet), git diff and git diff --cached do something sensible.\n\nWithout a detached orphan checkout, as Peff says, we'd have to put a\ntemporary empty commit in and then manually make the first commit avoiding\nusing it as a parent, which is very ugly. I'll take a look, but might be too\ncomplex to be worth doing for this corner-case.\n\nCheers,\n\nChris.\n"},{"id":"194116","messageId":"7vhau3m06e.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120622222633.GH25478@arachsys.com","subject":"Re: Editing the root commit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-22T22:50:01Z","receivedAt":"2012-06-22T22:50:01Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Ignoring the implementation, I think the nastiest bit here is what happens\n> for the user if there's a conflict, as Peff pointed out. Ideally, we want to\n> checkout a state we're going to replay the patch onto, so that if we drop\n> out because there's conflict (e.g. the patch modifies a file which doesn't\n> exist yet), git diff and git diff --cached do something sensible.\n\nStep back a bit.\n\nIf you are doing \"rebase -i --root\", what does it _mean_ to reorder\ncommits and move the root commit to somewhere else, or insert\nsomething else that is _not_ the root to the beginning of the\nsequence?\n\nIt does not make _any_ sense to me.  For one thing, the root commit\nis to replay \"addition of all these paths\" to void (if you were doing\n\"rebase -i --root --onto $there\", then $there may not be a void, but\nit needs not to have overlapping paths for the result to make any\nsense), and moving it to somewhere _other than_ the root location\ndoes not make much sense.  For another, a non-root commit is mostly\nreplay \"these changes to these existing paths\", and replaying such a\nchange to a void does not make any sense either.\n\nSo in that sense, perhaps\n\n\trebase -i --root\n\nin a history\n\n\tA---B---C\n\nshould behave as if you did\n\n\trebase -i A\n\ngot an insn sheet that looked like\n\n\tpick B\n        pick C\n\nand then you made it to look like\n\n\texec false\n        pick B\n        pick C\n\nto get the control back when the HEAD is detached at A, in order for\nyou to muck with the tree and \"git commit --amend\" to reword the\nmessage.\n"},{"id":"194126","messageId":"20120623072017.GI25478@arachsys.com","threadId":"30838","inReplyTo":"7vhau3m06e.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-23T07:20:17Z","receivedAt":"2012-06-23T07:20:17Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> If you are doing \"rebase -i --root\", what does it _mean_ to reorder\n> commits and move the root commit to somewhere else, or insert\n> something else that is _not_ the root to the beginning of the\n> sequence?\n> \n> It does not make _any_ sense to me.  For one thing, the root commit\n> is to replay \"addition of all these paths\" to void (if you were doing\n> \"rebase -i --root --onto $there\", then $there may not be a void, but\n> it needs not to have overlapping paths for the result to make any\n> sense), and moving it to somewhere _other than_ the root location\n> does not make much sense.  For another, a non-root commit is mostly\n> replay \"these changes to these existing paths\", and replaying such a\n> change to a void does not make any sense either.\n\nAs you say, it depends on the commits you're re-ordering, but in my case the\nfirst few commits were entirely additions, and I wanted to add these files\nin a different order, and add different batches at once, with more sensible\ncommit messages to explain to the reader what was going on. The addition of\nCOPYING from quite a long way forward needed to move right back into the\nfirst commit too.\n\n> So in that sense, perhaps\n> \n> \trebase -i --root\n> \n> in a history\n> \n> \tA---B---C\n> \n> should behave as if you did\n> \n> \trebase -i A\n> \n> got an insn sheet that looked like\n> \n> \tpick B\n>         pick C\n> \n> and then you made it to look like\n> \n> \texec false\n>         pick B\n>         pick C\n> \n> to get the control back when the HEAD is detached at A, in order for\n> you to muck with the tree and \"git commit --amend\" to reword the\n> message.\n\nThat would be easier to implement, certainly, but it makes --root --onto\ninconsistent with --root without --onto, which does work 'in the standard\nway' at present. It's also just a bit of syntactic sugar for something you\ncan already do with rebase -i at present, in exactly the way you describe\nabove.\n\nMaybe it's the best I can sensibly do though. I'm away this weekend, but\nwill see what I can cook up one way or the other next week when the round\ntuit supply is topped up!\n\nCheers,\n\nChris.\n"},{"id":"194218","messageId":"CAOeW2eGnz6d6XdLneH1CQJ+ziD_YJ7yN1N5_YWvULX3nxFsewQ@mail.gmail.com","threadId":"30838","inReplyTo":"7vy5nhvo0z.fsf@alter.siamese.dyndns.org","subject":"Re: Editing the root commit","fromName":"Martin von Zweigbergk","fromEmail":"martin.von.zweigbergk@gmail.com","sentAt":"2012-06-25T17:22:05Z","receivedAt":"2012-06-25T17:22:05Z","isPatch":false,"sender":{"key":"martinvonz@gmail.com","avatar":"https://avatars.githubusercontent.com/u/891642?v=4"},"body":"On Wed, Jun 20, 2012 at 11:25 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n>    $ git rebase [-i] --root --onto nitfol\n>\n> looks at the entire history leading to where you are, and replays\n> everything you have done onto the tip of 'nitfol'.\n>\n> What if we do not say --onto here?\n\nOr even leaving out the --onto for that matter. If I understand\ncorrectly, \"git rebase --root --onto nitfol\" is (more-or-less) just\nsyntactic sugar for \"git rebase nitfol\", see\nhttp://thread.gmane.org/gmane.comp.version-control.git/181024/focus=182054.\n\nI have an old branch from around the time of that thread that make\nthis fact (that \"--root --onto\" is syntactic sugar) a little clearer\nin the code. I'll try to finally send out some of those patches as\nsoon as I can.\n\n>  What _should_ this command mean to a naïve user?\n>\n>    $ git rebase [-i] --root\n>\n> I think it should mean \"replay all my history down to root\".  The\n> original root commit should become the new root commit in the\n> rewritten history.\n\nI agree, and in this case, the --root flag would not just be syntactic sugar.\n\nMartin\n"},{"id":"194272","messageId":"20120626133339.GT9682@arachsys.com","threadId":"30838","inReplyTo":"20120620194824.GA32228@sigill.intra.peff.net","subject":"Re: Editing the root commit","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T13:33:40Z","receivedAt":"2012-06-26T13:33:40Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I think the only thing you can do is make a fake sentinel commit (with\n> an empty tree) to put in HEAD, and then remove the sentinel immediately\n> after the first commit is put in place (making sure not to include it in\n> the first commit's parent list). Yuck.\n\nI thought this would turn out far more horrible than it actually did in\npractice.\n\nThe follow-up patch adds this empty sentinel and then automatically squashes\nit into the root commit(s) as they're picked. The resulting rebase -i --root\ncan handle re-ordering of commits (picking a new root), editing of the root\ncommit, dropping the root commit, and so on.\n\nIn the second patch, I've written some simple tests to demonstrate this and\nto cover cases that seem particularly likely to break, as well as removing a\ntest_must_fail for --root without --onto, because it no longer does!\n\nCheers,\n\nChris.\n"},{"id":"194274","messageId":"bdb45972685db8899a46ebc62213e56c9a3d0c94.1340717793.git.chris@arachsys.com","threadId":"30838","inReplyTo":"20120626133339.GT9682@arachsys.com","subject":"[PATCH 1/2] rebase -i: support --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T13:36:32Z","receivedAt":"2012-06-26T13:36:32Z","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\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n Documentation/git-rebase.txt |    9 +++++----\n git-rebase--interactive.sh   |   24 ++++++++++++++++++------\n git-rebase.sh                |   14 ++++++++++++--\n 3 files changed, 35 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..ed5a6ba 100644\n--- a/git-rebase--interactive.sh\n+++ b/git-rebase--interactive.sh\n@@ -417,6 +417,21 @@ record_in_rewritten() {\n \tesac\n }\n \n+do_pick () {\n+\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n+\tthen\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 +443,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 +464,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":"194273","messageId":"a00f5d0e6ae7e2d07a26b506788ef1270af57558.1340717793.git.chris@arachsys.com","threadId":"30838","inReplyTo":"20120626133339.GT9682@arachsys.com","subject":"[PATCH 2/2] Add tests for rebase -i --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T13:36:33Z","receivedAt":"2012-06-26T13:36:33Z","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":"194281","messageId":"20120626150436.GU9682@arachsys.com","threadId":"30838","inReplyTo":"20120622205026.GI32205@arachsys.com","subject":"git-commit bug (was Re: Editing the root commit)","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T15:04:37Z","receivedAt":"2012-06-26T15:04:37Z","isPatch":false,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> PS Whilst experimenting, I also noticed a (presumably unintentional)\n> behaviour:\n> \n>   $ git init .\n>   Initialized empty Git repository in /tmp/foo/.git/\n>   $ git checkout --detach\n>   $ touch bar\n>   $ git add bar\n>   $ git commit -m test\n>   [(null) (root-commit) 17b5bf9] test\n>    0 files changed\n>    create mode 100644 bar\n>   $ ls .git/refs/heads/\n>   (null)\n>   $\n> \n> Here we've created a branch with the strange name '(null)' instead of\n> actually detaching, or refusing to detach because we're on an unborn\n> branch.\n\nThis was introduced by abe199808c, which is intended to allow\n\n  git init . && git checkout --orphan newbranch\n\nbut presumably wasn't also meant to enable\n\n  git checkout --orphan foo\n  git checkout --detach\n\nThis leads to a printf(\"%s\", NULL) and thus\n\n  $ git symbolic-ref HEAD\n  refs/heads/(null)\n\nI've followed up to this message with a patch including a test to catch this\nin future.\n\nBest wishes,\n\nChris.\n"},{"id":"194282","messageId":"b9069a6c6af42f4771c5a5c1c812800c21926622.1340723202.git.chris@arachsys.com","threadId":"30838","inReplyTo":"20120626150436.GU9682@arachsys.com","subject":"[PATCH] git-checkout: disallow --detach on unborn branch","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T15:06:42Z","receivedAt":"2012-06-26T15:06:42Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"abe199808c (git checkout -b: allow switching out of an unborn branch)\nintroduced a bug demonstrated by\n\n  git checkout --orphan foo\n  git checkout --detach\n  git symbolic-ref HEAD\n\nwhich gives 'refs/heads/(null)'.\n\nThis happens because we strbuf_addf(&branch_ref, \"refs/heads/%s\",\nopts->new_branch) when opts->new_branch can be NULL for --detach.\n\nCatch and forbid this case, adding a test to t2017 to catch it in\nfuture.\n\nSigned-off-by: Chris Webb <chris@arachsys.com>\n---\n builtin/checkout.c         |    2 ++\n t/t2017-checkout-orphan.sh |    6 ++++++\n 2 files changed, 8 insertions(+)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex e8c1b1f..3980d5d 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -915,6 +915,8 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts)\n \tint status;\n \tstruct strbuf branch_ref = STRBUF_INIT;\n \n+\tif (!opts->new_branch)\n+\t\tdie(_(\"You are on a branch yet to be born\"));\n \tstrbuf_addf(&branch_ref, \"refs/heads/%s\", opts->new_branch);\n \tstatus = create_symref(\"HEAD\", branch_ref.buf, \"checkout -b\");\n \tstrbuf_release(&branch_ref);\ndiff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh\nindex 0e3b858..655f278 100755\n--- a/t/t2017-checkout-orphan.sh\n+++ b/t/t2017-checkout-orphan.sh\n@@ -116,4 +116,10 @@ test_expect_success '--orphan refuses to switch if a merge is needed' '\n \tgit reset --hard\n '\n \n+test_expect_success 'cannot --detach on an unborn branch' '\n+\tgit checkout master &&\n+\tgit checkout --orphan new &&\n+\ttest_must_fail git checkout --detach\n+'\n+\n test_done\n-- \n1.7.10\n"},{"id":"194295","messageId":"7vy5naaqut.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120626150436.GU9682@arachsys.com","subject":"Re: git-commit bug","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-26T18:08:10Z","receivedAt":"2012-06-26T18:08:10Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Chris Webb <chris@arachsys.com> writes:\n\n> Chris Webb <chris@arachsys.com> writes:\n>\n>> PS Whilst experimenting, I also noticed a (presumably unintentional)\n>> behaviour:\n>> \n>>   $ git init .\n>>   Initialized empty Git repository in /tmp/foo/.git/\n>>   $ git checkout --detach\n>>   $ touch bar\n>>   $ git add bar\n>>   $ git commit -m test\n>>   [(null) (root-commit) 17b5bf9] test\n>>    0 files changed\n>>    create mode 100644 bar\n>>   $ ls .git/refs/heads/\n>>   (null)\n>>   $\n>> \n>> Here we've created a branch with the strange name '(null)' instead of\n>> actually detaching, or refusing to detach because we're on an unborn\n>> branch.\n>\n> This was introduced by abe199808c, which is intended to allow\n>\n>   git init . && git checkout --orphan newbranch\n>\n> but presumably wasn't also meant to enable\n>\n>   git checkout --orphan foo\n>   git checkout --detach\n\nCorrect.\n\nOn days like this, I really regret accepting that --orphan crap in\nthe first place.\n\nThanks for fixing things up.\n\n> This leads to a printf(\"%s\", NULL) and thus\n>\n>   $ git symbolic-ref HEAD\n>   refs/heads/(null)\n>\n> I've followed up to this message with a patch including a test to catch this\n> in future.\n>\n> Best wishes,\n>\n> Chris.\n"},{"id":"194304","messageId":"7vtxxxc22x.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"bdb45972685db8899a46ebc62213e56c9a3d0c94.1340717793.git.chris@arachsys.com","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-26T19:20:22Z","receivedAt":"2012-06-26T19:20:22Z","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> +do_pick () {\n> +\tif test \"$(git rev-parse HEAD)\" = \"$squash_onto\"\n\nThe idea to create a sentinel root upfront and special case it here\nis a good one.\n\n> +\tthen\n\nI am not quite sure what is going on in this \"then\" clause.\n\n> +\t\tgit commit --allow-empty --allow-empty-message --amend \\\n> +\t\t\t   --no-post-rewrite -n -q -C $1 &&\n\nAt this point, nobody touched the empty sentinel root yet; you\nrewrite its log message and authorship using the picked commit.\n\n> +\t\t\tpick_one -n $1 &&\n\nAnd then you create a new commit that records the update \"$1\" does\nrelative to its parent (this hopefully only contains additions -- is\nit sensible to die-with-patch if it doesn't?), making sure that it\ndoes not fast-forward.  Does this always make the result a root commit?\nIf \"$1\" has parents, wouldn't it become a child of the commits its\nparents were rewritten to (if any) in pick_one_preserving_merges()\nthat is called from pick_one?\n\n> +\t\t\tgit commit --allow-empty --allow-empty-message \\\n> +\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 ||\n\nAnd then you rewrite the log and authorship of that one.\n\nIn short, my questions are:\n\n (1) what is the purpose of the first \"commit --amend\" to update the\n     sentinel root commit?\n\n (2) Is the purpose of \"pick_one -n\" done here to create a root\n     commit?  Does it always do so correctly?\n\n> diff --git a/git-rebase.sh b/git-rebase.sh\n> index 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\nThis makes \"git rebase --root\" without $onto imply \"-i\", which makes\nsense, but it was a bit unexpected (it wasn't in the proposed log\nmessage).\n"},{"id":"194305","messageId":"20120626193817.GD30779@arachsys.com","threadId":"30838","inReplyTo":"7vtxxxc22x.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T19:38:18Z","receivedAt":"2012-06-26T19:38:18Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> I am not quite sure what is going on in this \"then\" clause.\n> \n> Chris Webb <chris@arachsys.com> writes:\n>\n> > +\t\tgit commit --allow-empty --allow-empty-message --amend \\\n> > +\t\t\t   --no-post-rewrite -n -q -C $1 &&\n> \n> At this point, nobody touched the empty sentinel root yet; you\n> rewrite its log message and authorship using the picked commit.\n> \n> > +\t\t\tpick_one -n $1 &&\n> \n> And then you create a new commit that records the update \"$1\" does\n> relative to its parent (this hopefully only contains additions -- is\n> it sensible to die-with-patch if it doesn't?), making sure that it\n> does not fast-forward.  Does this always make the result a root commit?\n> If \"$1\" has parents, wouldn't it become a child of the commits its\n> parents were rewritten to (if any) in pick_one_preserving_merges()\n> that is called from pick_one?\n> \n> > +\t\t\tgit commit --allow-empty --allow-empty-message \\\n> > +\t\t\t\t   --amend --no-post-rewrite -n -q -C $1 ||\n> \n> And then you rewrite the log and authorship of that one.\n> \n> In short, my questions are:\n> \n>  (1) what is the purpose of the first \"commit --amend\" to update the\n>      sentinel root commit?\n\nThis first commit --amend isn't supposed to change the empty tree in the\ncommit: the tree and index should be unchanged at this point. I'm only\nrunning it to set the commit message and author.\n\nThe idea here is that I want the author and commit message already in place\nif cherry-pick (and hence pick_one -n) fails so that we drop out for the\nuser to resolve conflicts.\n\nThis seems to be the way git cherry-pick or git merge behave when they need\nconflicts resolving, and I wanted the behaviour to be consistent to avoid\nsurprises.\n\nIs there a way of explicitly writing my commit --amend to make this\nintention clearer? Would a -o without paths spell this out, or would it just\nmake thing more confusing?\n\n>  (2) Is the purpose of \"pick_one -n\" done here to create a root\n>      commit?  Does it always do so correctly?\n\npick_one -n cherry-picks the changes without actually making a commit. It's\nalready used in the squash case, so should be well-tested.\n\nFollowing this, the second commit --amend actually commits those changes,\namending the sentinel. I don't change the message at all at this stage\nbecause it's already correct.\n\nSimilar question to before: is there a clearer way to ask commit --amend to\nleave the author and commit message unchanged rather than supply them\nexplicitly all over again, or shall I just comment to explain the intention?\nEDITOR=: perhaps?\n\n> This makes \"git rebase --root\" without $onto imply \"-i\", which makes\n> sense, but it was a bit unexpected (it wasn't in the proposed log\n> message).\n\nYes, sorry, you're quite right. It's only mentioned in the tests patch.\n\nWould you prefer me to make this change in a separate patch, and generate an\nerror for this case in the initial commit, or just explain it properly in\nthe log message to go with the original combined patch?\n\nBest wishes,\n\nChris.\n"},{"id":"194310","messageId":"7vfw9hbzz5.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120626193817.GD30779@arachsys.com","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-26T20:05:50Z","receivedAt":"2012-06-26T20:05:50Z","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>> In short, my questions are:\n>> \n>>  (1) what is the purpose of the first \"commit --amend\" to update the\n>>      sentinel root commit?\n>\n> This first commit --amend isn't supposed to change the empty tree in the\n> commit: the tree and index should be unchanged at this point. I'm only\n> running it to set the commit message and author.\n>\n> The idea here is that I want the author and commit message already in place\n> if cherry-pick (and hence pick_one -n) fails so that we drop out for the\n> user to resolve conflicts.\n\nVery understandable.  Perhaps in-code comments would have helped.\n\n>>  (2) Is the purpose of \"pick_one -n\" done here to create a root\n>>      commit?  Does it always do so correctly?\n>\n> pick_one -n cherry-picks the changes without actually making a commit. It's\n> already used in the squash case, so should be well-tested.\n\nOK.\n"},{"id":"194311","messageId":"20120626201155.GE5864@arachsys.com","threadId":"30838","inReplyTo":"7vfw9hbzz5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T20:11:56Z","receivedAt":"2012-06-26T20:11:56Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Very understandable.  Perhaps in-code comments would have helped.\n\nShall I re-spin this with a comment to explain what's going on, and to\nmention the implicit -i with rebase --root without -i, or would you prefer\nto queue the existing version with any clarifications you think appropriate?\n\nBest wishes,\n\nChris.\n"},{"id":"194315","messageId":"7vwr2tahs8.fsf@alter.siamese.dyndns.org","threadId":"30838","inReplyTo":"20120626201155.GE5864@arachsys.com","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-06-26T21:24:07Z","receivedAt":"2012-06-26T21:24:07Z","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> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> Very understandable.  Perhaps in-code comments would have helped.\n>\n> Shall I re-spin this with a comment to explain what's going on, and to\n> mention the implicit -i with rebase --root without -i, or would you prefer\n> to queue the existing version with any clarifications you think appropriate?\n\nA reroll would be preferred, as it would be less work for me ;-)\n\nThanks.\n"},{"id":"194316","messageId":"20120626212711.GB11498@arachsys.com","threadId":"30838","inReplyTo":"7vwr2tahs8.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 1/2] rebase -i: support --root without --onto","fromName":"Chris Webb","fromEmail":"chris@arachsys.com","sentAt":"2012-06-26T21:27:11Z","receivedAt":"2012-06-26T21:27:11Z","isPatch":true,"sender":{"key":"chris@arachsys.com","avatar":"https://avatars.githubusercontent.com/u/299056?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Chris Webb <chris@arachsys.com> writes:\n> \n> > Junio C Hamano <gitster@pobox.com> writes:\n> >\n> >> Very understandable.  Perhaps in-code comments would have helped.\n> >\n> > Shall I re-spin this with a comment to explain what's going on, and to\n> > mention the implicit -i with rebase --root without -i, or would you prefer\n> > to queue the existing version with any clarifications you think appropriate?\n> \n> A reroll would be preferred, as it would be less work for me ;-)\n\nNo problem, I'll do that now. Thanks for the feedback and all your help with\nthis patch series.\n\nBest wishes,\n\nChris.\n"}]}