* Editing the root commit @ 2012-06-19 9:16 Chris Webb 2012-06-19 10:09 ` Junio C Hamano 2012-06-19 11:50 ` jaseem abid 0 siblings, 2 replies; 29+ messages in thread From: Chris Webb @ 2012-06-19 9:16 UTC (permalink / raw) To: git I've recently been polishing up some private code for release, using git rebase --interactive to expand on some commit messages. In a couple of cases, I wanted to edit the root commit. (Adding a COPYING file, for example.) I've been successfully doing this with an explicit ROOT=$(git log --pretty=format:%H | tail -n 1) git checkout $ROOT git commit --amend --message='Initial import modified' # for example git rebase --onto HEAD $ROOT master However, this brought two questions to mind. The first is whether there's a clever symbolic way to refer to the root of the current branch, rather than tailing git log output? gitrevisions(7) doesn't obviously suggest one. The second question is whether it's possible to use git rebase --interactive to edit the root commit along with some subsequent ones in one fell swoop? My fingers half-remember doing something like git checkout --orphan rewritten git rm -rf git rebase --interactive --root --onto rewritten master a year or so ago, but this now fails (on git 1.7.10) with the somewhat surprising error $ git rebase --root --onto rewritten master fatal: Needed a single revision Does not point to a valid commit: master Am I misremembering the recipe here, or has the behaviour changed? It seems to fail identically with or without --interactive. Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-19 9:16 Editing the root commit Chris Webb @ 2012-06-19 10:09 ` Junio C Hamano 2012-06-19 11:17 ` Chris Webb 2012-06-19 11:50 ` jaseem abid 1 sibling, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-19 10:09 UTC (permalink / raw) To: Chris Webb; +Cc: git Chris Webb <chris@arachsys.com> writes: > The first is whether there's a clever symbolic way to refer to the root of > the current branch, rather than tailing git log output? gitrevisions(7) > doesn't obviously suggest one. There is not, for a few good reasons. The very first commit is no more special than any other commit in the history. Some projects may start with "the first working version", in which case there may be some value to be able to refer to it, while some other projects may start with "the initial snapshot" whose specialness comes _only_ from it being the first one. "The first working version" specialness may deserve to be tagged, and in that case you would already have a name to refer to it. If on the other hand the first one isn't even worth to be tagged, it does not deserve to waste a short-hand to refer to it at the machinery level. So there is nothing listed in the gitrevisions(7) for it. Also there is a more important question: Which root commit? There does not necessarily have to be a single "the root" commit in the history. > git checkout --orphan rewritten > git rm -rf > git rebase --interactive --root --onto rewritten master The argument to "--onto" must be a commit, but "checkout --orphan" is not a way to create a commit; it is a way to bring you to a state without any commit. I personally think "git rebase -i --root" should be made to just work without requiring "--onto" and let you "edit" even the first one in the history. It is understandable that nobody bothered, as people are a lot less often rewriting near the very beginning of the history than otherwise. Even though I wouldn't bother doing this myself, I wouldn't mind reviewing a patch series ;-) ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-19 10:09 ` Junio C Hamano @ 2012-06-19 11:17 ` Chris Webb 2012-06-20 9:32 ` Chris Webb 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-19 11:17 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Junio C Hamano <gitster@pobox.com> writes: [symbolic reference to root commit] > Also there is a more important question: Which root commit? There > does not necessarily have to be a single "the root" commit in the > history. Ah yes, very good point. Anything with a subtree merge would have several roots, for example. I suppose the thing that makes root commits special is their lack of parents, so the most direct way to get a list of root commits for the current branch would just be git rev-list --max-parents=0 HEAD making the recipe ROOT=$(git rev-list --max-parents=0 master) git checkout "$ROOT" -- # will fail if more than one root git commit --amend git rebase [--interactive] --onto HEAD "$ROOT" master > I personally think "git rebase -i --root" should be made to just > work without requiring "--onto" and let you "edit" even the first > one in the history. It is understandable that nobody bothered, as > people are a lot less often rewriting near the very beginning of the > history than otherwise. > > Even though I wouldn't bother doing this myself, I wouldn't mind > reviewing a patch series ;-) Okay, I'll take a look when I finish my current project! Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-19 11:17 ` Chris Webb @ 2012-06-20 9:32 ` Chris Webb 2012-06-20 18:25 ` Junio C Hamano 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-20 9:32 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Chris Webb <chris@arachsys.com> writes: > Junio C Hamano <gitster@pobox.com> writes: > > > Even though I wouldn't bother doing this myself, I wouldn't mind > > reviewing a patch series ;-) > > Okay, I'll take a look when I finish my current project! I had a bit of spare time this morning and had a quick look through git-rebase--interactive.sh. Apart from the validation, message and reflog code in git-rebase.sh and git-rebase--interactive.sh that would need fixing up to know about this case, the essence of this seems to be starting with an orphan commit instead of a commit descended from $onto right at the end of --interactive. I'd love to write something like git checkout ${onto:---orphan} (or a variant) but can git be persuaded to have an orphan detached HEAD like that? An orphan branch appears to involve HEAD containing 'ref: refs/heads/foo' where refs/heads/foo doesn't exist yet, but I get 'not a git repo' instead of an orphan detached HEAD with either :>.git/HEAD or rm .git/HEAD. Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 9:32 ` Chris Webb @ 2012-06-20 18:25 ` Junio C Hamano 2012-06-20 19:29 ` Jeff King ` (2 more replies) 0 siblings, 3 replies; 29+ messages in thread From: Junio C Hamano @ 2012-06-20 18:25 UTC (permalink / raw) To: Chris Webb; +Cc: git Chris Webb <chris@arachsys.com> writes: > Chris Webb <chris@arachsys.com> writes: > >> Junio C Hamano <gitster@pobox.com> writes: >> >> > Even though I wouldn't bother doing this myself, I wouldn't mind >> > reviewing a patch series ;-) >> >> Okay, I'll take a look when I finish my current project! > > I had a bit of spare time this morning and had a quick look through > git-rebase--interactive.sh. > > Apart from the validation, message and reflog code in git-rebase.sh and > git-rebase--interactive.sh that would need fixing up to know about this > case, the essence of this seems to be starting with an orphan commit instead > of a commit descended from $onto right at the end of --interactive. > > I'd love to write something like > > git checkout ${onto:---orphan} > > (or a variant) but can git be persuaded to have an orphan detached HEAD like > that? For the root commit in the history, you check it out on the detached HEAD. Under "--interactive" if the insn sheet tells you to allow the user to "edit/amend/reword" it, give control back the user after you have detached HEAD at that commit. The user experience should be identical to the case you are replaying on an existing commit after that point. But lets step back a bit and look at the whole picture, to make sure we are on the same page. $ git rebase [-i] frotz looks at where you are, finds where you forked from 'frotz', and replays everything you have done since you forked onto the tip of 'frotz'. $ git rebase [-i] --onto nitfol frotz replays the same history onto the tip of 'nitfol' instead. $ git rebase [-i] --root --onto nitfol looks at the entire history leading to where you are, and replays everything you have done onto the tip of 'nitfol'. What if we do not say --onto here? I am not asking what the current implementation does (we get an error message saying "I want 'onto' specified"). What _should_ this command mean to a naïve user? $ git rebase [-i] --root I think it should mean "replay all my history down to root". The original root commit should become the new root commit in the rewritten history. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 18:25 ` Junio C Hamano @ 2012-06-20 19:29 ` Jeff King 2012-06-20 19:39 ` Chris Webb 2012-06-20 19:35 ` Editing the root commit Chris Webb 2012-06-25 17:22 ` Martin von Zweigbergk 2 siblings, 1 reply; 29+ messages in thread From: Jeff King @ 2012-06-20 19:29 UTC (permalink / raw) To: Junio C Hamano; +Cc: Chris Webb, git On Wed, Jun 20, 2012 at 11:25:32AM -0700, Junio C Hamano wrote: > What if we do not say --onto here? I am not asking what the current > implementation does (we get an error message saying "I want 'onto' > specified"). What _should_ this command mean to a naïve user? > > $ git rebase [-i] --root > > I think it should mean "replay all my history down to root". The > original root commit should become the new root commit in the > rewritten history. I think that is the only thing that makes sense. And it should be easy with non-interactive rebase, because we always start with the root commit, and it always applies cleanly. For interactive rebase, though, it's a little trickier. Earlier you said: > For the root commit in the history, you check it out on the detached > HEAD. Under "--interactive" if the insn sheet tells you to allow > the user to "edit/amend/reword" it, give control back the user after > you have detached HEAD at that commit. The user experience should > be identical to the case you are replaying on an existing commit > after that point. That makes sense if the first instruction involves picking that first commit. But if the first commit is deleted (or reordered), then it is not appropriate to detach to the root; we must detach to the first picked commit, which we can only do after we see the final instruction sheet. Git-rebase tries to do the rewind before dropping to run_specific_rebase. However, I think we might be OK, as it seems that there is a special exception for "interactive", and we drop to run_specific_rebase early in that case. -Peff PS I have no clue how multiple roots would do. Without --preserve merges, I would except history to be flattened, and that should be OK (the root commit will become a non-root, just as it would if you were actually going --onto something else). But I suspect --preserve-merges might be tricky, as you might have to create several root commits during the course of processing the instruction sheet. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 19:29 ` Jeff King @ 2012-06-20 19:39 ` Chris Webb 2012-06-20 19:48 ` Jeff King 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-20 19:39 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, git Jeff King <peff@peff.net> writes: > But if the first commit is deleted (or reordered), then it is not > appropriate to detach to the root; we must detach to the first picked > commit, which we can only do after we see the final instruction sheet. It's worse than that isn't it? If you have A -- B -- C and the sheet says drop A, pick B, pick C, you can't detach to B. You want the commit B as a root (i.e. with no parent), not the commit B with parent A. You need to have the patch from A to B replayed as the first commit on an empty branch (only without the branch). Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 19:39 ` Chris Webb @ 2012-06-20 19:48 ` Jeff King 2012-06-22 20:50 ` Chris Webb 2012-06-26 13:33 ` Editing the root commit Chris Webb 0 siblings, 2 replies; 29+ messages in thread From: Jeff King @ 2012-06-20 19:48 UTC (permalink / raw) To: Chris Webb; +Cc: Junio C Hamano, git On Wed, Jun 20, 2012 at 08:39:23PM +0100, Chris Webb wrote: > Jeff King <peff@peff.net> writes: > > > But if the first commit is deleted (or reordered), then it is not > > appropriate to detach to the root; we must detach to the first picked > > commit, which we can only do after we see the final instruction sheet. > > It's worse than that isn't it? If you have > > A -- B -- C > > and the sheet says drop A, pick B, pick C, you can't detach to B. You want > the commit B as a root (i.e. with no parent), not the commit B with parent > A. You need to have the patch from A to B replayed as the first commit on an > empty branch (only without the branch). Oh, you're right. I think you would have to do some custom magic to make the first commit without looking at HEAD, like: 1. Erase the index and working tree. 2. Apply the patch from B^ to B (where B is the first picked commit). 3. git-commit-tree manually with no parents. 4. Point HEAD to the newly made commit. But there is a very good chance of step (2) causing conflicts, at which point you would have to give control back to the user. And what is in HEAD at that point that would give them a meaningful answer to "git diff --cached" or similar? I think the only thing you can do is make a fake sentinel commit (with an empty tree) to put in HEAD, and then remove the sentinel immediately after the first commit is put in place (making sure not to include it in the first commit's parent list). Yuck. -Peff ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 19:48 ` Jeff King @ 2012-06-22 20:50 ` Chris Webb 2012-06-22 21:35 ` Junio C Hamano 2012-06-26 15:04 ` git-commit bug (was Re: Editing the root commit) Chris Webb 2012-06-26 13:33 ` Editing the root commit Chris Webb 1 sibling, 2 replies; 29+ messages in thread From: Chris Webb @ 2012-06-22 20:50 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, git Jeff King <peff@peff.net> writes: > I think the only thing you can do is make a fake sentinel commit (with > an empty tree) to put in HEAD, and then remove the sentinel immediately > after the first commit is put in place (making sure not to include it in > the first commit's parent list). Yuck. If I do this: diff --git a/path.c b/path.c index 6f2aa69..1b3b6f3 100644 --- a/path.c +++ b/path.c @@ -169,8 +169,9 @@ int validate_headref(const char *path) int fd; ssize_t len; + /* Allow HEAD to be entirely missing for detached orphan state */ if (lstat(path, &st) < 0) - return -1; + return errno == ENOENT ? 0 : -1; /* Make sure it is a "refs/.." symlink */ if (S_ISLNK(st.st_mode)) { to thwart the sanity check, I can do 'rm $GIT_DIR/HEAD' to put my HEAD into a state where it is both detached and unborn, i.e. so that my next commit will result in a detached HEAD pointing at a root commit. Surprisingly, this check appears to be the only thing disallowing such a state, and the result behaves as sanely as a normal git-checkout --orphan <branch> does! Using a detached unborn HEAD like this would avoid any need for sentinel commits or the like in generalising rebase: we'd just do git rm -rf . rm -f $GIT_DIR/index $GIT_DIR/HEAD instead of git checkout $onto, and be away replaying the commits or executing the instruction sheet as normal. If I prepared a proper patch series with docs and tests, would allowing this be acceptable? I don't want to work on it if there's an intentional design decision to explicitly disallow it. However, apart from just rebase and rebase--interactive, I suspect other scripts which operate on history will be more easily generalised to work on history right up to the root commit if such a state were allowed. PS Whilst experimenting, I also noticed a (presumably unintentional) behaviour: $ git init . Initialized empty Git repository in /tmp/foo/.git/ $ git checkout --detach $ touch bar $ git add bar $ git commit -m test [(null) (root-commit) 17b5bf9] test 0 files changed create mode 100644 bar $ ls .git/refs/heads/ (null) $ Here we've created a branch with the strange name '(null)' instead of actually detaching, or refusing to detach because we're on an unborn branch. Assuming this is a bug, I'll cook up a patch to fix it either way, either by entering a detached unborn state if we're allowing that, or to refuse to detach if we're not allowing that state. Best wishes, Chris. ^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-22 20:50 ` Chris Webb @ 2012-06-22 21:35 ` Junio C Hamano 2012-06-22 22:02 ` Chris Webb 2012-06-26 15:04 ` git-commit bug (was Re: Editing the root commit) Chris Webb 1 sibling, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-22 21:35 UTC (permalink / raw) To: Chris Webb; +Cc: Jeff King, git Chris Webb <chris@arachsys.com> writes: > Jeff King <peff@peff.net> writes: > >> I think the only thing you can do is make a fake sentinel commit (with >> an empty tree) to put in HEAD, and then remove the sentinel immediately >> after the first commit is put in place (making sure not to include it in >> the first commit's parent list). Yuck. > > If I do this: > > diff --git a/path.c b/path.c > index 6f2aa69..1b3b6f3 100644 > --- a/path.c > +++ b/path.c > @@ -169,8 +169,9 @@ int validate_headref(const char *path) > int fd; > ssize_t len; > > + /* Allow HEAD to be entirely missing for detached orphan state */ > if (lstat(path, &st) < 0) > - return -1; > + return errno == ENOENT ? 0 : -1; > > /* Make sure it is a "refs/.." symlink */ > if (S_ISLNK(st.st_mode)) { > > > to thwart the sanity check, I can do 'rm $GIT_DIR/HEAD' to put my HEAD into a > state where it is both detached and unborn, i.e. so that my next commit will > result in a detached HEAD pointing at a root commit. No thanks. It will be too big a change to the fundamental invariant for what a git directory is (and isn't). It is simply unacceptable to suddenly start treating a random directory that does not even have HEAD as a git directory. It would be a lot more palatable approach to teach "rebase -i" defer its "detaching HEAD to the onto commit" step before starting to read the insn sheet. Would such a change be too involved for it to be worth supporting "rebase --root -i"? ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-22 21:35 ` Junio C Hamano @ 2012-06-22 22:02 ` Chris Webb 2012-06-22 22:26 ` Chris Webb 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-22 22:02 UTC (permalink / raw) To: Junio C Hamano; +Cc: Jeff King, git Junio C Hamano <gitster@pobox.com> writes: [detached unborn HEAD] > No thanks. It will be too big a change to the fundamental invariant > for what a git directory is (and isn't). It is simply unacceptable > to suddenly start treating a random directory that does not even > have HEAD as a git directory. No problem. I imagine you wouldn't be keen on other representations of the same state either, e.g. a null sha1 in HEAD, and would prefer to disallow it altogether? In that case, would you like me to do a test and a fix for the '(null)' branch behaviour of git checkout --orphan dummy && git checkout --detach ? I assume that can't be intentional: looks from the code like it was intended to tell me I'm on an unborn branch and can't do that. > It would be a lot more palatable approach to teach "rebase -i" defer > its "detaching HEAD to the onto commit" step before starting to read > the insn sheet. Would such a change be too involved for it to be > worth supporting "rebase --root -i"? I'm not sure as I don't really know the rebase shell scripts well at all, but I'm happy to take a look and see. I imagine we wouldn't want to make rebase -i much more complicated (and consequently harder to work on) just to cover this rarely needed variant, but if it's relatively self-contained (e.g. detect we're supposed to be making an orphan commit and do it by hand instead of with git commit, maybe?) it would presumably be worthwhile? Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-22 22:02 ` Chris Webb @ 2012-06-22 22:26 ` Chris Webb 2012-06-22 22:50 ` Junio C Hamano 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-22 22:26 UTC (permalink / raw) To: Junio C Hamano; +Cc: Jeff King, git Chris Webb <chris@arachsys.com> writes: > Junio C Hamano <gitster@pobox.com> writes: > > > It would be a lot more palatable approach to teach "rebase -i" defer > > its "detaching HEAD to the onto commit" step before starting to read > > the insn sheet. Would such a change be too involved for it to be > > worth supporting "rebase --root -i"? > > I'm not sure as I don't really know the rebase shell scripts well at all, > but I'm happy to take a look and see. Ignoring the implementation, I think the nastiest bit here is what happens for the user if there's a conflict, as Peff pointed out. Ideally, we want to checkout a state we're going to replay the patch onto, so that if we drop out because there's conflict (e.g. the patch modifies a file which doesn't exist yet), git diff and git diff --cached do something sensible. Without a detached orphan checkout, as Peff says, we'd have to put a temporary empty commit in and then manually make the first commit avoiding using it as a parent, which is very ugly. I'll take a look, but might be too complex to be worth doing for this corner-case. Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-22 22:26 ` Chris Webb @ 2012-06-22 22:50 ` Junio C Hamano 2012-06-23 7:20 ` Chris Webb 0 siblings, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-22 22:50 UTC (permalink / raw) To: Chris Webb; +Cc: Jeff King, git Chris Webb <chris@arachsys.com> writes: > Ignoring the implementation, I think the nastiest bit here is what happens > for the user if there's a conflict, as Peff pointed out. Ideally, we want to > checkout a state we're going to replay the patch onto, so that if we drop > out because there's conflict (e.g. the patch modifies a file which doesn't > exist yet), git diff and git diff --cached do something sensible. Step back a bit. If you are doing "rebase -i --root", what does it _mean_ to reorder commits and move the root commit to somewhere else, or insert something else that is _not_ the root to the beginning of the sequence? It does not make _any_ sense to me. For one thing, the root commit is to replay "addition of all these paths" to void (if you were doing "rebase -i --root --onto $there", then $there may not be a void, but it needs not to have overlapping paths for the result to make any sense), and moving it to somewhere _other than_ the root location does not make much sense. For another, a non-root commit is mostly replay "these changes to these existing paths", and replaying such a change to a void does not make any sense either. So in that sense, perhaps rebase -i --root in a history A---B---C should behave as if you did rebase -i A got an insn sheet that looked like pick B pick C and then you made it to look like exec false pick B pick C to get the control back when the HEAD is detached at A, in order for you to muck with the tree and "git commit --amend" to reword the message. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-22 22:50 ` Junio C Hamano @ 2012-06-23 7:20 ` Chris Webb 0 siblings, 0 replies; 29+ messages in thread From: Chris Webb @ 2012-06-23 7:20 UTC (permalink / raw) To: Junio C Hamano; +Cc: Jeff King, git Junio C Hamano <gitster@pobox.com> writes: > If you are doing "rebase -i --root", what does it _mean_ to reorder > commits and move the root commit to somewhere else, or insert > something else that is _not_ the root to the beginning of the > sequence? > > It does not make _any_ sense to me. For one thing, the root commit > is to replay "addition of all these paths" to void (if you were doing > "rebase -i --root --onto $there", then $there may not be a void, but > it needs not to have overlapping paths for the result to make any > sense), and moving it to somewhere _other than_ the root location > does not make much sense. For another, a non-root commit is mostly > replay "these changes to these existing paths", and replaying such a > change to a void does not make any sense either. As you say, it depends on the commits you're re-ordering, but in my case the first few commits were entirely additions, and I wanted to add these files in a different order, and add different batches at once, with more sensible commit messages to explain to the reader what was going on. The addition of COPYING from quite a long way forward needed to move right back into the first commit too. > So in that sense, perhaps > > rebase -i --root > > in a history > > A---B---C > > should behave as if you did > > rebase -i A > > got an insn sheet that looked like > > pick B > pick C > > and then you made it to look like > > exec false > pick B > pick C > > to get the control back when the HEAD is detached at A, in order for > you to muck with the tree and "git commit --amend" to reword the > message. That would be easier to implement, certainly, but it makes --root --onto inconsistent with --root without --onto, which does work 'in the standard way' at present. It's also just a bit of syntactic sugar for something you can already do with rebase -i at present, in exactly the way you describe above. Maybe it's the best I can sensibly do though. I'm away this weekend, but will see what I can cook up one way or the other next week when the round tuit supply is topped up! Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* git-commit bug (was Re: Editing the root commit) 2012-06-22 20:50 ` Chris Webb 2012-06-22 21:35 ` Junio C Hamano @ 2012-06-26 15:04 ` Chris Webb 2012-06-26 15:06 ` [PATCH] git-checkout: disallow --detach on unborn branch Chris Webb 2012-06-26 18:08 ` git-commit bug Junio C Hamano 1 sibling, 2 replies; 29+ messages in thread From: Chris Webb @ 2012-06-26 15:04 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, git Chris Webb <chris@arachsys.com> writes: > PS Whilst experimenting, I also noticed a (presumably unintentional) > behaviour: > > $ git init . > Initialized empty Git repository in /tmp/foo/.git/ > $ git checkout --detach > $ touch bar > $ git add bar > $ git commit -m test > [(null) (root-commit) 17b5bf9] test > 0 files changed > create mode 100644 bar > $ ls .git/refs/heads/ > (null) > $ > > Here we've created a branch with the strange name '(null)' instead of > actually detaching, or refusing to detach because we're on an unborn > branch. This was introduced by abe199808c, which is intended to allow git init . && git checkout --orphan newbranch but presumably wasn't also meant to enable git checkout --orphan foo git checkout --detach This leads to a printf("%s", NULL) and thus $ git symbolic-ref HEAD refs/heads/(null) I've followed up to this message with a patch including a test to catch this in future. Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH] git-checkout: disallow --detach on unborn branch 2012-06-26 15:04 ` git-commit bug (was Re: Editing the root commit) Chris Webb @ 2012-06-26 15:06 ` Chris Webb 2012-06-26 18:08 ` git-commit bug Junio C Hamano 1 sibling, 0 replies; 29+ messages in thread From: Chris Webb @ 2012-06-26 15:06 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, Jeff King, Chris Webb abe199808c (git checkout -b: allow switching out of an unborn branch) introduced a bug demonstrated by git checkout --orphan foo git checkout --detach git symbolic-ref HEAD which gives 'refs/heads/(null)'. This happens because we strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch) when opts->new_branch can be NULL for --detach. Catch and forbid this case, adding a test to t2017 to catch it in future. Signed-off-by: Chris Webb <chris@arachsys.com> --- builtin/checkout.c | 2 ++ t/t2017-checkout-orphan.sh | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/builtin/checkout.c b/builtin/checkout.c index e8c1b1f..3980d5d 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -915,6 +915,8 @@ static int switch_unborn_to_new_branch(struct checkout_opts *opts) int status; struct strbuf branch_ref = STRBUF_INIT; + if (!opts->new_branch) + die(_("You are on a branch yet to be born")); strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch); status = create_symref("HEAD", branch_ref.buf, "checkout -b"); strbuf_release(&branch_ref); diff --git a/t/t2017-checkout-orphan.sh b/t/t2017-checkout-orphan.sh index 0e3b858..655f278 100755 --- a/t/t2017-checkout-orphan.sh +++ b/t/t2017-checkout-orphan.sh @@ -116,4 +116,10 @@ test_expect_success '--orphan refuses to switch if a merge is needed' ' git reset --hard ' +test_expect_success 'cannot --detach on an unborn branch' ' + git checkout master && + git checkout --orphan new && + test_must_fail git checkout --detach +' + test_done -- 1.7.10 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: git-commit bug 2012-06-26 15:04 ` git-commit bug (was Re: Editing the root commit) Chris Webb 2012-06-26 15:06 ` [PATCH] git-checkout: disallow --detach on unborn branch Chris Webb @ 2012-06-26 18:08 ` Junio C Hamano 1 sibling, 0 replies; 29+ messages in thread From: Junio C Hamano @ 2012-06-26 18:08 UTC (permalink / raw) To: Chris Webb; +Cc: Jeff King, git Chris Webb <chris@arachsys.com> writes: > Chris Webb <chris@arachsys.com> writes: > >> PS Whilst experimenting, I also noticed a (presumably unintentional) >> behaviour: >> >> $ git init . >> Initialized empty Git repository in /tmp/foo/.git/ >> $ git checkout --detach >> $ touch bar >> $ git add bar >> $ git commit -m test >> [(null) (root-commit) 17b5bf9] test >> 0 files changed >> create mode 100644 bar >> $ ls .git/refs/heads/ >> (null) >> $ >> >> Here we've created a branch with the strange name '(null)' instead of >> actually detaching, or refusing to detach because we're on an unborn >> branch. > > This was introduced by abe199808c, which is intended to allow > > git init . && git checkout --orphan newbranch > > but presumably wasn't also meant to enable > > git checkout --orphan foo > git checkout --detach Correct. On days like this, I really regret accepting that --orphan crap in the first place. Thanks for fixing things up. > This leads to a printf("%s", NULL) and thus > > $ git symbolic-ref HEAD > refs/heads/(null) > > I've followed up to this message with a patch including a test to catch this > in future. > > Best wishes, > > Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 19:48 ` Jeff King 2012-06-22 20:50 ` Chris Webb @ 2012-06-26 13:33 ` Chris Webb 2012-06-26 13:36 ` [PATCH 1/2] rebase -i: support --root without --onto Chris Webb 1 sibling, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-26 13:33 UTC (permalink / raw) To: Jeff King; +Cc: Junio C Hamano, git Jeff King <peff@peff.net> writes: > I think the only thing you can do is make a fake sentinel commit (with > an empty tree) to put in HEAD, and then remove the sentinel immediately > after the first commit is put in place (making sure not to include it in > the first commit's parent list). Yuck. I thought this would turn out far more horrible than it actually did in practice. The follow-up patch adds this empty sentinel and then automatically squashes it into the root commit(s) as they're picked. The resulting rebase -i --root can handle re-ordering of commits (picking a new root), editing of the root commit, dropping the root commit, and so on. In the second patch, I've written some simple tests to demonstrate this and to cover cases that seem particularly likely to break, as well as removing a test_must_fail for --root without --onto, because it no longer does! Cheers, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 13:33 ` Editing the root commit Chris Webb @ 2012-06-26 13:36 ` Chris Webb 2012-06-26 13:36 ` [PATCH 2/2] Add tests for rebase -i " Chris Webb 2012-06-26 19:20 ` [PATCH 1/2] rebase -i: support " Junio C Hamano 0 siblings, 2 replies; 29+ messages in thread From: Chris Webb @ 2012-06-26 13:36 UTC (permalink / raw) To: git; +Cc: Jeff King, Junio C Hamano, Chris Webb Allow --root to be specified to rebase -i without --onto, making it possible to edit and re-order all commits right back to the root(s). If there is a conflict to be resolved when applying the first change, the user will expect a sane index and working tree to get sensible behaviour from git-diff and friends, so create a sentinel commit with an empty tree to rebase onto. Automatically squash the sentinel with any commits rebased directly onto it, so they end up as root commits in their own right and retain their authorship and commit message. Signed-off-by: Chris Webb <chris@arachsys.com> --- Documentation/git-rebase.txt | 9 +++++---- git-rebase--interactive.sh | 24 ++++++++++++++++++------ git-rebase.sh | 14 ++++++++++++-- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt index 147fa1a..85b5e44 100644 --- a/Documentation/git-rebase.txt +++ b/Documentation/git-rebase.txt @@ -10,7 +10,7 @@ SYNOPSIS [verse] 'git rebase' [-i | --interactive] [options] [--onto <newbase>] [<upstream>] [<branch>] -'git rebase' [-i | --interactive] [options] --onto <newbase> +'git rebase' [-i | --interactive] [options] [--onto <newbase>] --root [<branch>] 'git rebase' --continue | --skip | --abort @@ -348,10 +348,11 @@ idea unless you know what you are doing (see BUGS below). --root:: Rebase all commits reachable from <branch>, instead of limiting them with an <upstream>. This allows you to rebase - the root commit(s) on a branch. Must be used with --onto, and + the root commit(s) on a branch. When used with --onto, it will skip changes already contained in <newbase> (instead of - <upstream>). When used together with --preserve-merges, 'all' - root commits will be rewritten to have <newbase> as parent + <upstream>) whereas without --onto it will operate on every change. + When used together with both --onto and --preserve-merges, + 'all' root commits will be rewritten to have <newbase> as parent instead. --autosquash:: diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh index 0c19b7c..ed5a6ba 100644 --- a/git-rebase--interactive.sh +++ b/git-rebase--interactive.sh @@ -417,6 +417,21 @@ record_in_rewritten() { esac } +do_pick () { + if test "$(git rev-parse HEAD)" = "$squash_onto" + then + git commit --allow-empty --allow-empty-message --amend \ + --no-post-rewrite -n -q -C $1 && + pick_one -n $1 && + git commit --allow-empty --allow-empty-message \ + --amend --no-post-rewrite -n -q -C $1 || + die_with_patch $1 "Could not apply $1... $2" + else + pick_one $1 || + die_with_patch $1 "Could not apply $1... $2" + fi +} + do_next () { rm -f "$msg" "$author_script" "$amend" || exit read -r command sha1 rest < "$todo" @@ -428,16 +443,14 @@ do_next () { comment_for_reflog pick mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" record_in_rewritten $sha1 ;; reword|r) comment_for_reflog reword mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" git commit --amend --no-post-rewrite || { warn "Could not amend commit after successfully picking $sha1... $rest" warn "This is most likely due to an empty commit message, or the pre-commit hook" @@ -451,8 +464,7 @@ do_next () { comment_for_reflog edit mark_action_done - pick_one $sha1 || - die_with_patch $sha1 "Could not apply $sha1... $rest" + do_pick $sha1 "$rest" warn "Stopped at $sha1... $rest" exit_with_patch $sha1 0 ;; diff --git a/git-rebase.sh b/git-rebase.sh index e616737..bde2be8 100755 --- a/git-rebase.sh +++ b/git-rebase.sh @@ -31,7 +31,7 @@ SUBDIRECTORY_OK=Yes OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>] -git rebase [-i] [options] --onto <newbase> --root [<branch>] +git rebase [-i] [options] [--onto <newbase>] --root [<branch>] git-rebase [-i] --continue | --abort | --skip -- Available options are @@ -364,6 +364,11 @@ and run me again. I am stopping in case you still have something valuable there.' fi +if test -n "$rebase_root" && test -z "$onto" +then + test -z "$interactive_rebase" && interactive_rebase=implied +fi + if test -n "$interactive_rebase" then type=interactive @@ -397,7 +402,12 @@ then die "invalid upstream $upstream_name" upstream_arg="$upstream_name" else - test -z "$onto" && die "You must specify --onto when using --root" + if test -z "$onto" + then + empty_tree=`git hash-object -t tree /dev/null` + onto=`git commit-tree $empty_tree </dev/null` + squash_onto="$onto" + fi unset upstream_name unset upstream upstream_arg=--root -- 1.7.10 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* [PATCH 2/2] Add tests for rebase -i --root without --onto 2012-06-26 13:36 ` [PATCH 1/2] rebase -i: support --root without --onto Chris Webb @ 2012-06-26 13:36 ` Chris Webb 2012-06-26 19:20 ` [PATCH 1/2] rebase -i: support " Junio C Hamano 1 sibling, 0 replies; 29+ messages in thread From: Chris Webb @ 2012-06-26 13:36 UTC (permalink / raw) To: git; +Cc: Jeff King, Junio C Hamano, Chris Webb Test for likely breakages in t3404, including successful reordering of non-conflicting changes with a new root, correct preservation of commit message and author in a root commit when it is squashed with the sentinel, and presence of the sentinel following a conflicting cherry-pick of a new root. Remove test_must_fail for git rebase --root without --onto from t3412 as this case will now be successfully handled by an implicit git rebase -i. Signed-off-by: Chris Webb <chris@arachsys.com> --- t/t3404-rebase-interactive.sh | 27 +++++++++++++++++++++++++++ t/t3412-rebase-root.sh | 4 ---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 025c1c6..6ffc9c2 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -755,4 +755,31 @@ test_expect_success 'rebase-i history with funny messages' ' test_cmp expect actual ' +test_expect_success 'rebase -i --root re-order and drop commits' ' + git checkout E && + FAKE_LINES="3 1 2 5" git rebase -i --root && + test E = $(git cat-file commit HEAD | sed -ne \$p) && + test B = $(git cat-file commit HEAD^ | sed -ne \$p) && + test A = $(git cat-file commit HEAD^^ | sed -ne \$p) && + test C = $(git cat-file commit HEAD^^^ | sed -ne \$p) && + test 0 = $(git cat-file commit HEAD^^^ | grep -c ^parent\ ) +' + +test_expect_success 'rebase -i --root retain root commit author and message' ' + git checkout A && + echo B >file7 && + git add file7 && + GIT_AUTHOR_NAME="Twerp Snog" git commit -m "different author" && + FAKE_LINES="2" git rebase -i --root && + git cat-file commit HEAD | grep -q "^author Twerp Snog" && + git cat-file commit HEAD | grep -q "^different author$" +' + +test_expect_success 'rebase -i --root temporary sentinel commit' ' + git checkout B && + FAKE_LINES="2" test_must_fail git rebase -i --root && + git cat-file commit HEAD | grep "^tree 4b825dc642cb" && + git rebase --abort +' + test_done diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh index 086c91c..e4f9da8 100755 --- a/t/t3412-rebase-root.sh +++ b/t/t3412-rebase-root.sh @@ -22,10 +22,6 @@ test_expect_success 'prepare repository' ' test_commit 4 B ' -test_expect_success 'rebase --root expects --onto' ' - test_must_fail git rebase --root -' - test_expect_success 'setup pre-rebase hook' ' mkdir -p .git/hooks && cat >.git/hooks/pre-rebase <<EOF && -- 1.7.10 ^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 13:36 ` [PATCH 1/2] rebase -i: support --root without --onto Chris Webb 2012-06-26 13:36 ` [PATCH 2/2] Add tests for rebase -i " Chris Webb @ 2012-06-26 19:20 ` Junio C Hamano 2012-06-26 19:38 ` Chris Webb 1 sibling, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-26 19:20 UTC (permalink / raw) To: Chris Webb; +Cc: git, Jeff King Chris Webb <chris@arachsys.com> writes: > +do_pick () { > + if test "$(git rev-parse HEAD)" = "$squash_onto" The idea to create a sentinel root upfront and special case it here is a good one. > + then I am not quite sure what is going on in this "then" clause. > + git commit --allow-empty --allow-empty-message --amend \ > + --no-post-rewrite -n -q -C $1 && At this point, nobody touched the empty sentinel root yet; you rewrite its log message and authorship using the picked commit. > + pick_one -n $1 && And then you create a new commit that records the update "$1" does relative to its parent (this hopefully only contains additions -- is it sensible to die-with-patch if it doesn't?), making sure that it does not fast-forward. Does this always make the result a root commit? If "$1" has parents, wouldn't it become a child of the commits its parents were rewritten to (if any) in pick_one_preserving_merges() that is called from pick_one? > + git commit --allow-empty --allow-empty-message \ > + --amend --no-post-rewrite -n -q -C $1 || And then you rewrite the log and authorship of that one. In short, my questions are: (1) what is the purpose of the first "commit --amend" to update the sentinel root commit? (2) Is the purpose of "pick_one -n" done here to create a root commit? Does it always do so correctly? > diff --git a/git-rebase.sh b/git-rebase.sh > index e616737..bde2be8 100755 > --- a/git-rebase.sh > +++ b/git-rebase.sh > @@ -31,7 +31,7 @@ SUBDIRECTORY_OK=Yes > OPTIONS_KEEPDASHDASH= > OPTIONS_SPEC="\ > git rebase [-i] [options] [--onto <newbase>] [<upstream>] [<branch>] > -git rebase [-i] [options] --onto <newbase> --root [<branch>] > +git rebase [-i] [options] [--onto <newbase>] --root [<branch>] > git-rebase [-i] --continue | --abort | --skip > -- > Available options are > @@ -364,6 +364,11 @@ and run me again. I am stopping in case you still have something > valuable there.' > fi > > +if test -n "$rebase_root" && test -z "$onto" > +then > + test -z "$interactive_rebase" && interactive_rebase=implied > +fi > + This makes "git rebase --root" without $onto imply "-i", which makes sense, but it was a bit unexpected (it wasn't in the proposed log message). ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 19:20 ` [PATCH 1/2] rebase -i: support " Junio C Hamano @ 2012-06-26 19:38 ` Chris Webb 2012-06-26 20:05 ` Junio C Hamano 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-26 19:38 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Jeff King Junio C Hamano <gitster@pobox.com> writes: > I am not quite sure what is going on in this "then" clause. > > Chris Webb <chris@arachsys.com> writes: > > > + git commit --allow-empty --allow-empty-message --amend \ > > + --no-post-rewrite -n -q -C $1 && > > At this point, nobody touched the empty sentinel root yet; you > rewrite its log message and authorship using the picked commit. > > > + pick_one -n $1 && > > And then you create a new commit that records the update "$1" does > relative to its parent (this hopefully only contains additions -- is > it sensible to die-with-patch if it doesn't?), making sure that it > does not fast-forward. Does this always make the result a root commit? > If "$1" has parents, wouldn't it become a child of the commits its > parents were rewritten to (if any) in pick_one_preserving_merges() > that is called from pick_one? > > > + git commit --allow-empty --allow-empty-message \ > > + --amend --no-post-rewrite -n -q -C $1 || > > And then you rewrite the log and authorship of that one. > > In short, my questions are: > > (1) what is the purpose of the first "commit --amend" to update the > sentinel root commit? This first commit --amend isn't supposed to change the empty tree in the commit: the tree and index should be unchanged at this point. I'm only running it to set the commit message and author. The idea here is that I want the author and commit message already in place if cherry-pick (and hence pick_one -n) fails so that we drop out for the user to resolve conflicts. This seems to be the way git cherry-pick or git merge behave when they need conflicts resolving, and I wanted the behaviour to be consistent to avoid surprises. Is there a way of explicitly writing my commit --amend to make this intention clearer? Would a -o without paths spell this out, or would it just make thing more confusing? > (2) Is the purpose of "pick_one -n" done here to create a root > commit? Does it always do so correctly? pick_one -n cherry-picks the changes without actually making a commit. It's already used in the squash case, so should be well-tested. Following this, the second commit --amend actually commits those changes, amending the sentinel. I don't change the message at all at this stage because it's already correct. Similar question to before: is there a clearer way to ask commit --amend to leave the author and commit message unchanged rather than supply them explicitly all over again, or shall I just comment to explain the intention? EDITOR=: perhaps? > This makes "git rebase --root" without $onto imply "-i", which makes > sense, but it was a bit unexpected (it wasn't in the proposed log > message). Yes, sorry, you're quite right. It's only mentioned in the tests patch. Would you prefer me to make this change in a separate patch, and generate an error for this case in the initial commit, or just explain it properly in the log message to go with the original combined patch? Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 19:38 ` Chris Webb @ 2012-06-26 20:05 ` Junio C Hamano 2012-06-26 20:11 ` Chris Webb 0 siblings, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-26 20:05 UTC (permalink / raw) To: Chris Webb; +Cc: git, Jeff King Chris Webb <chris@arachsys.com> writes: >> In short, my questions are: >> >> (1) what is the purpose of the first "commit --amend" to update the >> sentinel root commit? > > This first commit --amend isn't supposed to change the empty tree in the > commit: the tree and index should be unchanged at this point. I'm only > running it to set the commit message and author. > > The idea here is that I want the author and commit message already in place > if cherry-pick (and hence pick_one -n) fails so that we drop out for the > user to resolve conflicts. Very understandable. Perhaps in-code comments would have helped. >> (2) Is the purpose of "pick_one -n" done here to create a root >> commit? Does it always do so correctly? > > pick_one -n cherry-picks the changes without actually making a commit. It's > already used in the squash case, so should be well-tested. OK. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 20:05 ` Junio C Hamano @ 2012-06-26 20:11 ` Chris Webb 2012-06-26 21:24 ` Junio C Hamano 0 siblings, 1 reply; 29+ messages in thread From: Chris Webb @ 2012-06-26 20:11 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Jeff King Junio C Hamano <gitster@pobox.com> writes: > Very understandable. Perhaps in-code comments would have helped. Shall I re-spin this with a comment to explain what's going on, and to mention the implicit -i with rebase --root without -i, or would you prefer to queue the existing version with any clarifications you think appropriate? Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 20:11 ` Chris Webb @ 2012-06-26 21:24 ` Junio C Hamano 2012-06-26 21:27 ` Chris Webb 0 siblings, 1 reply; 29+ messages in thread From: Junio C Hamano @ 2012-06-26 21:24 UTC (permalink / raw) To: Chris Webb; +Cc: git, Jeff King Chris Webb <chris@arachsys.com> writes: > Junio C Hamano <gitster@pobox.com> writes: > >> Very understandable. Perhaps in-code comments would have helped. > > Shall I re-spin this with a comment to explain what's going on, and to > mention the implicit -i with rebase --root without -i, or would you prefer > to queue the existing version with any clarifications you think appropriate? A reroll would be preferred, as it would be less work for me ;-) Thanks. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [PATCH 1/2] rebase -i: support --root without --onto 2012-06-26 21:24 ` Junio C Hamano @ 2012-06-26 21:27 ` Chris Webb 0 siblings, 0 replies; 29+ messages in thread From: Chris Webb @ 2012-06-26 21:27 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Jeff King Junio C Hamano <gitster@pobox.com> writes: > Chris Webb <chris@arachsys.com> writes: > > > Junio C Hamano <gitster@pobox.com> writes: > > > >> Very understandable. Perhaps in-code comments would have helped. > > > > Shall I re-spin this with a comment to explain what's going on, and to > > mention the implicit -i with rebase --root without -i, or would you prefer > > to queue the existing version with any clarifications you think appropriate? > > A reroll would be preferred, as it would be less work for me ;-) No problem, I'll do that now. Thanks for the feedback and all your help with this patch series. Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 18:25 ` Junio C Hamano 2012-06-20 19:29 ` Jeff King @ 2012-06-20 19:35 ` Chris Webb 2012-06-25 17:22 ` Martin von Zweigbergk 2 siblings, 0 replies; 29+ messages in thread From: Chris Webb @ 2012-06-20 19:35 UTC (permalink / raw) To: Junio C Hamano; +Cc: git Junio C Hamano <gitster@pobox.com> writes: > What if we do not say --onto here? I am not asking what the current > implementation does (we get an error message saying "I want 'onto' > specified"). What _should_ this command mean to a na??ve user? > > $ git rebase [-i] --root > > I think it should mean "replay all my history down to root". The > original root commit should become the new root commit in the > rewritten history. Yes, I definitely agree with everything you say here. That's exactly what I'd expect from git rebase --root without --onto, and what I'd hope to be able to implement in a patch series. > For the root commit in the history, you check it out on the detached > HEAD. Under "--interactive" if the insn sheet tells you to allow > the user to "edit/amend/reword" it, give control back the user after > you have detached HEAD at that commit. The user experience should > be identical to the case you are replaying on an existing commit > after that point. I think it might a little more complicated than detecting when we have to do a commit --amend on the root commit though? The user might have reordered the first commit (introducing A and B, say) with the second commit (introducing C and D), or dropped the original root commit entirely. My understanding of the way --interactive works at the moment is that it checks out the starting commit (whether given explicitly by --onto or taken from <upstream>) and then 'plays out' the commits as described in the instruction sheet. I could re-use this unchanged if I could do a git checkout --orphan without having to create a new branch, but I don't think this is allowed: I can have a detached head or make an orphan checkout onto a new branch, but not both at the same time? Would you prefer that I create a temporary branch just to be able to git checkout --orphan onto it here, or that I add support for this kind of 'detached HEAD with no parent' state, or is there a natural way to rework --interactive without needing to do this which I'm missing? Best wishes, Chris. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-20 18:25 ` Junio C Hamano 2012-06-20 19:29 ` Jeff King 2012-06-20 19:35 ` Editing the root commit Chris Webb @ 2012-06-25 17:22 ` Martin von Zweigbergk 2 siblings, 0 replies; 29+ messages in thread From: Martin von Zweigbergk @ 2012-06-25 17:22 UTC (permalink / raw) To: Junio C Hamano; +Cc: Chris Webb, git On Wed, Jun 20, 2012 at 11:25 AM, Junio C Hamano <gitster@pobox.com> wrote: > > $ git rebase [-i] --root --onto nitfol > > looks at the entire history leading to where you are, and replays > everything you have done onto the tip of 'nitfol'. > > What if we do not say --onto here? Or even leaving out the --onto for that matter. If I understand correctly, "git rebase --root --onto nitfol" is (more-or-less) just syntactic sugar for "git rebase nitfol", see http://thread.gmane.org/gmane.comp.version-control.git/181024/focus=182054. I have an old branch from around the time of that thread that make this fact (that "--root --onto" is syntactic sugar) a little clearer in the code. I'll try to finally send out some of those patches as soon as I can. > What _should_ this command mean to a naïve user? > > $ git rebase [-i] --root > > I think it should mean "replay all my history down to root". The > original root commit should become the new root commit in the > rewritten history. I agree, and in this case, the --root flag would not just be syntactic sugar. Martin ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: Editing the root commit 2012-06-19 9:16 Editing the root commit Chris Webb 2012-06-19 10:09 ` Junio C Hamano @ 2012-06-19 11:50 ` jaseem abid 1 sibling, 0 replies; 29+ messages in thread From: jaseem abid @ 2012-06-19 11:50 UTC (permalink / raw) To: Chris Webb; +Cc: git On Tue, Jun 19, 2012 at 2:46 PM, Chris Webb <chris@arachsys.com> wrote: > > I've recently been polishing up some private code for release, using git > rebase --interactive to expand on some commit messages. > > In a couple of cases, I wanted to edit the root commit. (Adding a COPYING > file, for example.) I've been successfully doing this with an explicit > > ROOT=$(git log --pretty=format:%H | tail -n 1) > git checkout $ROOT > git commit --amend --message='Initial import modified' # for example > git rebase --onto HEAD $ROOT master > > However, this brought two questions to mind. > > The first is whether there's a clever symbolic way to refer to the root of > the current branch, rather than tailing git log output? gitrevisions(7) > doesn't obviously suggest one. > > The second question is whether it's possible to use git rebase > --interactive > to edit the root commit along with some subsequent ones in one fell swoop? > > My fingers half-remember doing something like > > git checkout --orphan rewritten > git rm -rf > git rebase --interactive --root --onto rewritten master > > a year or so ago, but this now fails (on git 1.7.10) with the somewhat > surprising error > > $ git rebase --root --onto rewritten master > fatal: Needed a single revision > Does not point to a valid commit: master > > Am I misremembering the recipe here, or has the behaviour changed? It > seems > to fail identically with or without --interactive. I was trying to do something very similar yesterday. I was cleaning up a lot of commits with a rebase -i when I figured out that I cant do that on the root commit. The man on interactive rebase says, Start it with the last commit you want to retain as-is: git rebase -i <after-this-commit> which means root cant be included. Finally I had to settle for some solution like what you mentioned. If possible Junio, can a feature be added to include root commit also to git rebase -i somehow so that a rewrite including root is easier and more straightforward ? -- Jaseem Abid http://jaseemabid.github.com ^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2012-06-26 21:27 UTC | newest] Thread overview: 29+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-06-19 9:16 Editing the root commit Chris Webb 2012-06-19 10:09 ` Junio C Hamano 2012-06-19 11:17 ` Chris Webb 2012-06-20 9:32 ` Chris Webb 2012-06-20 18:25 ` Junio C Hamano 2012-06-20 19:29 ` Jeff King 2012-06-20 19:39 ` Chris Webb 2012-06-20 19:48 ` Jeff King 2012-06-22 20:50 ` Chris Webb 2012-06-22 21:35 ` Junio C Hamano 2012-06-22 22:02 ` Chris Webb 2012-06-22 22:26 ` Chris Webb 2012-06-22 22:50 ` Junio C Hamano 2012-06-23 7:20 ` Chris Webb 2012-06-26 15:04 ` git-commit bug (was Re: Editing the root commit) Chris Webb 2012-06-26 15:06 ` [PATCH] git-checkout: disallow --detach on unborn branch Chris Webb 2012-06-26 18:08 ` git-commit bug Junio C Hamano 2012-06-26 13:33 ` Editing the root commit Chris Webb 2012-06-26 13:36 ` [PATCH 1/2] rebase -i: support --root without --onto Chris Webb 2012-06-26 13:36 ` [PATCH 2/2] Add tests for rebase -i " Chris Webb 2012-06-26 19:20 ` [PATCH 1/2] rebase -i: support " Junio C Hamano 2012-06-26 19:38 ` Chris Webb 2012-06-26 20:05 ` Junio C Hamano 2012-06-26 20:11 ` Chris Webb 2012-06-26 21:24 ` Junio C Hamano 2012-06-26 21:27 ` Chris Webb 2012-06-20 19:35 ` Editing the root commit Chris Webb 2012-06-25 17:22 ` Martin von Zweigbergk 2012-06-19 11:50 ` jaseem abid
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).