* Re: [PATCH] New git-seek command with documentation and test. @ 2006-02-24 0:29 linux 2006-02-24 0:54 ` Johannes Schindelin 2006-02-24 6:53 ` H. Peter Anvin 0 siblings, 2 replies; 12+ messages in thread From: linux @ 2006-02-24 0:29 UTC (permalink / raw) To: cworth; +Cc: git The annoying thing about temporary branch names like "bisect" and "seek" is that: a) They clutter up the nae space available to the repository user. Users have to know that those are reserved names. b) If a repository is cloned while they're in use, they might get into a "remotes" file, with even more confusing results. This is somewhat heretical, but how about making a truly unnamed branch by having .git/HEAD *not* be a symlink, but rather hold a commit ID directly? It's already well established that files in the .git directory directly are strictly local to this working directory, so it seems a much better home for such temporary state. Admittedly, this requires more invasive edits (particularly adding a third legitimate case to validate_symref()), but it seems to make more sense. And be ultimately simpler than workarounds for the above problems. Just loosen the rules from ".git/HEAD must be a symlink" to ".git/HEAD must be a symlink before you can check in". Yes, I know it's radical. At least I'm not questioning the power and efficacy of indulgences. :-) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 0:29 [PATCH] New git-seek command with documentation and test linux @ 2006-02-24 0:54 ` Johannes Schindelin 2006-02-24 1:23 ` linux 2006-02-24 6:53 ` H. Peter Anvin 1 sibling, 1 reply; 12+ messages in thread From: Johannes Schindelin @ 2006-02-24 0:54 UTC (permalink / raw) To: linux; +Cc: cworth, git Hi, On Fri, 23 Feb 2006, linux@horizon.com wrote: > This is somewhat heretical, but how about making a truly unnamed branch by > having .git/HEAD *not* be a symlink, but rather hold a commit ID directly? Not heretical. How do you intend to switch branches now? And how do you intend to record the starting point of git-seek to which you want to return to? All leads back to .git/HEAD pointing to a branch (or whatever you want to call it). And BTW, .git/HEAD is no symlink these days, but a symref. Hth, Dscho ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 0:54 ` Johannes Schindelin @ 2006-02-24 1:23 ` linux 0 siblings, 0 replies; 12+ messages in thread From: linux @ 2006-02-24 1:23 UTC (permalink / raw) To: Johannes.Schindelin, linux; +Cc: cworth, git > Not heretical. How do you intend to switch branches now? Point .git/HEAD at the branch like usual. .git/HEAD would not be a symref *only* when on the unnamed temporary branch (which doesn't accept commits). > And how do you intend to record the starting point of git-seek to > which you want to return to? Te same way it's done now for git-seek or git-bisect: by copying the old HEAD to a temporary location like .git/head-name. > All leads back to .git/HEAD pointing to a branch (or whatever > you want to call it). In the usual case, yes it should. Any time you want to be able to develop on a branch, you need .git/HEAD pointing to a branch. You only make it point to a commit directly is when exploring the history with no intention of developing from it. (Note that you can easily change your mind with a simple "git checkout -b <branch>".) > And BTW, .git/HEAD is no symlink these days, but a symref. Yes, I'm sorry; I was just being lazy with my terminology. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 0:29 [PATCH] New git-seek command with documentation and test linux 2006-02-24 0:54 ` Johannes Schindelin @ 2006-02-24 6:53 ` H. Peter Anvin 2006-02-24 10:11 ` Andreas Ericsson 1 sibling, 1 reply; 12+ messages in thread From: H. Peter Anvin @ 2006-02-24 6:53 UTC (permalink / raw) To: linux; +Cc: cworth, git linux@horizon.com wrote: > The annoying thing about temporary branch names like "bisect" and "seek" > is that: > a) They clutter up the nae space available to the repository user. > Users have to know that those are reserved names. > b) If a repository is cloned while they're in use, they might get > into a "remotes" file, with even more confusing results. > > This is somewhat heretical, but how about making a truly unnamed branch by > having .git/HEAD *not* be a symlink, but rather hold a commit ID directly? > It's already well established that files in the .git directory directly > are strictly local to this working directory, so it seems a much better > home for such temporary state. > It might be easier to just reserve part of the namespace, e.g. ".bisect" and ".seek" instead. -hpa ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 6:53 ` H. Peter Anvin @ 2006-02-24 10:11 ` Andreas Ericsson 0 siblings, 0 replies; 12+ messages in thread From: Andreas Ericsson @ 2006-02-24 10:11 UTC (permalink / raw) To: H. Peter Anvin; +Cc: linux, cworth, git H. Peter Anvin wrote: > linux@horizon.com wrote: > >> The annoying thing about temporary branch names like "bisect" and "seek" >> is that: >> a) They clutter up the nae space available to the repository user. >> Users have to know that those are reserved names. >> b) If a repository is cloned while they're in use, they might get >> into a "remotes" file, with even more confusing results. >> >> This is somewhat heretical, but how about making a truly unnamed >> branch by >> having .git/HEAD *not* be a symlink, but rather hold a commit ID >> directly? >> It's already well established that files in the .git directory directly >> are strictly local to this working directory, so it seems a much better >> home for such temporary state. >> > > It might be easier to just reserve part of the namespace, e.g. ".bisect" > and ".seek" instead. > Ach, no. Not specific names. ^\.-.* would be acceptable, but I sometimes use '.name' or '-name' to mark a temporary branch. Making .- or some such reserved would perhaps make sense, but not with specific names. -- Andreas Ericsson andreas.ericsson@op5.se OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231 ^ permalink raw reply [flat|nested] 12+ messages in thread
* several quick questions @ 2006-02-14 16:28 Nicolas Vilz 'niv' 2006-02-14 17:05 ` Linus Torvalds 0 siblings, 1 reply; 12+ messages in thread From: Nicolas Vilz 'niv' @ 2006-02-14 16:28 UTC (permalink / raw) To: git Hello everyone, i wonder, how i revoke a straight forward merge of two trees... I actually wanted to be look like somewhere in the git-repository, where some branches are merged back with the master tree, but i think, that wasn't "cg-merge -c <tree to merge with the actual one>"... my result was that my master tree has now the same sha1-sum as my development-tree and gitk visualisation differs from that what i saw in the git-repository. (Several Arrows headed into back into one line...) maybe that was because i didn't do anything in my master tree in the meantime. And another thing, is there no posibility to get back to some commits or tags? I realized you can rebranch tags... what, if i want to switch back to git version 1.1.6 in the git repository? Or a certain commit? do you have to make a new private branch out of the tag 1.1.6? i used svn and there i could go back some revisions. I haven't found such a feature in git, yet... but i think i am blind all the time. I like git very much and every new day I like it more. Sincerly Nicolas ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 16:28 several quick questions Nicolas Vilz 'niv' @ 2006-02-14 17:05 ` Linus Torvalds 2006-02-14 18:10 ` Carl Worth 0 siblings, 1 reply; 12+ messages in thread From: Linus Torvalds @ 2006-02-14 17:05 UTC (permalink / raw) To: Nicolas Vilz 'niv'; +Cc: git On Tue, 14 Feb 2006, Nicolas Vilz 'niv' wrote: > > i wonder, how i revoke a straight forward merge of two trees... I > actually wanted to be look like somewhere in the git-repository, where > some branches are merged back with the master tree, but i think, that > wasn't "cg-merge -c <tree to merge with the actual one>"... > > my result was that my master tree has now the same sha1-sum as my > development-tree and gitk visualisation differs from that what i saw in > the git-repository. (Several Arrows headed into back into one line...) > > maybe that was because i didn't do anything in my master tree in the > meantime. > > And another thing, is there no posibility to get back to some commits or > tags? I realized you can rebranch tags... what, if i want to switch back > to git version 1.1.6 in the git repository? Or a certain commit? Both of these can be solved with "git reset". Before going into any more detail on that, let's go over the other related "basic operations" too: - "git branch". This creates a new branch of development at an arbitrary point (that defaults to "current state"). Example: git branch development-trial v1.1.6 This will create a new branch called "development-trial", which starts at the v1.1.6 state. NOTE! It will _not_ check it out - your old active state is left totally alone, and you still stay on whatever branch you used to be on. - "git checkout". This switches to another branch. As a shorthand, you can also choose to create the branch at the same time, but normally you'd just do like this example: git checkout development-trial which will switch to the branch you just created and check that out. - "git reset". This will reset the current branch state to something else. This is what you would use if you want to undo a commit, for example: you can "reset" the current branch to before the commit happened. NOTE! When you do this, you also have to choose what you want to do about your checked-out working tree. For example, when undoing the last commit, you normally want to totally undo all the working tree changes too, but you might also want to just undo the commit, and leave the actual changes you committed alone, so that you can re-commit them with a fixed commit message, for example. Example: git reset --hard HEAD^ this will undo the last commit (more exactly: it will select the first parent of HEAD to be the new top-of-development, so if the last thing you did was a merge, it will reset to the previous state). The "--hard" means that you want to reset the working tree too. Other example: git reset --hard v1.1.6 This will just reset the current branch to a particular known state (ie 1.1.6 in this case). Without the "--hard", it will _not_ change the working tree, but just update the index (and branch pointer, of course) to the new state, and tell you which files are "dirty" in that new state. This is great for undoing just a "git commit", but leaving the tree in the state is was before you committed. It's not so great if you expected to revert everything, and are now confused because "git diff" shows lots of changes ;) Finally, let's go over the difference between "git fetch" and "git pull": - "git fetch" is what you want to do if you want to _update_ another branch. For example, if you want to track what Junio is doing in his git repository (assuming that was what you cloned for), doing git fetch origin will update the "origin" branch, but will _not_ touch the current branch itself. This is very useful for seeing what Junio has been doing, without actually affecting your own work in any way. - "git pull" is really just "git fetch" + "git merge". It will fetch the state you asked for, and then merge that into your current branch. So it's important to rmember that this actually _changes_ what you have checked out and have worked on. One very special case of "git pull" is when you only use the repository to track another branch, and you never do any changes at all, and you never switch branches around, and you always pull from the same source. In that case, "git pull" will basically boil down to just a read-only tracking mechanism (ie you could think of this particular usage as being the git equivalent of "anoncvs" access) The reason people may get confused is that they start out using "git pull" as a read-only tracking mechanism, and it's not necessarily obvious that "git pull" really fundamentally is a very powerful operations - much MUCH more complex and powerful than just "track that other branch". Which is why I try to make the distinction between "git fetch" and "git pull" clear. Linus ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 17:05 ` Linus Torvalds @ 2006-02-14 18:10 ` Carl Worth 2006-02-14 18:34 ` Linus Torvalds 0 siblings, 1 reply; 12+ messages in thread From: Carl Worth @ 2006-02-14 18:10 UTC (permalink / raw) To: Linus Torvalds; +Cc: Nicolas Vilz 'niv', git [-- Attachment #1: Type: text/plain, Size: 2123 bytes --] On Tue, 14 Feb 2006 09:05:16 -0800 (PST), Linus Torvalds wrote: > > Both of these can be solved with "git reset". ... > - "git branch". This creates a new branch of development at an arbitrary > point (that defaults to "current state"). > > - "git checkout". This switches to another branch. > > - "git reset". This will reset the current branch state to something > else. Thanks for the summary. I don't know if it's the original poster's question or not, but an operation I don't see in the above is "put the working files into the state of a given revision". I recently needed this for some historical investigation, (specifically examining all release tags to ensure that the results after a git import match the results of what we get from the former CVS repository). In this kind of historical exploration, the notion of a "current branch" isn't interesting, since I won't be doing any commits. So the handling of the current branch in the above commands ends up getting in my way [*]. Is there a more fundamental operation to "put the working files into the state of the index"? If that exists, then that combined with git-read-tree would give me what I wanted I think. -Carl [*] I did succeed in performing the operation, but only in rather awkward ways. Here are a couple of versions of "put the working files into the state of <revision>", both requiring the use of an otherwise unnecessary branch, (bogus-branch): 1) Ensure bogus-branch doesn't exist, then create it at <revision>: # Can't be on bogus-branch when we delete it git checkout master # Use -D to force the removal, ignore errors for branch-does-not-exist git branch -D bogus-branch >& /dev/null || true # Create the branch where we want it git checkout -b bogus-branch <revision> 2) Ensure that bogus-branch exists somewhere (don't care where), then move it: # Create the branch (if it doesn't exist) git checkout -b bogus-branch >& /dev/null # Switch to it (which doesn't happen above if it already existed) git checkout bogus-branch # Move the branch to the revision of interest git reset --hard <revision> [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 18:10 ` Carl Worth @ 2006-02-14 18:34 ` Linus Torvalds 2006-02-14 20:10 ` Carl Worth 0 siblings, 1 reply; 12+ messages in thread From: Linus Torvalds @ 2006-02-14 18:34 UTC (permalink / raw) To: Carl Worth; +Cc: Nicolas Vilz 'niv', git On Tue, 14 Feb 2006, Carl Worth wrote: > > I don't know if it's the original poster's question or not, but an > operation I don't see in the above is "put the working files into the > state of a given revision". What a strange thing to ask for. But you can do it several ways: - just use "git reset" to move around in history, possibly on a temporary branch. - use "git checkout <rev> <filename>" to checkout a particular filename of a particular version (it's a special case of "git checkout", which is useful, but I personally think it's a bit confusing, so I wouldn't mention it unless you asked) - use the core internal git functions, in particular git-read-tree -m -u <oldtree> <newtree> will switch from "oldtree" to "newtree" and update (-u) the working tree. > 2) Ensure that bogus-branch exists somewhere (don't care where), then > move it: > > # Create the branch (if it doesn't exist) > git checkout -b bogus-branch >& /dev/null > # Switch to it (which doesn't happen above if it already existed) > git checkout bogus-branch > # Move the branch to the revision of interest > git reset --hard <revision> This is actually what I'd suggest you always do. Why? It's actually as efficient as anything else, and there's much less room for confusion. When you want to go back, you can just do a simple git checkout -f master and there's no room for confusion. You've not lost sight of any old state, and your HEAD never differs from your checked-out copy, so all the normal commands work the way you'd expect them to. Linus ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 18:34 ` Linus Torvalds @ 2006-02-14 20:10 ` Carl Worth 2006-02-14 20:40 ` Linus Torvalds 0 siblings, 1 reply; 12+ messages in thread From: Carl Worth @ 2006-02-14 20:10 UTC (permalink / raw) To: Linus Torvalds; +Cc: Nicolas Vilz 'niv', git [-- Attachment #1: Type: text/plain, Size: 2201 bytes --] On Tue, 14 Feb 2006 10:34:35 -0800 (PST), Linus Torvalds wrote: > On Tue, 14 Feb 2006, Carl Worth wrote: > > > > I don't know if it's the original poster's question or not, but an > > operation I don't see in the above is "put the working files into the > > state of a given revision". > > What a strange thing to ask for. It's pretty common in other tools. For example, many tools have a way to examine the files from a previous state in a "no current branch" state. Any attempt to commit from that state would prompt the user to create a new branch name at that point. In fact, this is the natural operation for the basis of something like git-bisect. > It's actually as efficient as anything else, and there's much less room > for confusion. When you want to go back, you can just do a simple > > git checkout -f master OK, the efficiency arguments made elsewhere in the thread make it clear that these are the operations that need to happen. But I'd still like to be able to do this without having to invent a fake branch name, without the ability to accidentally commit on the fake branch, and without the possibility of accidentally leaving those commits dangling the next time I seek somewhere else. So I looked, and git-bisect does use this approach with a fake branch of "bisect" and by saving the original head ref in $GIT_DIR/head-name for the sake of the final "git bisect reset". Also, git-bisect does take advantage of the $GIT_DIR/head-name state to prevent nested calls to "git bisect start", ("won't bisect on seeked tree"). That gives a very natural name, "seek", for the operation I'd like. How about "git seek" for doing the operations above, and using some reserved branch name, (say "seek"). Then, git-bisect could easily be built on that, and git-commit could respect the "seek" name and refuse to commit to it, (could tell the user how to create the branch necessary to commit from the current point). There could also be a "git seek reset" to return to the HEAD saved by the first in a chain of "git seek" operations. That looks like I minor generalization of existing behavior in git-bisect, but it would provide an operation that I would find useful. -Carl [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 20:10 ` Carl Worth @ 2006-02-14 20:40 ` Linus Torvalds 2006-02-14 21:53 ` Carl Worth 0 siblings, 1 reply; 12+ messages in thread From: Linus Torvalds @ 2006-02-14 20:40 UTC (permalink / raw) To: Carl Worth; +Cc: Nicolas Vilz 'niv', git On Tue, 14 Feb 2006, Carl Worth wrote: > > > > What a strange thing to ask for. > > It's pretty common in other tools. Well, it's pretty common in git too. But in git, the notion of "branch" really has been made so cheap that it's basically a no-op. The "overhead" of creating a branch is literally the cost of writing one (small) file. > In fact, this is the natural operation for the basis of something like > git-bisect. Right. And "git bisect" very much does exactly that. It creates a temporary branch for bisection (the branch is called "bisect", one of the less confusing naming decisions in git ;) That's really my point. It all boils down to the same three operations: "git branch", "git checkout" and "git reset". In fact, if you look into git-bisect, you'll notice that it doesn't even use "git reset" internally. It _literally_ creates a new branch (which it does by hand for some strange reason, but never mind) called "new-bisect", and then does "git checkout new-bisect" followed by renaming the branch back to "bisect" (which it again does by hand). So "git bisect" may actually get its hands dirty by knowing a bit too much about the internal workings of git branches, but conceptually, it really does just git checkout -b new-bisect <newrev> to switch its state around. > But I'd still like to be able to do this without having to invent a > fake branch name, without the ability to accidentally commit on the > fake branch, and without the possibility of accidentally leaving those > commits dangling the next time I seek somewhere else. Pasky did this before the "multi-branch" thing was common, and calls it "cg-seek". I think that does exactly what you ask for, I just don't really see the point. The downside of cg-seek is that you're really really limited to what you can do with it. For example, it may be "overhead" to have a dummy branch for bisection, but it means (for example) that you can actually do real work on the point that "git bisect" points you to. For example, if you hit a compile error, you can _literally_ fix that compile error AND COMMIT that state, and when you then mark that commit "good" or "bad" when you continue to bisect, bisection will actually do the right thing. Something that would be impossible in a "seek" environment, where you don't have a branch that you can do development on. I realize that when you come from an environment where branches are big things, this is kind of strange. But in git, a branch is literally a single file that is 41 bytes in size. That's it. No more, no less. Linus ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 20:40 ` Linus Torvalds @ 2006-02-14 21:53 ` Carl Worth 2006-02-14 22:39 ` Junio C Hamano 0 siblings, 1 reply; 12+ messages in thread From: Carl Worth @ 2006-02-14 21:53 UTC (permalink / raw) To: Linus Torvalds; +Cc: Nicolas Vilz 'niv', git [-- Attachment #1: Type: text/plain, Size: 1802 bytes --] On Tue, 14 Feb 2006 12:40:24 -0800 (PST), Linus Torvalds wrote: > > That's really my point. It all boils down to the same three operations: > "git branch", "git checkout" and "git reset". Yes. I understand that much. > I think that does exactly what you ask for, I just don't really see the > point. The downside of cg-seek is that you're really really limited to > what you can do with it. Well, I think it would be useful to generalize and export what git-bisect currently does even if there are no limitations added to it. If nothing else, it's a tiny bit of sugar to allow exploring the tree without having to invent a branch name first. So I'd be happy with "git seek" even if git-commit didn't refuse to commit on the seek branch, (but I still think that limitation makes sense---see below). > For example, if you hit a compile error, you can _literally_ fix that > compile error AND COMMIT that state, and when you then mark that commit > "good" or "bad" when you continue to bisect, bisection will actually do > the right thing. Something that would be impossible in a "seek" > environment, where you don't have a branch that you can do > development on. The only difference in the "seek" case would be that you would be required to create a branch before committing, right? And this would have the benefit of not leaving the commit object dangling after continuing the bisect, wouldn't it? You've pointed out that branches are free in terms of what git has to do. I'm saying that they're not free for the user who bears the cost of inventing a name. And in the case of any commit-while-seeking, it's at the time of the commit itself that the user has enough information to invent a useful name, not prior to seeking, (when the user is still trying to figure things out). -Carl [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: several quick questions 2006-02-14 21:53 ` Carl Worth @ 2006-02-14 22:39 ` Junio C Hamano 2006-02-23 20:31 ` [PATCH] New git-seek command with documentation and test Carl Worth 0 siblings, 1 reply; 12+ messages in thread From: Junio C Hamano @ 2006-02-14 22:39 UTC (permalink / raw) To: Carl Worth; +Cc: git, Linus Torvalds Carl Worth <cworth@cworth.org> writes: > You've pointed out that branches are free in terms of what git has to > do. I'm saying that they're not free for the user who bears the cost > of inventing a name. And in the case of any commit-while-seeking, it's > at the time of the commit itself that the user has enough information > to invent a useful name, not prior to seeking, (when the user is still > trying to figure things out). I think this is a very valid point and I am happy to accept a workable proposal (does not have to be a working patch, but a general semantics that covers most of if not all the corner cases). ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH] New git-seek command with documentation and test. 2006-02-14 22:39 ` Junio C Hamano @ 2006-02-23 20:31 ` Carl Worth 2006-02-24 0:18 ` J. Bruce Fields 2006-02-24 10:00 ` Andreas Ericsson 0 siblings, 2 replies; 12+ messages in thread From: Carl Worth @ 2006-02-23 20:31 UTC (permalink / raw) To: Junio C Hamano; +Cc: git, Linus Torvalds [-- Attachment #1: Type: text/plain, Size: 10708 bytes --] Add git-seek which allows for temporary excursions through the revision history. With "git seek <revision>" one gets a working tree corresponding to <revision>. When done with the excursion "git seek" returns back to the original branch from where the first seek began. Signed-off-by: Carl Worth <cworth@cworth.org> --- git-seek could be used as a new basis for git-bisect. This patch does not do that, but even so, git-bisect and git-seek should play nicely with each other, (in the sense that either will refuse to do anything if .git/head-name already exists). On Tue, 14 Feb 2006 14:39:34 -0800, Junio C Hamano wrote: > Carl Worth <cworth@cworth.org> writes: > > [arguments in favor of a new git-seek] > > I think this is a very valid point and I am happy to accept a > workable proposal (does not have to be a working patch, but a > general semantics that covers most of if not all the corner > cases). I had planned to just let this drop as my original need was some historical exploration that I've already finished. But now I've found a common use case in my everyday workflow that could benefit from git-seek. Here it is: I receive a bug-fix patch that updates a test case to demonstrate the bug. I can apply both the fix and the test case and see it succeed. But what I really want to do is first commit the test case, see it fail, and only then commit the fix and see the test now succeed. I'd also like the history to reflect that order. So what I do is: $ git-am $ git update-index test.c ; git commit -m "Update test" $ git update-index buggy.c ; git commit -m "Fix bug" At that point, without git-seek I can get by with: $ git checkout -b tmp HEAD^ $ make check # to see failure $ git checkout <branch_I_was_on_to_begin_with> $ git branch -d tmp # easy to forget, but breaks the next time otherwise $ make check # to see success But what I'd really like to do, (and can with the attached patch), is: $ git seek HEAD^ $ make check # to see failure $ git seek $ make check # to see success This avoids me having to: 1) invent a throwaway name, 2) remember the branch I started on, 3) remember to actually throwaway the temporary branch. I've documented git-seek quite carefully and added a test that tries to cover every documented failure mode. -Carl .gitignore | 1 Documentation/git-seek.txt | 44 +++++++++++++++++++++ Makefile | 4 +- git-seek.sh | 94 ++++++++++++++++++++++++++++++++++++++++++++ t/t3800-seek.sh | 82 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 Documentation/git-seek.txt create mode 100644 git-seek.sh create mode 100755 t/t3800-seek.sh 2656ffb6e3fcbd9443c22b4675b13f23c031600e diff --git a/.gitignore b/.gitignore index 94f66d5..55484b0 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ git-rev-list git-rev-parse git-revert git-rm +git-seek git-send-email git-send-pack git-sh-setup diff --git a/Documentation/git-seek.txt b/Documentation/git-seek.txt new file mode 100644 index 0000000..cb5c13d --- /dev/null +++ b/Documentation/git-seek.txt @@ -0,0 +1,44 @@ +git-bisect(1) +============= + +NAME +---- +git-seek - Provide a temporary excursion through the revision history. + + +SYNOPSIS +-------- +'git seek' [<revision>] + +DESCRIPTION +----------- +When given a <revision>, git-seek updates the files in the working +tree to the state of the given revision. It will do this by performing +a checkout of <revision> to a new branch named "seek", or by resetting +the seek branch if it already exists. + +When run with with no <revision> argument, git-seek will return to the +original branch from which the initial git-seek operation was +performed, (this original branch name is saved in $GIT_DIR/head-name). + +git-seek refuses to do anything if the working tree or index are +modified with respect to HEAD. If you want to carry modifications +around, use git-checkout rather than git-seek. + +git-seek will also fail if GIT_DIR/head-name exists when a seek is not +already in progress, or if a seek branch already exists that is not a +subset of the current branch, (that is, if it has unmerged commits). + +Author +------ +Written by Carl Worth <cworth@cworth.org>, based on git-bisect by +Linus Torvalds <torvalds@osdl.org> + +Documentation +------------- +Documentation by Carl Worth and the git-list <git@vger.kernel.org>. + +GIT +--- +Part of the gitlink:git[7] suite + diff --git a/Makefile b/Makefile index 8e6bbce..f3383d8 100644 --- a/Makefile +++ b/Makefile @@ -120,8 +120,8 @@ SCRIPT_SH = \ git-merge-one-file.sh git-parse-remote.sh \ git-prune.sh git-pull.sh git-push.sh git-rebase.sh \ git-repack.sh git-request-pull.sh git-reset.sh \ - git-resolve.sh git-revert.sh git-rm.sh git-sh-setup.sh \ - git-tag.sh git-verify-tag.sh git-whatchanged.sh \ + git-resolve.sh git-revert.sh git-rm.sh git-seek.sh \ + git-sh-setup.sh git-tag.sh git-verify-tag.sh git-whatchanged.sh \ git-applymbox.sh git-applypatch.sh git-am.sh \ git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \ git-merge-resolve.sh git-merge-ours.sh git-grep.sh \ diff --git a/git-seek.sh b/git-seek.sh new file mode 100644 index 0000000..26f0b76 --- /dev/null +++ b/git-seek.sh @@ -0,0 +1,94 @@ +#!/bin/sh + +USAGE='[<revision>]' +LONG_USAGE='git-seek provides a temporary excursion through the revision history. + +When given a <revision>, git-seek updates the files in the working +tree to the state of the given revision. It will do this by performing +a checkout of <revision> to a new branch named "seek", or by resetting +the seek branch if it already exists. + +When run with with no <revision> argument, git-seek will return to the +original branch from which the initial git-seek operation was +performed, (this original branch name is saved in $GIT_DIR/head-name). + +git-seek refuses to do anything if the working tree or index are +modified with respect to HEAD. If you want to carry modifications +around, use git-checkout rather than git-seek. + +git-seek will also fail if GIT_DIR/head-name exists when a seek is not +already in progress, or if a seek branch already exists that is not a +subset of the current branch, (that is, if it has unmerged commits).' + +. git-sh-setup + +# Does $GIT_DIR/head-name contain the given revision +# We use git-rev-parse to correctly resolve any aliases through references. +head_name_contains() { + old_head=$(git-rev-parse $(cat "$GIT_DIR/head-name")) + new_head=$(git-rev-parse "$1") + [ "$old_head" = "$new_head" ] +} + +seek_to() { + target="$1" + head=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD) || + die "Bad HEAD - I need a symbolic ref" + case "$head" in + refs/heads/seek) + # An explicit seek to head-name is treated as a reset + if head_name_contains "$target"; then + seek_reset + else + git reset --hard $target + fi + ;; + refs/heads/*) + [ -s "$GIT_DIR/head-name" ] && die "Will not seek: $GIT_DIR/head-name is already in use" + echo "$head" | sed 's#^refs/heads/##' >"$GIT_DIR/head-name" + if git-rev-parse --verify seek >&/dev/null ; then + git-branch -d seek || exit + fi + git checkout -b seek $target + ;; + *) + die "Bad HEAD - strange symbolic ref" + ;; + esac +} + +seek_reset() { + if [ -s "$GIT_DIR/head-name" ]; then + source=$(cat "$GIT_DIR/head-name") || exit + else + echo >&2 "No seek is in progress: returning to master." + source + fi + git checkout "$source" && + (git branch -d seek || err=$? ; git checkout seek ; exit $err) && + rm -f "$GIT_DIR/head-name" +} + +head=$(git-rev-parse --verify HEAD) || die "You do not have a valid HEAD" + +files_dirty=$(git-diff-index --name-only $head) || exit +index_dirty=$(git-diff-index --cached --name-only $head) || exit +if [ "$files_dirty" -o "$index_dirty" ]; then + die "Will not seek from a dirty state: + ${index_dirty:+(dirty in index: $index_dirty)} ${files_dirty:+(dirty in working tree: $files_dirty)} +You may want to commit these changes first or perhaps use git-checkout +-m instead of git-seek." +fi + +case "$#" in +0) + seek_reset + ;; +1) + seek_to "$1" + ;; +*) + usage + ;; +esac + diff --git a/t/t3800-seek.sh b/t/t3800-seek.sh new file mode 100755 index 0000000..e5d8f90 --- /dev/null +++ b/t/t3800-seek.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# +# Copyright (c) 2006 Carl D. Worth +# + +test_description='Test of git-seek and all documented failure modes.' + +. ./test-lib.sh + +echo "first" > file +git-add file && git-commit -m "add first revision of file" +echo "second" > file +git-commit -a -m "commit second revision" +git tag second +echo "third" > file +git-commit -a -m "commit third revision" + +verify_revision() { + contents=$(cat file) && [ "$contents" = "$1" ] +} + +test_expect_success \ + 'Test of initial "git-seek <revision>"' \ + 'git-seek HEAD~2 && verify_revision first' + +test_expect_success \ + 'Test of "git-seek <revision>" during seek' \ + 'git-seek second && verify_revision second' + +test_expect_success \ + 'Test that "git-seek" returns to starting point and resets seek state' \ + 'git-seek && verify_revision third && + [ ! -f .git/refs/seek ] && + [ ! -f .git/head-name ]' + +test_expect_success \ + 'Test that "git-seek master" also resets seek state' \ + 'git seek HEAD^1 && + git seek master && verify_revision third && + [ ! -f .git/refs/seek ] && + [ ! -f .git/head-name ]' + +test_expect_success \ + 'Test that "git-seek <revision>" which aliases to master also resets seek state' \ + 'source=$(git-rev-parse HEAD) && + git seek HEAD^1 && + git seek $source && verify_revision third && + [ ! -f .git/refs/seek ] && + [ ! -f .git/head-name ]' + +echo modified > file +test_expect_failure \ + 'Test that git-seek fails with local file modification' \ + 'git-seek HEAD^' +git-reset --hard master + +echo modified > file +git-update-index file +test_expect_failure \ + 'Test that git-seek fails with a modified index' \ + 'git-seek HEAD^' +git-reset --hard master + +echo master > .git/head-name +test_expect_failure \ + 'Test that git-seek fails when .git/head-name exists and not seeking' \ + 'git-seek HEAD^' +rm .git/head-name + +git-seek HEAD^ +echo new > new; git-add new; git-commit -m "Commit new file to seek branch" +test_expect_failure \ + 'Test that git-seek fails when there are unmerged commits on seek branch' \ + 'git-seek' + +git checkout master +git-pull . seek >&/dev/null +test_expect_success \ + 'Test that git-seek works again after merging in the seek branch' \ + 'git-seek' + +test_done -- 1.2.3.g207a-dirty [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-23 20:31 ` [PATCH] New git-seek command with documentation and test Carl Worth @ 2006-02-24 0:18 ` J. Bruce Fields 2006-02-24 10:00 ` Andreas Ericsson 1 sibling, 0 replies; 12+ messages in thread From: J. Bruce Fields @ 2006-02-24 0:18 UTC (permalink / raw) To: Carl Worth; +Cc: Junio C Hamano, git, Linus Torvalds On Thu, Feb 23, 2006 at 12:31:25PM -0800, Carl Worth wrote: > --- /dev/null > +++ b/Documentation/git-seek.txt > @@ -0,0 +1,44 @@ > +git-bisect(1) > +============= Oops. > +When given a <revision>, git-seek updates the files in the working > +tree to the state of the given revision. It will do this by performing > +a checkout of <revision> to a new branch named "seek", or by resetting > +the seek branch if it already exists. I wonder if its a good idea to silently reset a branch named with a short common word? > +LONG_USAGE='git-seek provides a temporary excursion through the revision history. > + > +When given a <revision>, git-seek updates the files in the working > +tree to the state of the given revision. It will do this by performing > +a checkout of <revision> to a new branch named "seek", or by resetting > +the seek branch if it already exists. These long usage texts with language duplicated from the man pages seem like they'd be asking for bit-rot, when an update happens in one place but not the other. I dunno. --b. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-23 20:31 ` [PATCH] New git-seek command with documentation and test Carl Worth 2006-02-24 0:18 ` J. Bruce Fields @ 2006-02-24 10:00 ` Andreas Ericsson 2006-02-24 11:38 ` Junio C Hamano 2006-02-24 14:23 ` Carl Worth 1 sibling, 2 replies; 12+ messages in thread From: Andreas Ericsson @ 2006-02-24 10:00 UTC (permalink / raw) To: Carl Worth; +Cc: Junio C Hamano, git, Linus Torvalds Carl Worth wrote: > Add git-seek which allows for temporary excursions through the > revision history. With "git seek <revision>" one gets a working tree > corresponding to <revision>. When done with the excursion "git seek" > returns back to the original branch from where the first seek began. > I've said it before, and I'll say it again. This tool provides less flexibility and much less power than "git checkout -b branch <commit-ish>" (although it would be nice to have '-o' for 'overwrite existing branch' as an argument to git checkout) > Signed-off-by: Carl Worth <cworth@cworth.org> > > --- > > I had planned to just let this drop as my original need was some > historical exploration that I've already finished. But now I've found > a common use case in my everyday workflow that could benefit from > git-seek. Here it is: > > I receive a bug-fix patch that updates a test case to demonstrate the > bug. I can apply both the fix and the test case and see it succeed. > But what I really want to do is first commit the test case, see it > fail, and only then commit the fix and see the test now succeed. I'd > also like the history to reflect that order. So what I do is: > > $ git-am > $ git update-index test.c ; git commit -m "Update test" > $ git update-index buggy.c ; git commit -m "Fix bug" > > At that point, without git-seek I can get by with: > > $ git checkout -b tmp HEAD^ > $ make check # to see failure > $ git checkout <branch_I_was_on_to_begin_with> > $ git branch -d tmp # easy to forget, but breaks the next time otherwise > $ make check # to see success > > But what I'd really like to do, (and can with the attached patch), is: > > $ git seek HEAD^ > $ make check # to see failure > $ git seek > $ make check # to see success > > This avoids me having to: > 1) invent a throwaway name, All programmers have at least five throwaway names that are only ever used as such (mine are, in order of precedence, foo, bar, tmp, fnurg, sdf and asd). > 2) remember the branch I started on, With topic branches, you need to pick more careful topic names. Without topic branches you're always on "master". Surely you know what the patches touch, so you know what branch they should be in. > 3) remember to actually throwaway the temporary branch. > This isn't always a bad thing, since you after applying some patch or other decide you want to go back to this point in history, or want to keep the point so you can show the author some problem or other with the patch. With git-seek you'll then have to remember the hard-to-learn SHA1, or how far below HEAD or some other easily remembered point in history it is. In that case, you need to remember to add the branch/tag/whatever to where you seeked rather than just go on with the work. Removing a branch later is simple. Finding the right spot to create it later can be trouble-some. If I had a vote, I'd say no to this patch, and to this tool entirely. -- Andreas Ericsson andreas.ericsson@op5.se OP5 AB www.op5.se Tel: +46 8-230225 Fax: +46 8-230231 ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 10:00 ` Andreas Ericsson @ 2006-02-24 11:38 ` Junio C Hamano 2006-02-24 14:23 ` Carl Worth 1 sibling, 0 replies; 12+ messages in thread From: Junio C Hamano @ 2006-02-24 11:38 UTC (permalink / raw) To: Andreas Ericsson; +Cc: Carl Worth, git, Linus Torvalds Andreas Ericsson <ae@op5.se> writes: > I've said it before, and I'll say it again. This tool provides less > flexibility and much less power than "git checkout -b branch > <commit-ish>" (although it would be nice to have '-o' for 'overwrite > existing branch' as an argument to git checkout) True, but assembly provides more flexibility than higher level languages and you need to strike a balance between power and usability. The real question is if the structure the tool enforces to your workflow is simply being a straight-jacket or helping an average user to avoid common mistakes. One occasion I've felt the need for "seek" like feature was when starting to bisect. You usually notice breakage, so you can start with "git bisect bad HEAD", but then what next? You usually are not absolutely sure which one _was_ working the last time. If I had a seek, then I could go back to some randomly chosen version to try it out, going back until I find a good one. Maybe "git bisect try $committish" would be a good addition. We could live without it (we can just say "git reset --hard $committish"), but it can be a bit more than just that. If given committish is known to be good or bad, we could remind the user what she said the last time, and offer a chance to take it back. That is, (1) if the given $committish is an ancestor of existing good one, list those good ones and ask "do you mean you are not sure if they are good anymore, and retry the bisection?" If yes, delete those good-* refs; (2) if the given $committish is a descendant of a bad one, show it and ask "do you mean you are not sure if they are good anymore, and retry the bisection?" If yes, remove the existing bad ref. In any case, "reset --hard" to it after user responds. Other than that, I haven't felt a need for seek-like feature; instead, I make liberal use of throw-away branches. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 10:00 ` Andreas Ericsson 2006-02-24 11:38 ` Junio C Hamano @ 2006-02-24 14:23 ` Carl Worth 2006-02-24 21:48 ` Johannes Schindelin 1 sibling, 1 reply; 12+ messages in thread From: Carl Worth @ 2006-02-24 14:23 UTC (permalink / raw) To: Andreas Ericsson; +Cc: Junio C Hamano, git, Linus Torvalds [-- Attachment #1: Type: text/plain, Size: 3134 bytes --] On Fri, 24 Feb 2006 11:00:29 +0100, Andreas Ericsson wrote: > > I've said it before, and I'll say it again. This tool provides less > flexibility and much less power than "git checkout -b branch > <commit-ish>" Yes, that's by design. It's not intended to be a replacement for git checkout -b. It's intended to be easier to use than that when its purpose fits what you want to to. > > 1) invent a throwaway name, > > All programmers have at least five throwaway names that are only ever > used as such (mine are, in order of precedence, foo, bar, tmp, fnurg, > sdf and asd). Sure, and when I use "git checkout -b" I have to keep trying these linearly until I found one that is available. That's what I've been doing, and it's painful enough that I wrote this. (Though yes, something like checkout -o would help here). > > 2) remember the branch I started on, > > With topic branches, you need to pick more careful topic names. Without > topic branches you're always on "master". Surely you know what the > patches touch, so you know what branch they should be in. I almost put "remember" in quotation marks. Obviously I know what I'm working on. It's more a matter of just having to type the name, (I do use very careful topic names so they tend to be longish). Having tab-completion for git-checkout would help here. So (1) and (2) have potential workarounds, but neither exists, and even then they would still be harder to use than git-seek. > > 3) remember to actually throwaway the temporary branch. > > This isn't always a bad thing, since you after applying some patch or > other decide you want to go back to this point in history, That assumes that I've made any change though. If you're going back in the past to make changes, then "git checkout -b" is the right thing to use. It's when you're not planning to make changes, but just exploring the past that "git seek" is helpful. So (3) is just extra pain when using git-seek for what its designed to be good for, (exploring history when not planning on writing to it). But note that the git-seek I've implemented *does* provide a writable branch, so if you discover that you do want to commit something, then that's always available. Linus gave compelling arguments for this. > In that case, you need to remember to add the > branch/tag/whatever to where you seeked rather than just go on with the > work. Removing a branch later is simple. Finding the right spot to > create it later can be trouble-some. Yes. And that's why git-seek stops and warns you before it leaves dangling commits by moving the branch. (Though it might make sense to add a -f option to force it to seek regardless of the things it currently balks at.) > If I had a vote, I'd say no to this patch, and to this tool entirely. One argument in favor is that seeking already exists in git privately within git-bisect. Exposing git-seek makes it easier to code new operations along the lines of git-bisect. It's certainly consistent with git's current implementation strategy to have the more primitive pieces of complex operations exported and available. -Carl [-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 14:23 ` Carl Worth @ 2006-02-24 21:48 ` Johannes Schindelin 2006-02-24 21:57 ` J. Bruce Fields 0 siblings, 1 reply; 12+ messages in thread From: Johannes Schindelin @ 2006-02-24 21:48 UTC (permalink / raw) To: Carl Worth; +Cc: Andreas Ericsson, Junio C Hamano, git, Linus Torvalds Hi, On Fri, 24 Feb 2006, Carl Worth wrote: > On Fri, 24 Feb 2006 11:00:29 +0100, Andreas Ericsson wrote: > > > > I've said it before, and I'll say it again. This tool provides less > > flexibility and much less power than "git checkout -b branch > > <commit-ish>" > > Yes, that's by design. It's not intended to be a replacement for git > checkout -b. I do not really understand why. git-seek shares so many characteristics with git-seek, you could make git-seek just another command line option to checkout (like "--temporary" and "--go-back"). Hth, Dscho ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] New git-seek command with documentation and test. 2006-02-24 21:48 ` Johannes Schindelin @ 2006-02-24 21:57 ` J. Bruce Fields 0 siblings, 0 replies; 12+ messages in thread From: J. Bruce Fields @ 2006-02-24 21:57 UTC (permalink / raw) To: Johannes Schindelin Cc: Carl Worth, Andreas Ericsson, Junio C Hamano, git, Linus Torvalds On Fri, Feb 24, 2006 at 10:48:46PM +0100, Johannes Schindelin wrote: > git-seek shares so many characteristics with git-seek, you could make > git-seek just another command line option to checkout (like "--temporary" > and "--go-back"). Well, as a user interface, git-seek seems a bit simpler (e.g., easier to remember).--b. ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2006-02-24 21:57 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2006-02-24 0:29 [PATCH] New git-seek command with documentation and test linux 2006-02-24 0:54 ` Johannes Schindelin 2006-02-24 1:23 ` linux 2006-02-24 6:53 ` H. Peter Anvin 2006-02-24 10:11 ` Andreas Ericsson -- strict thread matches above, loose matches on Subject: below -- 2006-02-14 16:28 several quick questions Nicolas Vilz 'niv' 2006-02-14 17:05 ` Linus Torvalds 2006-02-14 18:10 ` Carl Worth 2006-02-14 18:34 ` Linus Torvalds 2006-02-14 20:10 ` Carl Worth 2006-02-14 20:40 ` Linus Torvalds 2006-02-14 21:53 ` Carl Worth 2006-02-14 22:39 ` Junio C Hamano 2006-02-23 20:31 ` [PATCH] New git-seek command with documentation and test Carl Worth 2006-02-24 0:18 ` J. Bruce Fields 2006-02-24 10:00 ` Andreas Ericsson 2006-02-24 11:38 ` Junio C Hamano 2006-02-24 14:23 ` Carl Worth 2006-02-24 21:48 ` Johannes Schindelin 2006-02-24 21:57 ` J. Bruce Fields
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).