git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Detached HEAD (experimental)
@ 2007-01-02  7:45 Junio C Hamano
  2007-01-02 19:59 ` Edgar Toernig
                   ` (2 more replies)
  0 siblings, 3 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-02  7:45 UTC (permalink / raw)
  To: git

This allows "git checkout -d v1.4.3" to detach the HEAD from any
branch but point directly at the named commit.  After this, "git
branch" starts reporting that you are not on any branch.  You
can merge into "current branch" although there is not even such
a thing.

You can go back the normal state by switching to an existing
branch, say, "git checkout master" for example.  Another way to
get out of this is "git checkout -b newbranch".

This is still experimental.  While I think it makes sense to
allow commits on top of detached HEAD, it is rather dangerous
unless you are careful and know what you are doing.  Next "git
checkout master" will obviously lose what you have done, so we
might want to require "git checkout -f" out of a detached HEAD
if we find that the HEAD commit is not an ancestor of any other
branches.

On the other hand, the reason the user did not start the ad-hoc
work on a new branch with "git checkout -b" was probably because
the work was of a throw-away nature, so the convenience of not
having that safety valve might be even better.  We'll see.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-branch.c |   36 ++++++++++++++++++++++++++----------
 cache.h          |    2 +-
 git-checkout.sh  |   22 +++++++++++++++++++---
 path.c           |   26 ++++++++++++++++++--------
 setup.c          |    5 +++--
 5 files changed, 67 insertions(+), 24 deletions(-)

diff --git a/builtin-branch.c b/builtin-branch.c
index 745ee04..71f88f2 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -299,7 +299,8 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
 	free_ref_list(&ref_list);
 }
 
-static void create_branch(const char *name, const char *start,
+static void create_branch(const char *name, const char *start_name,
+			  unsigned char *start_sha1,
 			  int force, int reflog)
 {
 	struct ref_lock *lock;
@@ -318,9 +319,14 @@ static void create_branch(const char *name, const char *start,
 			die("Cannot force update the current branch.");
 	}
 
-	if (get_sha1(start, sha1) ||
-	    (commit = lookup_commit_reference(sha1)) == NULL)
-		die("Not a valid branch point: '%s'.", start);
+	if (start_sha1)
+		/* detached HEAD */
+		hashcpy(sha1, start_sha1);
+	else if (get_sha1(start_name, sha1))
+		die("Not a valid object name: '%s'.", start_name);
+
+	if ((commit = lookup_commit_reference(sha1)) == NULL)
+		die("Not a valid branch point: '%s'.", start_name);
 	hashcpy(sha1, commit->object.sha1);
 
 	lock = lock_any_ref_for_update(ref, NULL);
@@ -329,7 +335,8 @@ static void create_branch(const char *name, const char *start,
 
 	if (reflog) {
 		log_all_ref_updates = 1;
-		snprintf(msg, sizeof msg, "branch: Created from %s", start);
+		snprintf(msg, sizeof msg, "branch: Created from %s",
+			 start_name);
 	}
 
 	if (write_ref_sha1(lock, sha1, msg) < 0)
@@ -341,6 +348,9 @@ static void rename_branch(const char *oldname, const char *newname, int force)
 	char oldref[PATH_MAX], newref[PATH_MAX], logmsg[PATH_MAX*2 + 100];
 	unsigned char sha1[20];
 
+	if (!oldname)
+		die("cannot rename the curren branch while not on any.");
+
 	if (snprintf(oldref, sizeof(oldref), "refs/heads/%s", oldname) > sizeof(oldref))
 		die("Old branchname too long");
 
@@ -447,9 +457,15 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	head = xstrdup(resolve_ref("HEAD", head_sha1, 0, NULL));
 	if (!head)
 		die("Failed to resolve HEAD as a valid ref.");
-	if (strncmp(head, "refs/heads/", 11))
-		die("HEAD not found below refs/heads!");
-	head += 11;
+	if (!strcmp(head, "HEAD")) {
+		/* detached HEAD */
+		;
+	}
+	else {
+		if (strncmp(head, "refs/heads/", 11))
+			die("HEAD not found below refs/heads!");
+		head += 11;
+	}
 
 	if (delete)
 		return delete_branches(argc - i, argv + i, force_delete, kinds);
@@ -460,9 +476,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	else if (rename && (i == argc - 2))
 		rename_branch(argv[i], argv[i + 1], force_rename);
 	else if (i == argc - 1)
-		create_branch(argv[i], head, force_create, reflog);
+		create_branch(argv[i], head, head_sha1, force_create, reflog);
 	else if (i == argc - 2)
-		create_branch(argv[i], argv[i + 1], force_create, reflog);
+		create_branch(argv[i], argv[i+1], NULL, force_create, reflog);
 	else
 		usage(builtin_branch_usage);
 
diff --git a/cache.h b/cache.h
index 29dd290..891045c 100644
--- a/cache.h
+++ b/cache.h
@@ -296,7 +296,7 @@ extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
 extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
 extern int create_symref(const char *ref, const char *refs_heads_master);
-extern int validate_symref(const char *ref);
+extern int validate_headref(const char *ref);
 
 extern int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
 extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
diff --git a/git-checkout.sh b/git-checkout.sh
index 92ec069..c50df28 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+USAGE='[-f] [-b <new_branch>] [-d] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 
@@ -12,6 +12,7 @@ force=
 branch=
 newbranch=
 newbranch_log=
+detached=
 merge=
 while [ "$#" != "0" ]; do
     arg="$1"
@@ -27,6 +28,9 @@ while [ "$#" != "0" ]; do
 		git-check-ref-format "heads/$newbranch" ||
 			die "git checkout: we do not like '$newbranch' as a branch name."
 		;;
+	-d)
+		detached=1
+		;;
 	"-l")
 		newbranch_log=1
 		;;
@@ -144,13 +148,25 @@ fi
 # are switching to, then we'd better just be checking out
 # what we already had
 
-[ -z "$branch$newbranch" ] &&
-	[ "$new" != "$old" ] &&
+if test -z "$branch$newbranch" && test "$new" != "$old"
+then
+	case "$detached" in
+	'')
 	die "git checkout: provided reference cannot be checked out directly
 
   You need -b to associate a new branch with the wanted checkout. Example:
   git checkout -b <new_branch_name> $arg
 "
+		;;
+	1)
+		# NEEDSWORK: we would want to have this command here
+		# that allows us to detach the HEAD atomically.
+		# git update-ref --detach HEAD "$new"
+		rm -f "$GIT_DIR/HEAD"
+		echo "$new" >"$GIT_DIR/HEAD"
+		;;
+	esac
+fi
 
 if [ "X$old" = X ]
 then
diff --git a/path.c b/path.c
index 066f621..94ddd7e 100644
--- a/path.c
+++ b/path.c
@@ -90,10 +90,11 @@ int git_mkstemp(char *path, size_t len, const char *template)
 }
 
 
-int validate_symref(const char *path)
+int validate_headref(const char *path)
 {
 	struct stat st;
 	char *buf, buffer[256];
+	unsigned char sha1[20];
 	int len, fd;
 
 	if (lstat(path, &st) < 0)
@@ -119,14 +120,23 @@ int validate_symref(const char *path)
 	/*
 	 * Is it a symbolic ref?
 	 */
-	if (len < 4 || memcmp("ref:", buffer, 4))
+	if (len < 4)
 		return -1;
-	buf = buffer + 4;
-	len -= 4;
-	while (len && isspace(*buf))
-		buf++, len--;
-	if (len >= 5 && !memcmp("refs/", buf, 5))
+	if (!memcmp("ref:", buffer, 4)) {
+		buf = buffer + 4;
+		len -= 4;
+		while (len && isspace(*buf))
+			buf++, len--;
+		if (len >= 5 && !memcmp("refs/", buf, 5))
+			return 0;
+	}
+
+	/*
+	 * Is this a detached HEAD?
+	 */
+	if (!get_sha1_hex(buffer, sha1))
 		return 0;
+
 	return -1;
 }
 
@@ -241,7 +251,7 @@ char *enter_repo(char *path, int strict)
 		return NULL;
 
 	if (access("objects", X_OK) == 0 && access("refs", X_OK) == 0 &&
-	    validate_symref("HEAD") == 0) {
+	    validate_headref("HEAD") == 0) {
 		putenv("GIT_DIR=.");
 		check_repository_format();
 		return path;
diff --git a/setup.c b/setup.c
index 2ae57f7..cc97f9f 100644
--- a/setup.c
+++ b/setup.c
@@ -138,7 +138,8 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *    GIT_OBJECT_DIRECTORY environment variable
  *  - a refs/ directory
  *  - either a HEAD symlink or a HEAD file that is formatted as
- *    a proper "ref:".
+ *    a proper "ref:", or a regular file HEAD that has a properly
+ *    formatted sha1 object name.
  */
 static int is_git_directory(const char *suspect)
 {
@@ -161,7 +162,7 @@ static int is_git_directory(const char *suspect)
 		return 0;
 
 	strcpy(path + len, "/HEAD");
-	if (validate_symref(path))
+	if (validate_headref(path))
 		return 0;
 
 	return 1;
-- 
1.5.0.rc0.gab5a

^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02  7:45 [PATCH] Detached HEAD (experimental) Junio C Hamano
@ 2007-01-02 19:59 ` Edgar Toernig
  2007-01-02 21:56 ` Carl Worth
  2007-01-02 23:22 ` [PATCH] git-branch: show detached HEAD Lars Hjemli
  2 siblings, 0 replies; 68+ messages in thread
From: Edgar Toernig @ 2007-01-02 19:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git

[Note: casual git-user speaking]

Junio C Hamano wrote:
>
> This allows "git checkout -d v1.4.3" to detach the HEAD from any
> branch but point directly at the named commit.  After this, "git
> branch" starts reporting that you are not on any branch.

Nice.  But why -d?  Create more confusion? [1]

> You can go back the normal state by switching to an existing
> branch, say, "git checkout master" for example.

This is fine.  Often you want to test a couple of tags, one
after another, so "git checkout v1", "git checkout v2", ...
should work.

> Another way to get out of this is "git checkout -b newbranch".

Wth should this do?  I already noticed this line in your posting
from 29.Dec: [slightly edited]

	$ git checkout v1.5.0
	Checking out a tag -- you are not on any branch now...
	$ <modify>
	$ git commit -m 'fix' -a
	You cannot commit without a current branch.
	$ git checkout -b maint-1.5.0
	$ git commit -m 'fix' -a

I assume it will create a new branch and modify HEAD so that
the current working dir/index gets committed into that branch.
(Basically "git branch main-1.5.0 &&
            echo 'ref: refs/head/main-1.5.0' >.git/HEAD")
If that's the case, I was looking for that incantation for
a long time and couldn't find it.  I'm using the git-branch
and echo as shown above to get that.  The man-page isn't
very helpful for that special case of git-checkout.

Anyway, if I want to commit and git tells me that I can't
because I'm not on a branch, the _most unintuitive_ thing
would be calling 'git-checkout'.  I want to checkin!  No
way that I call checkout and risk losing all my changes.

What's wrong with a -b option to commit, similar to -b on
checkout?

	$ git checkout v1.5.0
	Checking out a tag -- you are not on any branch now...
	$ <modify>
	$ git commit -m 'fix' -a
	You cannot commit without a current branch.
	Give '-b <newbranch>' to commit into a new branch. 
	$ git commit -b maint-1.5.0 -m 'fix' -a

Another variant (the one I prefer): commit just updates HEAD and
git-branch can be used to give it a name (and switch to it!).
So these workflows would be possible:

Name after commit:

	$ git checkout v1.5.0
	Checking out a tag -- you are not on any branch now...
	$ git branch
	  master
	* (unnamed) c8ff51290518949225c832bae1e22b1bba6ab2cd
	$ <modify>
	$ git commit -m 'fix' -a
	Warning: data committed into unnamed branch.
	Give it a name now with "git branch <newname>"
	$ git branch
	  master
	* (unnamed) 13482f25863e5380cdd41065338e1709d469a605
	$ git branch maint-1.5.0
	$ git branch
	  master
	* main-1.5.0

or name before commit:

	$ git checkout v1.5.0
	Checking out a tag -- you are not on any branch now...
	$ <modify>
	$ git branch
	  master
	* (unnamed) c8ff51290518949225c832bae1e22b1bba6ab2cd
	$ git branch maint-1.5.0
	$ git branch
	  master
	* maint-1.5.0
	$ git commit -m 'fix' -a

Yes, 'git branch <newname>' would get a new semantic:
if no start-point is given the newname will become the
new current branch.

[Btw, I would even do that when we are on some branch. How
often did I do a checkout of a regular branch and only later
noticed, that I want to commit changes into a temp-branch:

	$ git checkout master
	$ <play around, fix compile issues, add debug stuff>
	$ git branch debug
	$ git branch
	  master
	* debug
	$ git commit -a -m "Add foo debugging code"
]

But that special case is IMHO (M = my, a casual user's) much
better than some weird checkout-incantations.

Ciao, ET.


[1] My pet-peeve:

	$ git checkout foo
	fatal: Entry 'bar' not uptodate. Cannot merge.

    What the heck?  Nobody asked for a merge!?!?!  What
    is it trying to do?  Does it actually mean:

	fatal: Working dir is dirty.  Either give '-f'
	to force the checkout and lose your changes, or
	give '-m' to merge 'foo' and your changes.

   ?  But then, why does an 'rm bar' fixes that?  Now 'bar'
   definitely isn't "uptodate".

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02  7:45 [PATCH] Detached HEAD (experimental) Junio C Hamano
  2007-01-02 19:59 ` Edgar Toernig
@ 2007-01-02 21:56 ` Carl Worth
  2007-01-02 22:18   ` Jakub Narebski
  2007-01-02 22:44   ` Junio C Hamano
  2007-01-02 23:22 ` [PATCH] git-branch: show detached HEAD Lars Hjemli
  2 siblings, 2 replies; 68+ messages in thread
From: Carl Worth @ 2007-01-02 21:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 3942 bytes --]

On Mon, 01 Jan 2007 23:45:08 -0800, Junio C Hamano wrote:
> This allows "git checkout -d v1.4.3" to detach the HEAD from any
> branch but point directly at the named commit.

Being able to perform "checkout" with a tag like this, (and no
specific branch), is something I've been wanting git to acquire for
some time. So, thanks for coding this up!

> This is still experimental.  While I think it makes sense to
> allow commits on top of detached HEAD, it is rather dangerous
> unless you are careful and know what you are doing.

This part I don't understand. I don't see why it's useful to introduce
new danger to "git checkout" in that after this change it could cause
commits to become dangling. Currently, "git checkout" is entirely
safe, as are most git commands. The few commands that create dangling
commits require fairly explicit actions from the user, (such as
"--hard" for git-reset or -D instead of -d for git-branch).

So I'd vote against this aspect. I'd rather see commits to a detached
head be disallowed with a message instructing the user to do "git
checkout -b new-branch" in order to do the commit.

And with that new safer behavior, I think it would be a good idea to
just drop the "-d" option from git-checkout.

I want this new behavior not for people who know what they are doing,
but people who are using git only incidentally, (say they just want to
acquire and build the latest version of some software). So I'd like
the sequence to work along the lines of your earlier post, (as quoted
by another reply). Specifically, I wouldn't want to see any warning
about a "missing branch" until a commit was attempted.

This would allow a sequence like this to proceed without git ever
telling the user they were doing something "wrong":

	$ git clone git://git.kernel.org/pub/scm/git/git.git
	$ cd git
	$ git checkout v1.4.3
	$ make

With the recent improvements to the git-checkout error message
(thanks!) this sequence is at least successful eventually after the
user reads and responds to the following:

	git checkout: provided reference cannot be checked out directly

	  You need -b to associate a new branch with the wanted
	  checkout. Example:
	  git checkout -b <new_branch_name> v1.4.3

But the user is required to invent a name and deal with its existence
later. For example, after some time, imagine the same user wanting
to update to the latest and build again:

	git pull origin
	git checkout v1.5.0

Now the user has to invent _another_ unique branch name, (or learn
"git branch -d" or "git reset --hard" or ...), while this branch
concept and these other commands aren't actually helping the user with
the task at hand, (just tracking the code and building the most recent
version).

Similarly, I think this use case of "just tracking" should support
branches disappearing from the remote repository without the user
having to edit any config file. If there are entries that are
automatically added by git-clone that should be removed later, that
should happen automatically. A recent thread suggested adding an error
message instructing the user to delete the entries. That's again
unkind to a user who doesn't really want to learn git, but just wants
to get at the most recent version of some code that happens to be
available through git.

That disappearing branches cause problems requiring manual cleanup of
configuration files is one of the reasons that we are not using any
feature branches in the "central" cairo repository, for example, (we
do have branches for release maintenance). I'd really like to be able
to put some feature branches there for shared work, (rather than
forcing that work out to separate personal repositories as we do
know).

Maybe the configuration file entries added by git-clone need to be
marked in some way to distinguish them from manually added entries, so
that we would feel more comfortable automatically removing them when a
remote branch has disappeared.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 21:56 ` Carl Worth
@ 2007-01-02 22:18   ` Jakub Narebski
  2007-01-03  0:34     ` Carl Worth
  2007-01-02 22:44   ` Junio C Hamano
  1 sibling, 1 reply; 68+ messages in thread
From: Jakub Narebski @ 2007-01-02 22:18 UTC (permalink / raw)
  To: git

Carl Worth wrote:

> Similarly, I think this use case of "just tracking" should support
> branches disappearing from the remote repository without the user
> having to edit any config file. If there are entries that are
> automatically added by git-clone that should be removed later, that
> should happen automatically. A recent thread suggested adding an error
> message instructing the user to delete the entries. That's again
> unkind to a user who doesn't really want to learn git, but just wants
> to get at the most recent version of some code that happens to be
> available through git.
> 
> That disappearing branches cause problems requiring manual cleanup of
> configuration files is one of the reasons that we are not using any
> feature branches in the "central" cairo repository, for example, (we
> do have branches for release maintenance). I'd really like to be able
> to put some feature branches there for shared work, (rather than
> forcing that work out to separate personal repositories as we do
> know).
> 
> Maybe the configuration file entries added by git-clone need to be
> marked in some way to distinguish them from manually added entries, so
> that we would feel more comfortable automatically removing them when a
> remote branch has disappeared.

Is it still problem (the dissapearing remote branches) with the new
wildcard remote.<name>.fetch generated by new git-clone? I think it
should not complain that some branches vanished, but it would not I think
it would remove no longer needed tracking branches (local branches)
for us...

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 21:56 ` Carl Worth
  2007-01-02 22:18   ` Jakub Narebski
@ 2007-01-02 22:44   ` Junio C Hamano
  2007-01-02 23:34     ` Carl Worth
  2007-01-03 10:46     ` Jeff King
  1 sibling, 2 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-02 22:44 UTC (permalink / raw)
  To: Carl Worth; +Cc: git

Carl Worth <cworth@cworth.org> writes:

> On Mon, 01 Jan 2007 23:45:08 -0800, Junio C Hamano wrote:
>> This allows "git checkout -d v1.4.3" to detach the HEAD from any
>> branch but point directly at the named commit.
>
> Being able to perform "checkout" with a tag like this, (and no
> specific branch), is something I've been wanting git to acquire for
> some time. So, thanks for coding this up!
>
>> This is still experimental.  While I think it makes sense to
>> allow commits on top of detached HEAD, it is rather dangerous
>> unless you are careful and know what you are doing.
>
> This part I don't understand. I don't see why it's useful to introduce
> new danger to "git checkout"...

I am not saying being risky is useful.  That's why I said it is
experimental.

We could do two things, and I think disallowing commits is not
necessarily a better option of the two.  We could allow commits
and prevent the user from switching out of the detached HEAD
state without an explicit action instead.  If we go the first
route, you need to also prevent merges into the detached HEAD.
If we go the latter I think you only need to add a check in
"git-checkout" but there may be other cases.  In either way, we
need a safety valve, which the experimental code does not have.

And being able to merge into the detached HEAD turns out to be
somewhat useful.  I checked out the v1.4.4.3 and tried to see if
a topic is applicable by merging into that detached HEAD and
running testsuite.  Of course, without any safety valve, I can
easily lose the merge result by switching out of the detached
HEAD state (say, "git checkout master"), but on the other hand,
creating a new branch at that point with "git checkout -b
v1.4.4.3-maint" would let me continue from that point without
losing anything.

But this is only "somewhat" -- I do not have strong opinion
either way, other than that we need a safety valve (which we
agree).

In any case, I did this because I got tired of waiting for it to
happen (I thought you wanted to hack on this over the long
week^W yearend, so I deliberately stayed away from doing this)
and I was bored.  This will not be in 'next' in the current
shape.

You've thought about the issue long enough to write your
commentary and I agree to most of your points (including
favoring "no commit allowed in this state" over "allow commits
and merges to help advanced usage" for its simplicity), so if
you code it up with a clean patch, I would not reject it on the
basis of its design.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH] git-branch: show detached HEAD
  2007-01-02  7:45 [PATCH] Detached HEAD (experimental) Junio C Hamano
  2007-01-02 19:59 ` Edgar Toernig
  2007-01-02 21:56 ` Carl Worth
@ 2007-01-02 23:22 ` Lars Hjemli
  2007-01-03  5:18   ` Shawn O. Pearce
  2007-01-03  7:05   ` Junio C Hamano
  2 siblings, 2 replies; 68+ messages in thread
From: Lars Hjemli @ 2007-01-02 23:22 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This makes git-branch show a detached HEAD as '* (no branch)'.

Signed-off-by: Lars Hjemli <hjemli@gmail.com>
---

This might be a premature patch. But if/when we allow HEAD to be detached, 
git-branch should tell us that HEAD is the current 'branch'.

 builtin-branch.c |  103 +++++++++++++++++++++++++++++-------------------------
 1 files changed, 55 insertions(+), 48 deletions(-)

diff --git a/builtin-branch.c b/builtin-branch.c
index 71f88f2..16f86cc 100644
--- a/builtin-branch.c
+++ b/builtin-branch.c
@@ -231,29 +231,54 @@ static int ref_cmp(const void *r1, const void *r2)
 	return strcmp(c1->name, c2->name);
 }
 
-static void print_ref_info(const unsigned char *sha1, int abbrev)
+static void print_ref_item(struct ref_item *item, int maxwidth, int verbose, 
+			   int abbrev, int current)
 {
+	char c;
+	int color;
 	struct commit *commit;
 	char subject[256];
 
+	switch (item->kind) {
+	case REF_LOCAL_BRANCH:
+		color = COLOR_BRANCH_LOCAL;
+		break;
+	case REF_REMOTE_BRANCH:
+		color = COLOR_BRANCH_REMOTE;
+		break;
+	default:
+		color = COLOR_BRANCH_PLAIN;
+		break;
+	}
 
-	commit = lookup_commit(sha1);
-	if (commit && !parse_commit(commit))
-		pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
-				    subject, sizeof(subject), 0,
-				    NULL, NULL, 0);
-	else
-		strcpy(subject, " **** invalid ref ****");
+	c = ' ';
+	if (current) {
+		c = '*';
+		color = COLOR_BRANCH_CURRENT;
+	}
 
-	printf(" %s %s\n", find_unique_abbrev(sha1, abbrev), subject);
+	if (verbose) {
+		commit = lookup_commit(item->sha1);
+		if (commit && !parse_commit(commit))
+			pretty_print_commit(CMIT_FMT_ONELINE, commit, ~0,
+					    subject, sizeof(subject), 0,
+					    NULL, NULL, 0);
+		else
+			strcpy(subject, " **** invalid ref ****");
+		printf("%c %s%-*s%s %s %s\n", c, branch_get_color(color),
+		       maxwidth, item->name,
+		       branch_get_color(COLOR_BRANCH_RESET),
+		       find_unique_abbrev(item->sha1, abbrev), subject);
+	} else {
+		printf("%c %s%s%s\n", c, branch_get_color(color), item->name,
+		       branch_get_color(COLOR_BRANCH_RESET));
+	}
 }
 
-static void print_ref_list(int kinds, int verbose, int abbrev)
+static void print_ref_list(int kinds, int verbose, int abbrev, int detached)
 {
 	int i;
-	char c;
 	struct ref_list ref_list;
-	int color;
 
 	memset(&ref_list, 0, sizeof(ref_list));
 	ref_list.kinds = kinds;
@@ -261,39 +286,22 @@ static void print_ref_list(int kinds, int verbose, int abbrev)
 
 	qsort(ref_list.list, ref_list.index, sizeof(struct ref_item), ref_cmp);
 
-	for (i = 0; i < ref_list.index; i++) {
-		switch( ref_list.list[i].kind ) {
-			case REF_LOCAL_BRANCH:
-				color = COLOR_BRANCH_LOCAL;
-				break;
-			case REF_REMOTE_BRANCH:
-				color = COLOR_BRANCH_REMOTE;
-				break;
-			default:
-				color = COLOR_BRANCH_PLAIN;
-				break;
-		}
-
-		c = ' ';
-		if (ref_list.list[i].kind == REF_LOCAL_BRANCH &&
-				!strcmp(ref_list.list[i].name, head)) {
-			c = '*';
-			color = COLOR_BRANCH_CURRENT;
-		}
+	if (detached && (kinds & REF_LOCAL_BRANCH)) {
+		struct ref_item item;
+		item.name = "(no branch)";
+		item.kind = REF_LOCAL_BRANCH;
+		hashcpy(item.sha1, head_sha1);
+		if (strlen(item.name) > ref_list.maxwidth)
+			      ref_list.maxwidth = strlen(item.name);
+		print_ref_item(&item, ref_list.maxwidth, verbose, abbrev, 1);
+	}
 
-		if (verbose) {
-			printf("%c %s%-*s%s", c,
-					branch_get_color(color),
-					ref_list.maxwidth,
-					ref_list.list[i].name,
-					branch_get_color(COLOR_BRANCH_RESET));
-			print_ref_info(ref_list.list[i].sha1, abbrev);
-		}
-		else
-			printf("%c %s%s%s\n", c,
-					branch_get_color(color),
-					ref_list.list[i].name,
-					branch_get_color(COLOR_BRANCH_RESET));
+	for (i = 0; i < ref_list.index; i++) {
+		int current = !(detached && (kinds & REF_LOCAL_BRANCH)) &&
+			(ref_list.list[i].kind == REF_LOCAL_BRANCH) &&
+			!strcmp(ref_list.list[i].name, head);
+		print_ref_item(&ref_list.list[i], ref_list.maxwidth, verbose, 
+			       abbrev, current);
 	}
 
 	free_ref_list(&ref_list);
@@ -380,7 +388,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 {
 	int delete = 0, force_delete = 0, force_create = 0;
 	int rename = 0, force_rename = 0;
-	int verbose = 0, abbrev = DEFAULT_ABBREV;
+	int verbose = 0, abbrev = DEFAULT_ABBREV, detached = 0;
 	int reflog = 0;
 	int kinds = REF_LOCAL_BRANCH;
 	int i;
@@ -458,8 +466,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (!head)
 		die("Failed to resolve HEAD as a valid ref.");
 	if (!strcmp(head, "HEAD")) {
-		/* detached HEAD */
-		;
+		detached = 1;
 	}
 	else {
 		if (strncmp(head, "refs/heads/", 11))
@@ -470,7 +477,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 	if (delete)
 		return delete_branches(argc - i, argv + i, force_delete, kinds);
 	else if (i == argc)
-		print_ref_list(kinds, verbose, abbrev);
+		print_ref_list(kinds, verbose, abbrev, detached);
 	else if (rename && (i == argc - 1))
 		rename_branch(head, argv[i], force_rename);
 	else if (rename && (i == argc - 2))
-- 
1.5.0.rc0.g76033

^ permalink raw reply related	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 22:44   ` Junio C Hamano
@ 2007-01-02 23:34     ` Carl Worth
  2007-01-03  2:45       ` Junio C Hamano
  2007-01-08 11:19       ` Junio C Hamano
  2007-01-03 10:46     ` Jeff King
  1 sibling, 2 replies; 68+ messages in thread
From: Carl Worth @ 2007-01-02 23:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 2119 bytes --]

On Tue, 02 Jan 2007 14:44:31 -0800, Junio C Hamano wrote:
> We could do two things, and I think disallowing commits is not
> necessarily a better option of the two.  We could allow commits
> and prevent the user from switching out of the detached HEAD
> state without an explicit action instead.

Yeah, that would be fine too. Personally, I'd be happy with either
approach.

> "git-checkout" but there may be other cases.  In either way, we
> need a safety valve, which the experimental code does not have.

OK. I guess I misinterpreted things. I was afraid that you were
proposing a safety valve on _entering_ the detached state, (perhaps
the -d option to checkout itself). It was the requirement of something
extra to checkout a tag (as opposed to checkout of a branch) that I
disliked.

> In any case, I did this because I got tired of waiting for it to
> happen (I thought you wanted to hack on this over the long
> week^W yearend, so I deliberately stayed away from doing this)
> and I was bored.  This will not be in 'next' in the current
> shape.

I'm glad you went ahead. I ended up almost not touching computers at
all from December 23 to January 2 [*].

> You've thought about the issue long enough to write your
> commentary and I agree to most of your points (including
> favoring "no commit allowed in this state" over "allow commits
> and merges to help advanced usage" for its simplicity), so if
> you code it up with a clean patch, I would not reject it on the
> basis of its design.

I don't actually prefer "no commit allowed". I just didn't want the
user to have to explicitly disable the safety before being able to
perform a checkout based on a tag.

I am still interested in this feature, so I will try to find time to
come back with a revised version of your patch with the missing safety
check (and without requiring -d on checkout). Thanks again for this
initial take on the problem. (Though if anyone else beats me to it, I
certainly will not be offended.)

-Carl

[*] I did play some nice new (to me) board games, (Zendo and DVONN
being standouts), but thats a topic for elsewhere I suppose.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 22:18   ` Jakub Narebski
@ 2007-01-03  0:34     ` Carl Worth
  2007-01-06 18:58       ` J. Bruce Fields
  0 siblings, 1 reply; 68+ messages in thread
From: Carl Worth @ 2007-01-03  0:34 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 5717 bytes --]

On Tue, 02 Jan 2007 23:18:13 +0100, Jakub Narebski wrote:
> Is it still problem (the dissapearing remote branches) with the new
> wildcard remote.<name>.fetch generated by new git-clone?

Ah, you're right. Sorry I missed that, (looks like it was in next but
not in master). I had said I was going to start running from next to
test this stuff.

So now I tried switching to next and hit a couple minor surprises,
(not big issues---mostly just me really trying out separate-remotes
for the first time, and pretending to some extent that I don't know
anything about it):

	$ git checkout next
	error: pathspec 'next' did not match any file(s) known to git.
	Did you forget to 'git add'?

Here I'm using a branch name that cannot be resolved but I'm getting
an error message based on a path name that cannot be resolved. It's
tricky to know how to construct the correct error message here since
"git checkout" can accept either a branch name or a path name. But I
would argue that the branch name is the primary thing for "git
checkout" to act on so the error message should talk about that if the
argument cannot be resolved as either a branch or a path. (Regardless,
"git add" would not be a helpful suggestion if someone were actually
trying to do "git checkout file").

So I know that "git checkout next" used to work, and I know that we're
now in a "separate remotes" world. But I don't know how everything
about how they work yet. Clearly just using "next" doesn't resolve to
anything anymore. So let's see what we have to work with:

	$ git branch
	* master

Hmm... nothing to see here (though the fact that the remote-tracking
branches don't show up here is generally quite nice---I love the
reduced noise). But maybe we want at least an indication of what's
not being shown? Maybe something like:

	$ git branch
	* master
	[and 8 remote branches: use -r to see them as well]

That might avoid some confusion for upgraders anyway.

Moving on, I can see the "missing" branches with:

	$ git branch -r
	  origin/HEAD
	  origin/html
	  origin/maint
	  origin/man
	  origin/master
	  origin/next
	  origin/pu
	  origin/todo

And now I try to check one out:

	$ git checkout origin/next
	git checkout: provided reference cannot be checked out directly

	  You need -b to associate a new branch with the wanted checkout. Example:
	  git checkout -b <new_branch_name> origin/next

And now I start getting confused. If git-checkout wants a branch, and
git-branch says that "origin/next" is a branch, then why won't this
work? OK, I know that something's special about origin/next, (it's a
"remote-tracking branch" and I needed a -r option to get git-branch to
list it for me), but nothing in the git-checkout documentation would
lead me to expect that "git checkout origin/next" wouldn't work.

But at least I'm given a very clear error message here, (a great
improvement, thanks!), and even a sample command. So I can do:

	$ git checkout -b next origin/next

And I'm happy that works and I can build things.

But say in a couple of days I want to build the latest in Junio's
"next". What's the easiest recipe for that now? If I'm understanding
things correctly, I can update my remote-tracking origin/next with
just:

	$ git pull origin

And that's thanks to this entry in .git/config:

	[remote "origin"]
	        url = git://git.kernel.org/pub/scm/git/git.git
	        fetch = +refs/heads/*:refs/remotes/origin/*

I _think_ there's also a way for me to configure my local "next" to
automatically fast-forward to track what's happening in "origin/next"
on any invocation of "git pull origin", right? That is, configure
origin/next as the thing to get merged into my local next when I
pull. How do I do that again?  Where's that documented?

Ah, if I look in .git/config I can see that I should be able to just
copy the block for the "master" branch and come up with:

	[branch "next"]
	        remote = origin
	        merge = refs/heads/next

is that right? If so, it's really nice that what used to be hard-coded
magic, (first remote branch getting merged into current branch), is
now self-documented magic that can easily be applied to other branch
combinations. Another great improvement, well done!

The remaining question is whether it wouldn't make sense to just
create that block when I did "git checkout -b next origin/next". I
think this has been proposed before and Junio said "Maybe, if
everything can be resolved unambiguously, but even then, not
always". I'd be interested in hearing more about when that would be
the wrong thing to do. It seems it would be awfully convenient here,
(and not doing it means it's easy to end up with a local "next" branch
without realizing how stale it is).

Now, if I'm only tracking/building what's in next and not actually
planning on committing anything, then I wouldn't even need the local
branch at all if I could just checkout the remote tracking-branch
directly:

	$ git checkout origin/next

In fact, I'd greatly prefer this, since a lot of the advantage of
separate remotes is that "git branch" lists only stuff I'm actually
working on and not other noise from remote branches that I consider
uninteresting. Forcing me to clutter up that list just to examine the
state of some remote branch is not helpful.

Of course, this feature depends on the pending "detached HEAD" work
that started this thread, (wow, look at that, I wandered back on
topic!).

And a further question from there is whether it makes sense to have
"git checkout" look around in .git/refs/remotes/* so that I could
checkout origin/next by just using the name "next":

	$ git checkout next

which could complain if that couldn't be resolved without ambiguity.
Would that be a bad idea?

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 23:34     ` Carl Worth
@ 2007-01-03  2:45       ` Junio C Hamano
  2007-01-08 11:19       ` Junio C Hamano
  1 sibling, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-03  2:45 UTC (permalink / raw)
  To: Carl Worth; +Cc: git

Carl Worth <cworth@cworth.org> writes:

> I don't actually prefer "no commit allowed". I just didn't want the
> user to have to explicitly disable the safety before being able to
> perform a checkout based on a tag.

Ok, then I think we are in agreement that the safety should be
at the point where the user might leave the detached state.

> I am still interested in this feature, so I will try to find time to
> come back with a revised version of your patch with the missing safety
> check (and without requiring -d on checkout). Thanks again for this
> initial take on the problem. (Though if anyone else beats me to it, I
> certainly will not be offended.)

Sounds good.  

I do not mind losing -d, but I would suggest that there should
be a message that says "you are no longer on any branch" after a
checkout that makes the head detached.  The user should be
warned about such an unusal situation.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-02 23:22 ` [PATCH] git-branch: show detached HEAD Lars Hjemli
@ 2007-01-03  5:18   ` Shawn O. Pearce
  2007-01-03  6:53     ` Junio C Hamano
  2007-01-03  7:05   ` Junio C Hamano
  1 sibling, 1 reply; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-03  5:18 UTC (permalink / raw)
  To: Lars Hjemli; +Cc: git, Junio C Hamano

Lars Hjemli <hjemli@gmail.com> wrote:
> This makes git-branch show a detached HEAD as '* (no branch)'.

It would be nicer if when you are on a remote tracking branch or
on a tag that the name of the tag or the remote tracking branch is
shown rather than '* (no branch)'.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-03  5:18   ` Shawn O. Pearce
@ 2007-01-03  6:53     ` Junio C Hamano
  2007-01-03  7:50       ` Lars Hjemli
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-03  6:53 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Lars Hjemli, git

"Shawn O. Pearce" <spearce@spearce.org> writes:

> Lars Hjemli <hjemli@gmail.com> wrote:
>> This makes git-branch show a detached HEAD as '* (no branch)'.
>
> It would be nicer if when you are on a remote tracking branch or
> on a tag that the name of the tag or the remote tracking branch is
> shown rather than '* (no branch)'.

That would be utterly confusing if you are talking about the
same detached HEAD semantics as I and Carl discussed today.  I
like what Lars's patch does (although I felt that it was too big
for only doing this which made it harder to judge), but I would
even make it stronger to say something like:

	* You are not on ANY branch right now.
          master
          next
          pu
          ...

You will never be _on_ a remote tracking branch.  So far we did
not allow HEAD to point at outside refs/heads/ and we still
don't.  When HEAD is detached from any branch, however, it can
store a bare 40-hex (plus LF) commit object name instead of
being a symref.  You are not on any branch at that point.

Most importantly, if we allow commits to be built on top of HEAD
while it is detached from any branch, the commit will _not_
advance any branch.  So showing the remote tracking branch the
way you suggest will be misleading.

If we do not allow commits to be built on top, we would still
allow something to be done other than switching out of "detached
mode" to be useful.  For example, reset to move around which
commit to look at would be a useful thing.  Another of my
unstated desire is to get rid of the use of special "bisect"
branch during bisection using detached HEAD.  Again, if we
highlight remote tracking branch whose tip happens to be the
same commit as the current HEAD as you suggest, that would lead
to quite confusing behaviour.  Sometimes it would say the same
thing as you are _on_ that branch (which confuses you because
you are _not_ on that branch in reality), sometimes it would
highlight nothing to show you are not on any branch.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-02 23:22 ` [PATCH] git-branch: show detached HEAD Lars Hjemli
  2007-01-03  5:18   ` Shawn O. Pearce
@ 2007-01-03  7:05   ` Junio C Hamano
  2007-01-03  7:37     ` Lars Hjemli
  1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-03  7:05 UTC (permalink / raw)
  To: Lars Hjemli; +Cc: git

Lars Hjemli <hjemli@gmail.com> writes:

> This makes git-branch show a detached HEAD as '* (no branch)'.
>
> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
> ---
>
> This might be a premature patch. But if/when we allow HEAD to be detached, 
> git-branch should tell us that HEAD is the current 'branch'.

I fully agree with the motivation, but 100 lines of change to
adjust only to detached HEAD seems too much.  What else is going
on in this patch, I wonder...

Can we have two patches, one for loop restructuring without
detached HEAD support, and then another to add support for it?

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-03  7:05   ` Junio C Hamano
@ 2007-01-03  7:37     ` Lars Hjemli
  0 siblings, 0 replies; 68+ messages in thread
From: Lars Hjemli @ 2007-01-03  7:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 1/3/07, Junio C Hamano <junkio@cox.net> wrote:
> Can we have two patches, one for loop restructuring without
> detached HEAD support, and then another to add support for it?

Sure, I'll do it tonight

-- 
larsh

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-03  6:53     ` Junio C Hamano
@ 2007-01-03  7:50       ` Lars Hjemli
  2007-01-03  7:52         ` Junio C Hamano
  0 siblings, 1 reply; 68+ messages in thread
From: Lars Hjemli @ 2007-01-03  7:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Shawn O. Pearce, git

On 1/3/07, Junio C Hamano <junkio@cox.net> wrote:
> I would even make it stronger to say something like:
>
>         * You are not on ANY branch right now.
>           master
>           next
>           pu
>           ...
>

Hmm, that wouldn't be very nice for 'git-branch -v' (which suddenly
got extra useful with detached head).

-- 
larsh

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] git-branch: show detached HEAD
  2007-01-03  7:50       ` Lars Hjemli
@ 2007-01-03  7:52         ` Junio C Hamano
  0 siblings, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-03  7:52 UTC (permalink / raw)
  To: Lars Hjemli; +Cc: git

"Lars Hjemli" <hjemli@gmail.com> writes:

> On 1/3/07, Junio C Hamano <junkio@cox.net> wrote:
>> I would even make it stronger to say something like:
>>
>>         * You are not on ANY branch right now.
>>           master
>>           next
>>           pu
>>           ...
>>
>
> Hmm, that wouldn't be very nice for 'git-branch -v' (which suddenly
> got extra useful with detached head).

Ah, please scratch that.

I did not remember that option, since I do not use it myself.
Thanks for injecting sanity.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 22:44   ` Junio C Hamano
  2007-01-02 23:34     ` Carl Worth
@ 2007-01-03 10:46     ` Jeff King
  2007-01-03 11:59       ` Jeff King
  1 sibling, 1 reply; 68+ messages in thread
From: Jeff King @ 2007-01-03 10:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Carl Worth, git

On Tue, Jan 02, 2007 at 02:44:31PM -0800, Junio C Hamano wrote:

> necessarily a better option of the two.  We could allow commits
> and prevent the user from switching out of the detached HEAD
> state without an explicit action instead.  If we go the first

I think you should only enact this safety valve if there have actually
been commits. Otherwise, people who are just tracking and do a
"git-checkout v1.4.0; look look look; git-checkout v1.5.0" will get a
confusing message.

Personally, I like the "don't allow commit without a branch" approach,
but only if you can "git-commit -b newbranch" and "git-merge -b
newbranch" to make it convenient to create a branch. Making commits that
aren't on any branch seems like a broken state (and indeed, you have to
use special options to get out of the state); it makes more sense to me
to never enter the state in the first place.

Also, the implementation should be conceptually simple. Put
refs/tags/v1.4.0 into HEAD on checkout. Disallow commit/merge unless
HEAD points to refs/heads/*.

Just my 2 cents...

-Peff

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-03 10:46     ` Jeff King
@ 2007-01-03 11:59       ` Jeff King
  0 siblings, 0 replies; 68+ messages in thread
From: Jeff King @ 2007-01-03 11:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Carl Worth, git

On Wed, Jan 03, 2007 at 05:46:20AM -0500, Jeff King wrote:

> Also, the implementation should be conceptually simple. Put
> refs/tags/v1.4.0 into HEAD on checkout. Disallow commit/merge unless
> HEAD points to refs/heads/*.

Let me take that back. It is actually still annoying to implement, since
many things (at least commit-tree, branch) are unhappy with a non-branch
in HEAD. Moreover, it's not as flexible as simply putting the commit
sha1 into the HEAD, as you suggested. My suggestion allows only
non-branch refs to be checked-out; however, it's likely somebody might
want to git-checkout HEAD~10 or some other unnamed thing.

-Peff

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-03  0:34     ` Carl Worth
@ 2007-01-06 18:58       ` J. Bruce Fields
  2007-01-06 20:48         ` Alan Chandler
  0 siblings, 1 reply; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-06 18:58 UTC (permalink / raw)
  To: Carl Worth; +Cc: Jakub Narebski, git

On Tue, Jan 02, 2007 at 04:34:45PM -0800, Carl Worth wrote:
> And now I start getting confused. If git-checkout wants a branch, and
> git-branch says that "origin/next" is a branch, then why won't this
> work? OK, I know that something's special about origin/next, (it's a
> "remote-tracking branch" and I needed a -r option to get git-branch to
> list it for me), but nothing in the git-checkout documentation would
> lead me to expect that "git checkout origin/next" wouldn't work.

If we use the word "branches" for things that you can check out and
commit to, then "remote-tracking branches" are not actually branches.
Argh!

What would be better terminology here?

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-06 18:58       ` J. Bruce Fields
@ 2007-01-06 20:48         ` Alan Chandler
  2007-01-06 22:52           ` J. Bruce Fields
  0 siblings, 1 reply; 68+ messages in thread
From: Alan Chandler @ 2007-01-06 20:48 UTC (permalink / raw)
  To: git

On Saturday 06 January 2007 18:58, J. Bruce Fields wrote:
> If we use the word "branches" for things that you can check out and
> commit to, then "remote-tracking branches" are not actually branches.
> Argh!
>
> What would be better terminology here?

Why can't we use the terms 'local branch' and 'remote branch'.  We can 
only commit to local branches - you need to push to remote ones.
-- 
Alan Chandler
http://www.chandlerfamily.org.uk

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-06 20:48         ` Alan Chandler
@ 2007-01-06 22:52           ` J. Bruce Fields
  0 siblings, 0 replies; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-06 22:52 UTC (permalink / raw)
  To: Alan Chandler; +Cc: git

On Sat, Jan 06, 2007 at 08:48:15PM +0000, Alan Chandler wrote:
> On Saturday 06 January 2007 18:58, J. Bruce Fields wrote:
> > If we use the word "branches" for things that you can check out and
> > commit to, then "remote-tracking branches" are not actually branches.
> > Argh!
> >
> > What would be better terminology here?
> 
> Why can't we use the terms 'local branch' and 'remote branch'.  We can 
> only commit to local branches - you need to push to remote ones.

We'd have to replace "branch" by "local branch" in a lot of
documentation, but that could work.

Though what do you call a branch in a remote repository then, if not a
remote branch?  I suppose it doesn't matter.

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-02 23:34     ` Carl Worth
  2007-01-03  2:45       ` Junio C Hamano
@ 2007-01-08 11:19       ` Junio C Hamano
  2007-01-08 13:17         ` Jeff King
  1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-08 11:19 UTC (permalink / raw)
  To: git; +Cc: Carl Worth

Carl Worth <cworth@cworth.org> writes:

> On Tue, 02 Jan 2007 14:44:31 -0800, Junio C Hamano wrote:
> ...
>> In any case, I did this because I got tired of waiting for it to
>> happen (I thought you wanted to hack on this over the long
>> week^W yearend, so I deliberately stayed away from doing this)
>> and I was bored.  This will not be in 'next' in the current
>> shape.
> ...
> I don't actually prefer "no commit allowed". I just didn't want the
> user to have to explicitly disable the safety before being able to
> perform a checkout based on a tag.
>
> I am still interested in this feature,...

I decided to fast-track this one.  With a handful fix-ups, this
is now at the tip of 'next'.

The primary difference from the one we discussed, and then has
been sitting in 'pu', is that coming back from the detached HEAD
state is allowed only with '-f' or to a branch that is a
fast-forward of HEAD.

So you can do:

	git checkout v1.2.0 ;# detach
        ... look around ...
        git checkout v1.4.0 ;# still detached
        ... look around ...
        git checkout master ;# Ok, because v1.4.0 is an ancestor of master

but you would be warned and asked to say -f if you do:

        git checkout v1.4.0 ;# detach
        edit ...
        git commit -a -m 'some tweak'
	git checkout master ;# Not Ok -- you may lose that commit.

An alternative exit in this case is to create a new branch at
that point.  So this does work:

        git checkout v1.4.0 ;# detach
        edit ...
        git commit -a -m 'some tweak'
	git checkout -b maint-1.4.0 ;# start the maint-1.4.0 branch

Have fun.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-08 11:19       ` Junio C Hamano
@ 2007-01-08 13:17         ` Jeff King
  2007-01-09  0:19           ` Junio C Hamano
  0 siblings, 1 reply; 68+ messages in thread
From: Jeff King @ 2007-01-08 13:17 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Carl Worth

On Mon, Jan 08, 2007 at 03:19:48AM -0800, Junio C Hamano wrote:

> I decided to fast-track this one.  With a handful fix-ups, this
> is now at the tip of 'next'.

I haven't seen the code, waiting for kernel.org to mirror, but I have a
question...

> The primary difference from the one we discussed, and then has
> been sitting in 'pu', is that coming back from the detached HEAD
> state is allowed only with '-f' or to a branch that is a
> fast-forward of HEAD.

Hrm. So does that mean this doesn't work (without -f):

  git checkout v1.4.0
  ... look around ...
  git checkout v1.2.0

I think a better (but more expensive) check would be "coming back from
the detached HEAD is allowed only with '-f' or if HEAD is an ancestor
of any non-HEAD ref."

-Peff

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-08 13:17         ` Jeff King
@ 2007-01-09  0:19           ` Junio C Hamano
  2007-01-09  0:43             ` Carl Worth
  2007-01-09 14:21             ` Jeff King
  0 siblings, 2 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09  0:19 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Carl Worth

Jeff King <peff@peff.net> writes:

> On Mon, Jan 08, 2007 at 03:19:48AM -0800, Junio C Hamano wrote:
>
>> I decided to fast-track this one.  With a handful fix-ups, this
>> is now at the tip of 'next'.
>
> I haven't seen the code, waiting for kernel.org to mirror, but I have a
> question...
>
>> The primary difference from the one we discussed, and then has
>> been sitting in 'pu', is that coming back from the detached HEAD
>> state is allowed only with '-f' or to a branch that is a
>> fast-forward of HEAD.
>
> Hrm. So does that mean this doesn't work (without -f):
>
>   git checkout v1.4.0
>   ... look around ...
>   git checkout v1.2.0

That should work.

The first checkout, because there is no branch v1.4.0, makes the
HEAD detached.  You are no longer on any branch at that point,
and "git checkout v1.2.0" that follows do not trigger the check
which is about "coming back from the detached HEAD state".

But I would probably do the second v1.2.0 "checkout" with "git
reset --hard", if what I am doing is "wandering, looking around
to see different commits".

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  0:19           ` Junio C Hamano
@ 2007-01-09  0:43             ` Carl Worth
  2007-01-09  1:05               ` Junio C Hamano
  2007-01-09 14:21             ` Jeff King
  1 sibling, 1 reply; 68+ messages in thread
From: Carl Worth @ 2007-01-09  0:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git

[-- Attachment #1: Type: text/plain, Size: 1381 bytes --]

On Mon, 08 Jan 2007 16:19:28 -0800, Junio C Hamano wrote:
> The first checkout, because there is no branch v1.4.0, makes the
> HEAD detached.  You are no longer on any branch at that point,
> and "git checkout v1.2.0" that follows do not trigger the check
> which is about "coming back from the detached HEAD state".

So what's the final check? Is it "can come from detached HEAD to a
branch only if the detached HEAD is reachable from the target branch"?

If so, that's still a trap for people who are just exploring with "git
checkout" and never make any commits while detached.

> But I would probably do the second v1.2.0 "checkout" with "git
> reset --hard", if what I am doing is "wandering, looking around
> to see different commits".

You would probably do this, yes, but is it what you would recommend
in a tutorial for new users doing read-only exploration of old
versions of some piece of software? One of the main reasons I'm
interested in the "detached head" stuff is so that such users can use
"git checkout" to explore any revision and never have to worry about
doing anything "wrong", (never leave any commits dangling), nor ever
have to see any "scary" message, (ie. "use checkout -f if you know
what you are doing").

-Carl

PS. Thanks for giving detached head some attention---I'm chronically
inept at getting into actual git development like I'd really like to.

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  0:43             ` Carl Worth
@ 2007-01-09  1:05               ` Junio C Hamano
  2007-01-09  1:15                 ` Carl Worth
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09  1:05 UTC (permalink / raw)
  To: Carl Worth; +Cc: git

Carl Worth <cworth@cworth.org> writes:

> On Mon, 08 Jan 2007 16:19:28 -0800, Junio C Hamano wrote:
>> The first checkout, because there is no branch v1.4.0, makes the
>> HEAD detached.  You are no longer on any branch at that point,
>> and "git checkout v1.2.0" that follows do not trigger the check
>> which is about "coming back from the detached HEAD state".
>
> So what's the final check? Is it "can come from detached HEAD to a
> branch only if the detached HEAD is reachable from the target branch"?
>
> If so, that's still a trap for people who are just exploring with "git
> checkout" and never make any commits while detached.

An obvious alternative is not to allow building on top of a HEAD
that is detached at all, which I suggested initially.

A non-alternative is to silently lose commits, which you seem to
be suggesting, but I would rather play it safe.

The wording used for current warning that says "use checkout -f"
is horrible, and it needs to be reworded much better, but other
than that, I think playing safer is much better than making a
worse trap of silently losing the commits they may make before
they come to understand how "a branch" works.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  1:05               ` Junio C Hamano
@ 2007-01-09  1:15                 ` Carl Worth
  2007-01-09  3:26                   ` Shawn O. Pearce
  2007-01-09  8:12                   ` [PATCH] Detached HEAD (experimental) Luben Tuikov
  0 siblings, 2 replies; 68+ messages in thread
From: Carl Worth @ 2007-01-09  1:15 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 1224 bytes --]

On Mon, 08 Jan 2007 17:05:26 -0800, Junio C Hamano wrote:
> An obvious alternative is not to allow building on top of a HEAD
> that is detached at all, which I suggested initially.

That sounds great to me. Let's just suggest "checkout -b" before
commit, (maybe even add new "merge -b <newbranch>" and "commit -b
<newbranch>" so the suggest command could be even closer to what the
user wanted).

> A non-alternative is to silently lose commits, which you seem to
> be suggesting, but I would rather play it safe.

No, I would never want that. We both agreed earlier that a safety
valve is necessary.

I just want to make sure that people that never actually need it don't
have to see the message. And I don't think that _that_ part would be
feasible with the safety valve at the point of "leaving detached
state". It would basically come down to having to do reachability
analysis for the current HEAD from all known branches or something
equally horrific.

So let's put the safety valve where it's cheap to detect and where we
know it will distinguish between read-only and read-write use, (that
is, put it precisely at the point where there's an attempt to create a
new commit object while in the detached state).

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  1:15                 ` Carl Worth
@ 2007-01-09  3:26                   ` Shawn O. Pearce
  2007-01-09  7:07                     ` Junio C Hamano
  2007-01-09  8:12                   ` [PATCH] Detached HEAD (experimental) Luben Tuikov
  1 sibling, 1 reply; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-09  3:26 UTC (permalink / raw)
  To: Carl Worth; +Cc: Junio C Hamano, git

Carl Worth <cworth@cworth.org> wrote:
> On Mon, 08 Jan 2007 17:05:26 -0800, Junio C Hamano wrote:
> > An obvious alternative is not to allow building on top of a HEAD
> > that is detached at all, which I suggested initially.
> 
> I just want to make sure that people that never actually need it don't
> have to see the message. And I don't think that _that_ part would be
> feasible with the safety valve at the point of "leaving detached
> state". It would basically come down to having to do reachability
> analysis for the current HEAD from all known branches or something
> equally horrific.

The common case is probably going to be where the argument to
`git checkout` is a fast-foward of the detached HEAD.  And that's
pretty cheap to check.  So we perform that check, and if we fail
that then we search through every ref to determine if the detached
HEAD is fully contained in any of those.  Currently that would be
pretty slow to do with the current tools, but a small modification
of say git-merge-base (or git-describe) might make it cheap enough
to run during this slightly less common case.

No need to complicate merge/am/rebase/revert/commit/applymbox
with a -b option.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  3:26                   ` Shawn O. Pearce
@ 2007-01-09  7:07                     ` Junio C Hamano
  2007-01-09 10:41                       ` [PATCH 0/6] Expose in_merge_bases() via merge-base Junio C Hamano
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09  7:07 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

"Shawn O. Pearce" <spearce@spearce.org> writes:

> The common case is probably going to be where the argument to
> `git checkout` is a fast-foward of the detached HEAD.  And that's
> pretty cheap to check.  So we perform that check, and if we fail
> that then we search through every ref to determine if the detached
> HEAD is fully contained in any of those.  Currently that would be
> pretty slow to do with the current tools, but a small modification
> of say git-merge-base (or git-describe) might make it cheap enough
> to run during this slightly less common case.

The needed change to merge-base is quite minimum.  Let me come
up with a patch...

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  1:15                 ` Carl Worth
  2007-01-09  3:26                   ` Shawn O. Pearce
@ 2007-01-09  8:12                   ` Luben Tuikov
  1 sibling, 0 replies; 68+ messages in thread
From: Luben Tuikov @ 2007-01-09  8:12 UTC (permalink / raw)
  To: Carl Worth, Junio C Hamano; +Cc: git

--- Carl Worth <cworth@cworth.org> wrote:
> 
> So let's put the safety valve where it's cheap to detect and where we
> know it will distinguish between read-only and read-write use, (that
> is, put it precisely at the point where there's an attempt to create a
> new commit object while in the detached state).

Yes, I agree.

>From my point of view, the question is where does it "go" committing
changes on top of a "detached HEAD".  Commits shold probably be only
allowed on top of local branches, since creating the branch itself
shows an intention, possibly intention to do work, to commit
new things.

    Luben

^ permalink raw reply	[flat|nested] 68+ messages in thread

* [PATCH 0/6] Expose in_merge_bases() via merge-base.
  2007-01-09  7:07                     ` Junio C Hamano
@ 2007-01-09 10:41                       ` Junio C Hamano
  0 siblings, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09 10:41 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: git

Junio C Hamano <junkio@cox.net> writes:

> "Shawn O. Pearce" <spearce@spearce.org> writes:
>
>> The common case is probably going to be where the argument to
>> `git checkout` is a fast-foward of the detached HEAD.  And that's
>> pretty cheap to check.  So we perform that check, and if we fail
>> that then we search through every ref to determine if the detached
>> HEAD is fully contained in any of those.  Currently that would be
>> pretty slow to do with the current tools, but a small modification
>> of say git-merge-base (or git-describe) might make it cheap enough
>> to run during this slightly less common case.
>
> The needed change to merge-base is quite minimum.  Let me come
> up with a patch...

[PATCH 1/6] Allow in_merge_bases() to take more than one reference commits.
[PATCH 2/6] merge_base(): move traversal into a separate function.
[PATCH 3/6] git-merge-base: --check-ancestry option
[PATCH 4/6] in_merge_bases(): optimization
[PATCH 5/6] Make merge-base a built-in.
[PATCH 6/6] Teach "git-merge-base --check-ancestry" about refs.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09  0:19           ` Junio C Hamano
  2007-01-09  0:43             ` Carl Worth
@ 2007-01-09 14:21             ` Jeff King
  2007-01-09 21:20               ` Junio C Hamano
  1 sibling, 1 reply; 68+ messages in thread
From: Jeff King @ 2007-01-09 14:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Carl Worth

On Mon, Jan 08, 2007 at 04:19:28PM -0800, Junio C Hamano wrote:

> > Hrm. So does that mean this doesn't work (without -f):
> >
> >   git checkout v1.4.0
> >   ... look around ...
> >   git checkout v1.2.0
> 
> That should work.
> 
> The first checkout, because there is no branch v1.4.0, makes the
> HEAD detached.  You are no longer on any branch at that point,
> and "git checkout v1.2.0" that follows do not trigger the check
> which is about "coming back from the detached HEAD state".

Oh, that's even worse, since the safety valve doesn't kick in when it
should. For example, with what's in next now, I can do this:

  git checkout v1.4.0
  hack hack hack
  git commit -m -a 'some changes which will never be seen again'
  git checkout v1.2.0

I thought the _point_ of the safety valve was not to lose those changes.

> But I would probably do the second v1.2.0 "checkout" with "git
> reset --hard", if what I am doing is "wandering, looking around
> to see different commits".

As Carl mentioned, I think recommending that workflow is a terrible idea
from a user interface perspective.

-Peff

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 14:21             ` Jeff King
@ 2007-01-09 21:20               ` Junio C Hamano
  2007-01-09 21:31                 ` J. Bruce Fields
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09 21:20 UTC (permalink / raw)
  To: Jeff King; +Cc: git

Jeff King <peff@peff.net> writes:

> For example, with what's in next now, I can do this:
>
>   git checkout v1.4.0
>   hack hack hack
>   git commit -m -a 'some changes which will never be seen again'
>   git checkout v1.2.0
>
> I thought the _point_ of the safety valve was not to lose those changes.

Fair enough.

We could always do the check upon "git checkout" from a detached
HEAD state, whether it takes you back on some existing branch or
leaves your HEAD still detached.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:20               ` Junio C Hamano
@ 2007-01-09 21:31                 ` J. Bruce Fields
  2007-01-09 21:43                   ` Carl Worth
  2007-01-09 22:37                   ` Junio C Hamano
  0 siblings, 2 replies; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-09 21:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git

On Tue, Jan 09, 2007 at 01:20:27PM -0800, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
> 
> > For example, with what's in next now, I can do this:
> >
> >   git checkout v1.4.0
> >   hack hack hack
> >   git commit -m -a 'some changes which will never be seen again'
> >   git checkout v1.2.0
> >
> > I thought the _point_ of the safety valve was not to lose those changes.
> 
> Fair enough.
> 
> We could always do the check upon "git checkout" from a detached
> HEAD state, whether it takes you back on some existing branch or
> leaves your HEAD still detached.

Stupid question: why can't checkout do something like this?

	if we're currently not on a branch, fail if .git/PREV
		doesn't point to the same commit as .git/HEAD.

	if we're checking out a non-branch, store its SHA1 into
		.git/PREV.

So the user gets a warning (overrideable with some kind of --force
option) if they do a checkout when the HEAD isn't exactly what they last
checked out.  Then

	git checkout master
	git checkout v1.4.0
	git checkout v1.2.0
	git checkout master

all works without complaints, but the example above gives a warning at
the "git checkout v1.2.0" point.

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:31                 ` J. Bruce Fields
@ 2007-01-09 21:43                   ` Carl Worth
  2007-01-09 21:53                     ` J. Bruce Fields
                                       ` (3 more replies)
  2007-01-09 22:37                   ` Junio C Hamano
  1 sibling, 4 replies; 68+ messages in thread
From: Carl Worth @ 2007-01-09 21:43 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Junio C Hamano, Jeff King, git

[-- Attachment #1: Type: text/plain, Size: 1887 bytes --]

On Tue, 9 Jan 2007 16:31:17 -0500, "J. Bruce Fields" wrote:
> > >   git checkout v1.4.0
> > >   hack hack hack
> > >   git commit -m -a 'some changes which will never be seen again'
> > >   git checkout v1.2.0
> > >
> > > I thought the _point_ of the safety valve was not to lose those changes.
...
> Stupid question: why can't checkout do something like this?
>
> 	if we're currently not on a branch, fail if .git/PREV
> 		doesn't point to the same commit as .git/HEAD.
>
> 	if we're checking out a non-branch, store its SHA1 into
> 		.git/PREV.

I would guess the problem is that this would still cause warnings even
if the user had since given a name (created a branch) for the commits
originally made to the dangling head.

Frankly, I don't understand why so much effort is being put toward
allowing these "fragile commits" to be made in the first place. Why
not require users to name the branch before creating any commits, just
as has always been the case?

To me, the only real advantage to the new "detached head" stuff is
simply making it easier to checkout previous state without having to
name a new branch precisely _because_ the user has not intent to
commit anything. If the user is going to commit something, then the
user should be able to come up with a name for the branch.

But, whatever, if allowing fragile commits is seen as important by
those doing the work, who am I to complain about that? I'd just ask
that the following not be made slow:

	git checkout commit-from-beginning-of-time
	git checkout master

Thanks to the index, and the simplicity of what "git checkout" means,
checkout has always been blisteringly fast. All the talk of doing
reachability analysis scares me from a performance point of view,
(particularly when the _interesting_ cases (to me) of checkouts to
non-branches never need this anyway---since no commits will be made).

Thanks,

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:43                   ` Carl Worth
@ 2007-01-09 21:53                     ` J. Bruce Fields
  2007-01-09 23:44                     ` Shawn O. Pearce
                                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-09 21:53 UTC (permalink / raw)
  To: Carl Worth; +Cc: Junio C Hamano, Jeff King, git

On Tue, Jan 09, 2007 at 01:43:16PM -0800, Carl Worth wrote:
> On Tue, 9 Jan 2007 16:31:17 -0500, "J. Bruce Fields" wrote:
> > > >   git checkout v1.4.0
> > > >   hack hack hack
> > > >   git commit -m -a 'some changes which will never be seen again'
> > > >   git checkout v1.2.0
> > > >
> > > > I thought the _point_ of the safety valve was not to lose those changes.
> ...
> > Stupid question: why can't checkout do something like this?
> >
> > 	if we're currently not on a branch, fail if .git/PREV
> > 		doesn't point to the same commit as .git/HEAD.
> >
> > 	if we're checking out a non-branch, store its SHA1 into
> > 		.git/PREV.
> 
> I would guess the problem is that this would still cause warnings even
> if the user had since given a name (created a branch) for the commits
> originally made to the dangling head.

I think as long as we provided a special exception for a case like "git
checkout -b":

	git checkout v1.4.0
	hack hack hack
	git commit -m -a 'some changes'
	git checkout -b new-changes

and also provide a way out (--force-checkout-losing-current-head) for
people that really know what they're doing, that should be more than
enough to handle that sort of case.

Because, I agree, the point is to make easy what 90% of users will
probably do, at least on the first encounter with git--download project
X, checkout version Y, build--and making checkouts on detached commits
convenient seems a lower priority.

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:31                 ` J. Bruce Fields
  2007-01-09 21:43                   ` Carl Worth
@ 2007-01-09 22:37                   ` Junio C Hamano
  2007-01-09 23:39                     ` Shawn O. Pearce
  2007-01-09 23:46                     ` Linus Torvalds
  1 sibling, 2 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-09 22:37 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Jeff King, git

"J. Bruce Fields" <bfields@fieldses.org> writes:

> On Tue, Jan 09, 2007 at 01:20:27PM -0800, Junio C Hamano wrote:
>> Jeff King <peff@peff.net> writes:
>> 
>> > For example, with what's in next now, I can do this:
>> >
>> >   git checkout v1.4.0
>> >   hack hack hack
>> >   git commit -m -a 'some changes which will never be seen again'
>> >   git checkout v1.2.0
>> >
>> > I thought the _point_ of the safety valve was not to lose those changes.
>> 
>> Fair enough.
>> 
>> We could always do the check upon "git checkout" from a detached
>> HEAD state, whether it takes you back on some existing branch or
>> leaves your HEAD still detached.
>
> Stupid question: why can't checkout do something like this?
>
> 	if we're currently not on a branch, fail if .git/PREV
> 		doesn't point to the same commit as .git/HEAD.
>
> 	if we're checking out a non-branch, store its SHA1 into
> 		.git/PREV.

I do not want to think about the consequences of adding more
cruft under .git/ directory.  For example, should PREV be
noticed by fsck and prune?  What should various forms of
'git-reset' do with it?  How does it interact with 'git-bisect'?

Being able to test merge or even make commits without being on a
branch is vastly useful.  It might or might not lead to anywhere
even after you make a handful commits -- and I would imagine
that it would be very handy to be able to be lazy and not having
to decide if it is worth a new branch.

But that may be just my imagination; I generally prefer any
feature that allows me to defer decision over something that
makes me decide early.  If Carl wants to do a patch to teach
'git-commit' (and all other things that can create commits) not
to do things from working in a detached HEAD, I would probably
not opposed to it too much, but I am fairly certain that I won't
be coding it myself.

It's tempting to forget about this whole "safety" business.
Because we allow "reset --hard" and other forms of operations
that can lose history if they were done while on a branch, only
giving the safety to "git checkout" feels somewhat silly.  And
the primary motive for detached HEAD as I understand it is for
sightseeing, and not allowing "reset --hard" to jump around is
just plain silly.

That is, after:

	git checkout v1.4.0

you are not on any branch, and we would still allow

	git reset --hard v1.2.0

which is exactly the same as:

	git checkout v1.2.0

You can still say:

	git checkout master

and we do not even check.

Which makes the "merge-base --check-ancestry" stuff I did last
night pretty much unnecessary, but that's Ok.  It will find
other uses.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 22:37                   ` Junio C Hamano
@ 2007-01-09 23:39                     ` Shawn O. Pearce
  2007-01-09 23:46                     ` Linus Torvalds
  1 sibling, 0 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-09 23:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: J. Bruce Fields, Jeff King, git

Junio C Hamano <junkio@cox.net> wrote:
> I do not want to think about the consequences of adding more
> cruft under .git/ directory.  For example, should PREV be
> noticed by fsck and prune?  What should various forms of
> 'git-reset' do with it?  How does it interact with 'git-bisect'?

I agree.  The reachability list for those is already starting to
get out of control, and the rules for making sure those files are
always in sync with every command is getting crazy.  Didn't we just
fix `git reset --hard` to throw away .git/MERGE_MSG?  That's been
a longstanding bug right there, and that's something that has been
in the tree for a loooooooong time.
 
> Being able to test merge or even make commits without being on a
> branch is vastly useful.  It might or might not lead to anywhere
> even after you make a handful commits -- and I would imagine
> that it would be very handy to be able to be lazy and not having
> to decide if it is worth a new branch.

I agree.  I'm always creating and deleting `foof` because I need
someplace to work real quick.  Being able to work on a detached HEAD
would just slightly streamline the process, especially given that
`git checkout -b a-real-name` is readily available to move that
detached HEAD state into a real branch and continue on with it.
 
> If Carl wants to do a patch to teach
> 'git-commit' (and all other things that can create commits) not
> to do things from working in a detached HEAD

My concern here is to hit all of the corner cases.  reset.  bisect.
am.  rebase.  merge.  cherry-pick/revert.  Did I get all of 'em?
I'm not sure actually.  ;-)

> It's tempting to forget about this whole "safety" business.
> Because we allow "reset --hard" and other forms of operations
> that can lose history if they were done while on a branch, only
> giving the safety to "git checkout" feels somewhat silly.

But isn't the --hard switch the safety valve here?  And lets not
forget that reflogs are enabled by default now so even a `reset
--hard` on a real branch isn't a total loss (its only a loss for
uncommitted files in the working directory).

But a detached HEAD has no reflog. Which means operations that
update it in a non-fastforward way would orphan work.  A subsequent
gc/prune/repack might destroy it, unless an existing ref contains
that previous commit.

> Which makes the "merge-base --check-ancestry" stuff I did last
> night pretty much unnecessary, but that's Ok.  It will find
> other uses.

Pity.  It looked like it was a good change and would be useful here
as a safety valve.  Though based on what you said above I would
think we'd actually want it in both checkout and reset (--soft and
--hard versions).

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:43                   ` Carl Worth
  2007-01-09 21:53                     ` J. Bruce Fields
@ 2007-01-09 23:44                     ` Shawn O. Pearce
  2007-01-10  0:26                       ` Jakub Narebski
  2007-01-10  9:08                     ` Andreas Ericsson
  2007-01-10  9:40                     ` Junio C Hamano
  3 siblings, 1 reply; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-09 23:44 UTC (permalink / raw)
  To: Carl Worth; +Cc: J. Bruce Fields, Junio C Hamano, Jeff King, git

Carl Worth <cworth@cworth.org> wrote:
> But, whatever, if allowing fragile commits is seen as important by
> those doing the work, who am I to complain about that? I'd just ask
> that the following not be made slow:
> 
> 	git checkout commit-from-beginning-of-time
> 	git checkout master
> 
> Thanks to the index, and the simplicity of what "git checkout" means,
> checkout has always been blisteringly fast. All the talk of doing
> reachability analysis scares me from a performance point of view,
> (particularly when the _interesting_ cases (to me) of checkouts to
> non-branches never need this anyway---since no commits will be made).

The safety valve I was proposing would be only the additional time of
running `git merge-base commit-from-begging-of-time master` to verify
the former is completely contained in the latter.  That's going to
be true, and is a relatively fast operation (roughly linear in time
with the length of the history).

However in this case:

  git checkout v1.5.0
  git checkout v1.2.0

would take slightly longer as we'd have to verify that the HEAD
from the first checkout is contained in an existing tag/ref.
Which it is.  Since its probably exactly equal to one of those
dereferenced tags this may just wind up being the cost of scanning
the .git/packed-refs file.  You do pack your refs, don't you?

In my mind that is a small price to pay for making sure the
commit currently in a detached HEAD doesn't get orphaned off
into never-never land.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 22:37                   ` Junio C Hamano
  2007-01-09 23:39                     ` Shawn O. Pearce
@ 2007-01-09 23:46                     ` Linus Torvalds
  2007-01-10  0:10                       ` Junio C Hamano
                                         ` (4 more replies)
  1 sibling, 5 replies; 68+ messages in thread
From: Linus Torvalds @ 2007-01-09 23:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: J. Bruce Fields, Jeff King, git



On Tue, 9 Jan 2007, Junio C Hamano wrote:
> 
> Being able to test merge or even make commits without being on a
> branch is vastly useful.

Yes. I think the detached head notion is really really important. I think 
it was a mistake to not allow it initially, but hey, there were various 
historical reasons, and the whole thing about how branches worked was a 
bit up in the air.

I would suggest a solution:

 - git checkout will refuse to switch AWAY from a detached head unless the 
   SHA1 of the detached head exactly matches some other branch.

Not any expensive "reachability" cheaks. Simple and straightforward: just 
say "no, I will not leave this branch-less HEAD behind, because it is not 
described by any other branch or tag".

So if you do

	git checkout v1.4.4

you'll be fine, because even though you got a detached HEAD that isn't 
attached to any branch, it still exists as a tag, so checking out 
something else is fine - you've not lost any state.

In contrast, if you actually start committing to that detached HEAD, you 
need to either

 - use some new flag ("git checkout --forget-old") to explicitly say that 
   you _want_ to leave this old naked branch behind

 - either tag the current point or make a real branch out of it (with 
   either "git tag <tagname>" or "git branch <branchname>" respectively) 
   and then you can check out some other tag/branch after that.

Doing "reachability analysis" is not only expensive, it's actually really 
wrong, because even if the current HEAD is _reachable_ from some other tag 
or branch, you're still going to drop that point in the development series 
unless it _exactly_ matchs it.

Hmm?

I'd love to see the detached HEAD series move into "master", but I do 
think we should make sure that people can't drop their work easily by 
mistake, and I think the above suggestion is both simple and workable.

Comments?

		Linus

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:46                     ` Linus Torvalds
@ 2007-01-10  0:10                       ` Junio C Hamano
  2007-01-10  0:18                         ` Shawn O. Pearce
  2007-01-10  0:51                       ` Carl Worth
                                         ` (3 subsequent siblings)
  4 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  0:10 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: J. Bruce Fields, Jeff King, git

Linus Torvalds <torvalds@osdl.org> writes:

> On Tue, 9 Jan 2007, Junio C Hamano wrote:
>> 
>> Being able to test merge or even make commits without being on a
>> branch is vastly useful.
>
> Yes. I think the detached head notion is really really important. I think 
> it was a mistake to not allow it initially, but hey, there were various 
> historical reasons, and the whole thing about how branches worked was a 
> bit up in the air.
>
> I would suggest a solution:
>
>  - git checkout will refuse to switch AWAY from a detached head unless the 
>    SHA1 of the detached head exactly matches some other branch.

... or an existing "ref^{commit}".

> I'd love to see the detached HEAD series move into "master", but I do 
> think we should make sure that people can't drop their work easily by 
> mistake, and I think the above suggestion is both simple and workable.
>
> Comments?

I agree with the "reachability is wrong -- you would lose the
point in the middle" reasoning.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  0:10                       ` Junio C Hamano
@ 2007-01-10  0:18                         ` Shawn O. Pearce
  2007-01-10  0:54                           ` Linus Torvalds
  0 siblings, 1 reply; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  0:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, J. Bruce Fields, Jeff King, git

Junio C Hamano <junkio@cox.net> wrote:
> Linus Torvalds <torvalds@osdl.org> writes:
> >  - git checkout will refuse to switch AWAY from a detached head unless the 
> >    SHA1 of the detached head exactly matches some other branch.
> 
> ... or an existing "ref^{commit}".

I think that was implied.  ;-)
 
> > I'd love to see the detached HEAD series move into "master", but I do 
> > think we should make sure that people can't drop their work easily by 
> > mistake, and I think the above suggestion is both simple and workable.
> >
> > Comments?
> 
> I agree with the "reachability is wrong -- you would lose the
> point in the middle" reasoning.

I have no problem with that.  Forget the reachability thing entirely.

My point about reset --hard/--soft probably also needing this check
still stands however.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:44                     ` Shawn O. Pearce
@ 2007-01-10  0:26                       ` Jakub Narebski
  2007-01-10  0:34                         ` Shawn O. Pearce
  0 siblings, 1 reply; 68+ messages in thread
From: Jakub Narebski @ 2007-01-10  0:26 UTC (permalink / raw)
  To: git

Shawn O. Pearce wrote:

> In my mind that is a small price to pay for making sure the
> commit currently in a detached HEAD doesn't get orphaned off
> into never-never land.

By the way, would detached HEAD be reflogged, and if it would
(and certainly it would be nice to have, because protection or
not sh*t happens) how it would be implemented?
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  0:26                       ` Jakub Narebski
@ 2007-01-10  0:34                         ` Shawn O. Pearce
  2007-01-10  1:03                           ` J. Bruce Fields
  2007-01-10  1:15                           ` Nicolas Pitre
  0 siblings, 2 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  0:34 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

Jakub Narebski <jnareb@gmail.com> wrote:
> Shawn O. Pearce wrote:
> 
> > In my mind that is a small price to pay for making sure the
> > commit currently in a detached HEAD doesn't get orphaned off
> > into never-never land.
> 
> By the way, would detached HEAD be reflogged, and if it would
> (and certainly it would be nice to have, because protection or
> not sh*t happens) how it would be implemented?

Ohhhhh.  It should reflog if .git/logs/HEAD exists, so long as
changes to HEAD are done via update-ref and not just by echo (as
one of Junio's versions of the feature had done).

Unfortunately .git/logs/HEAD wouldn't be created by default as its
not under refs/heads or refs/remotes.  Though it could be made to be
on by default, in which case it would only log changes while HEAD
is detached.  If HEAD is attached to a branch then .git/logs/HEAD
wouldn't be appended to (or even created), while the branch's own
log is still appended to.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:46                     ` Linus Torvalds
  2007-01-10  0:10                       ` Junio C Hamano
@ 2007-01-10  0:51                       ` Carl Worth
  2007-01-10  8:02                       ` Junio C Hamano
                                         ` (2 subsequent siblings)
  4 siblings, 0 replies; 68+ messages in thread
From: Carl Worth @ 2007-01-10  0:51 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, J. Bruce Fields, Jeff King, git

[-- Attachment #1: Type: text/plain, Size: 1801 bytes --]

On Tue, 9 Jan 2007 15:46:32 -0800 (PST), Linus Torvalds wrote:
>  - git checkout will refuse to switch AWAY from a detached head unless the
>    SHA1 of the detached head exactly matches some other branch.

That's a nice cheap check.

But I've also been liking the idea of using this "detached head" stuff
for git-bisect, (instead of making it carry around its own temporary
branch). One long-standing user-interface bug with git-bisect is that
often the user doesn't know a priori what the last-known-good state is
to initially mark with "git bisect good". So I've long wanted a good
clean way to explore fairly arbitrarily in order to get git-bisect
jump started.

When I first started using git a year ago, what was suggested to me
for this, (and what I've used ever since), is:

	git checkout -b tmp some-guess-at-a-good-commit
	# check it
	git reset --hard next-guess-at-a-good-commit

Obviously, that works but fails the "good clean" test for me. Half
the time it fails for me and I have to "git branch -D tmp" first. Then
there's the fact that I want very new users to learn git-bisect---I
want random users that have hit bugs in my software to bisect those
bugs for me---and many of these users will have never seen git
before. I don't think it's kind to start their education with "git
reset --hard". I'd like to instead teach them something as simple as:

	git checkout some-guess-at-a-good-commit
	# check it
	git checkout next-guess-at-a-good-commit

I wouldn't want these uses to trigger warnings just because the user
is checking out arbitrary revisions from the logs rather than using
tags and branches.

But, yes, as soon as the user actually _commits_ in the detached
state, then a check for "HEAD == some branch" should be just fine for
checking a checkout to somewhere else.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  0:18                         ` Shawn O. Pearce
@ 2007-01-10  0:54                           ` Linus Torvalds
  0 siblings, 0 replies; 68+ messages in thread
From: Linus Torvalds @ 2007-01-10  0:54 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Junio C Hamano, J. Bruce Fields, Jeff King, git



On Tue, 9 Jan 2007, Shawn O. Pearce wrote:
> 
> My point about reset --hard/--soft probably also needing this check
> still stands however.

Well, I disagree, if only because the whole _point_ of "git reset" is to 
leave some point behind. I use it all the time (well, often enough) as a 
"undo" operation, and it's fundamentally different than "git checkout" at 
least to my worldview.

When you do "git reset" you _expect_ state to be reset/dropped. But when 
just switching between branches, you don't.

(I realize that "git checkout filename/goes/here" has kind of mixed up 
"git reset" and "git checkout". The "git checkout filename" syntax 
basically resets the filename, and that confuses things a bit. So in the 
above, I really do talk about just "checking out a _commit_" and do a 
state switch, not a "check out a filename" and overwrite the old contents 
of that file).

		Linus

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  0:34                         ` Shawn O. Pearce
@ 2007-01-10  1:03                           ` J. Bruce Fields
  2007-01-10  1:07                             ` Shawn O. Pearce
  2007-01-10  1:15                           ` Nicolas Pitre
  1 sibling, 1 reply; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-10  1:03 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Jakub Narebski, git

On Tue, Jan 09, 2007 at 07:34:33PM -0500, Shawn O. Pearce wrote:
> Unfortunately .git/logs/HEAD wouldn't be created by default as its
> not under refs/heads or refs/remotes.  Though it could be made to be
> on by default, in which case it would only log changes while HEAD
> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
> wouldn't be appended to (or even created), while the branch's own
> log is still appended to.

That would also provide all the needed "safety valve" on git checkout,
wouldn't it?  Since you could always recover from

	git checkout v1.4.0
	git commit -m -a 'some changes'
	git checkout 41.2.0

by looking back through the reflog for HEAD.

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:03                           ` J. Bruce Fields
@ 2007-01-10  1:07                             ` Shawn O. Pearce
  0 siblings, 0 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  1:07 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Jakub Narebski, git

"J. Bruce Fields" <bfields@fieldses.org> wrote:
> On Tue, Jan 09, 2007 at 07:34:33PM -0500, Shawn O. Pearce wrote:
> > Unfortunately .git/logs/HEAD wouldn't be created by default as its
> > not under refs/heads or refs/remotes.  Though it could be made to be
> > on by default, in which case it would only log changes while HEAD
> > is detached.  If HEAD is attached to a branch then .git/logs/HEAD
> > wouldn't be appended to (or even created), while the branch's own
> > log is still appended to.
> 
> That would also provide all the needed "safety valve" on git checkout,
> wouldn't it?  Since you could always recover from
> 
> 	git checkout v1.4.0
> 	git commit -m -a 'some changes'
> 	git checkout 41.2.0
> 
> by looking back through the reflog for HEAD.

Yes.  Then that removes my desire for a safety check in reset,
(which Linus doesn't want) thereby making both of us happy.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  0:34                         ` Shawn O. Pearce
  2007-01-10  1:03                           ` J. Bruce Fields
@ 2007-01-10  1:15                           ` Nicolas Pitre
  2007-01-10  1:24                             ` Junio C Hamano
  2007-01-10  1:37                             ` Jakub Narebski
  1 sibling, 2 replies; 68+ messages in thread
From: Nicolas Pitre @ 2007-01-10  1:15 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Jakub Narebski, git

On Tue, 9 Jan 2007, Shawn O. Pearce wrote:

> Jakub Narebski <jnareb@gmail.com> wrote:
> > Shawn O. Pearce wrote:
> > 
> > > In my mind that is a small price to pay for making sure the
> > > commit currently in a detached HEAD doesn't get orphaned off
> > > into never-never land.
> > 
> > By the way, would detached HEAD be reflogged, and if it would
> > (and certainly it would be nice to have, because protection or
> > not sh*t happens) how it would be implemented?
> 
> Ohhhhh.  It should reflog if .git/logs/HEAD exists, so long as
> changes to HEAD are done via update-ref and not just by echo (as
> one of Junio's versions of the feature had done).
> 
> Unfortunately .git/logs/HEAD wouldn't be created by default as its
> not under refs/heads or refs/remotes.  Though it could be made to be
> on by default, in which case it would only log changes while HEAD
> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
> wouldn't be appended to (or even created), while the branch's own
> log is still appended to.

Is this worth the trouble and complexity?  After all detached heads are 
not meant to be used for serious development.


Nicolas

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:15                           ` Nicolas Pitre
@ 2007-01-10  1:24                             ` Junio C Hamano
  2007-01-10  1:40                               ` Shawn O. Pearce
  2007-01-10  1:37                             ` Jakub Narebski
  1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  1:24 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Shawn O. Pearce, Jakub Narebski, git

Nicolas Pitre <nico@cam.org> writes:

>> Unfortunately .git/logs/HEAD wouldn't be created by default as its
>> not under refs/heads or refs/remotes.  Though it could be made to be
>> on by default, in which case it would only log changes while HEAD
>> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
>> wouldn't be appended to (or even created), while the branch's own
>> log is still appended to.
>
> Is this worth the trouble and complexity?  After all detached heads are 
> not meant to be used for serious development.

I agree.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:15                           ` Nicolas Pitre
  2007-01-10  1:24                             ` Junio C Hamano
@ 2007-01-10  1:37                             ` Jakub Narebski
  1 sibling, 0 replies; 68+ messages in thread
From: Jakub Narebski @ 2007-01-10  1:37 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Shawn O. Pearce, git

Nicolas Pitre wrote:
> On Tue, 9 Jan 2007, Shawn O. Pearce wrote:
> 
>> Jakub Narebski <jnareb@gmail.com> wrote:
>>> Shawn O. Pearce wrote:
>>> 
>>>> In my mind that is a small price to pay for making sure the
>>>> commit currently in a detached HEAD doesn't get orphaned off
>>>> into never-never land.
>>> 
>>> By the way, would detached HEAD be reflogged, and if it would
>>> (and certainly it would be nice to have, because protection or
>>> not sh*t happens) how it would be implemented?
>> 
>> Ohhhhh.  It should reflog if .git/logs/HEAD exists, so long as
>> changes to HEAD are done via update-ref and not just by echo (as
>> one of Junio's versions of the feature had done).
>> 
>> Unfortunately .git/logs/HEAD wouldn't be created by default as its
>> not under refs/heads or refs/remotes.  Though it could be made to be
>> on by default, in which case it would only log changes while HEAD
>> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
>> wouldn't be appended to (or even created), while the branch's own
>> log is still appended to.
> 
> Is this worth the trouble and complexity?  After all detached heads
> are not meant to be used for serious development.

I think reflogging detached HEAD is easier than adding safety checks
either on commit (no commits on top of detached HEAD), or on checkouts
and stuff (try not to loose unless forced chain of commits built on top
of detached HEAD).
-- 
Jakub Narebski
Poland

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:24                             ` Junio C Hamano
@ 2007-01-10  1:40                               ` Shawn O. Pearce
  2007-01-10  1:54                                 ` Nicolas Pitre
  0 siblings, 1 reply; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  1:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Nicolas Pitre, Jakub Narebski, git

Junio C Hamano <junkio@cox.net> wrote:
> Nicolas Pitre <nico@cam.org> writes:
> 
> >> Unfortunately .git/logs/HEAD wouldn't be created by default as its
> >> not under refs/heads or refs/remotes.  Though it could be made to be
> >> on by default, in which case it would only log changes while HEAD
> >> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
> >> wouldn't be appended to (or even created), while the branch's own
> >> log is still appended to.
> >
> > Is this worth the trouble and complexity?  After all detached heads are 
> > not meant to be used for serious development.
> 
> I agree.

  git checkout v1.4.0
  # dang, need some local fix
  git commit -m tmpfix -a
  git reset --hard v1.2.0
  git reset --hard v1.3.0
  # dang, need that local again fix - where is it?

It ain't in ORIG_HEAD.  Its now only findable by
fsck-objects/lost-found.  But if you reflog a detached
HEAD its there as HEAD@{2}.

Maybe its not really worth it.  But it almost seems like it would
come free if we always use update-ref like we're supposed to...

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:40                               ` Shawn O. Pearce
@ 2007-01-10  1:54                                 ` Nicolas Pitre
  2007-01-10  2:28                                   ` Shawn O. Pearce
  0 siblings, 1 reply; 68+ messages in thread
From: Nicolas Pitre @ 2007-01-10  1:54 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Junio C Hamano, Jakub Narebski, git

On Tue, 9 Jan 2007, Shawn O. Pearce wrote:

> Junio C Hamano <junkio@cox.net> wrote:
> > Nicolas Pitre <nico@cam.org> writes:
> > 
> > >> Unfortunately .git/logs/HEAD wouldn't be created by default as its
> > >> not under refs/heads or refs/remotes.  Though it could be made to be
> > >> on by default, in which case it would only log changes while HEAD
> > >> is detached.  If HEAD is attached to a branch then .git/logs/HEAD
> > >> wouldn't be appended to (or even created), while the branch's own
> > >> log is still appended to.
> > >
> > > Is this worth the trouble and complexity?  After all detached heads are 
> > > not meant to be used for serious development.
> > 
> > I agree.
> 
>   git checkout v1.4.0
>   # dang, need some local fix
>   git commit -m tmpfix -a
>   git reset --hard v1.2.0
>   git reset --hard v1.3.0
>   # dang, need that local again fix - where is it?

    cd /
    ls
    # wow lots of files
    rm -rf .
    # dang dunk down

So just don't use git-reset but create a branch to preserve that local 
change instead.

> It ain't in ORIG_HEAD.  Its now only findable by
> fsck-objects/lost-found.

Which is good enough in that circumstance IMHO.  We cannot always try to 
prevent people from shooting in their foot if they really want to.

> But if you reflog a detached
> HEAD its there as HEAD@{2}.

But when your head is not detached anymore then HEAD@{2} changes 
meaning and that is rather not good.


Nicolas

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  1:54                                 ` Nicolas Pitre
@ 2007-01-10  2:28                                   ` Shawn O. Pearce
  0 siblings, 0 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  2:28 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Junio C Hamano, Jakub Narebski, git

Nicolas Pitre <nico@cam.org> wrote:
> On Tue, 9 Jan 2007, Shawn O. Pearce wrote:
> > But if you reflog a detached
> > HEAD its there as HEAD@{2}.
> 
> But when your head is not detached anymore then HEAD@{2} changes 
> meaning and that is rather not good.

Ah, yes, apparently my own head is detached and not clearly thinking.
Thanks.  That UI is not so good.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:46                     ` Linus Torvalds
  2007-01-10  0:10                       ` Junio C Hamano
  2007-01-10  0:51                       ` Carl Worth
@ 2007-01-10  8:02                       ` Junio C Hamano
  2007-01-10  9:04                       ` Andy Parkins
  2007-01-10 14:04                       ` Jeff King
  4 siblings, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  8:02 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Linus Torvalds <torvalds@osdl.org> writes:

> I'd love to see the detached HEAD series move into "master", but I do 
> think we should make sure that people can't drop their work easily by 
> mistake, and I think the above suggestion is both simple and workable.

I've done this, also added one fix and merged the topic to
"next".  I am hoping I can move this to "master" by the weekend.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:46                     ` Linus Torvalds
                                         ` (2 preceding siblings ...)
  2007-01-10  8:02                       ` Junio C Hamano
@ 2007-01-10  9:04                       ` Andy Parkins
  2007-01-10  9:05                         ` Shawn O. Pearce
  2007-01-10  9:33                         ` Junio C Hamano
  2007-01-10 14:04                       ` Jeff King
  4 siblings, 2 replies; 68+ messages in thread
From: Andy Parkins @ 2007-01-10  9:04 UTC (permalink / raw)
  To: git

On Tuesday 2007 January 09 23:46, Linus Torvalds wrote:

> I would suggest a solution:
>
>  - git checkout will refuse to switch AWAY from a detached head unless the
>    SHA1 of the detached head exactly matches some other branch.

If the detached HEAD matches another branch what did we need a detached HEAD 
for in the first place?

Seems that this check will in practice always be true.  A detached HEAD by 
definition doesn't match some other branch.

Have I misunderstood?  Perhaps you meant the detached HEAD is /on/ some other 
branch?



Andy

-- 
Dr Andy Parkins, M Eng (hons), MIEE
andyparkins@gmail.com

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  9:04                       ` Andy Parkins
@ 2007-01-10  9:05                         ` Shawn O. Pearce
  2007-01-10  9:33                         ` Junio C Hamano
  1 sibling, 0 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10  9:05 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git

Andy Parkins <andyparkins@gmail.com> wrote:
> On Tuesday 2007 January 09 23:46, Linus Torvalds wrote:
> 
> > I would suggest a solution:
> >
> >  - git checkout will refuse to switch AWAY from a detached head unless the
> >    SHA1 of the detached head exactly matches some other branch.
> 
> If the detached HEAD matches another branch what did we need a detached HEAD 
> for in the first place?

Tags.  Previously you could not checkout a tag without first making
a branch from it.  Now you can.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:43                   ` Carl Worth
  2007-01-09 21:53                     ` J. Bruce Fields
  2007-01-09 23:44                     ` Shawn O. Pearce
@ 2007-01-10  9:08                     ` Andreas Ericsson
  2007-01-10  9:46                       ` Junio C Hamano
  2007-01-10  9:40                     ` Junio C Hamano
  3 siblings, 1 reply; 68+ messages in thread
From: Andreas Ericsson @ 2007-01-10  9:08 UTC (permalink / raw)
  To: Carl Worth; +Cc: J. Bruce Fields, Junio C Hamano, Jeff King, git

Carl Worth wrote:
> 
> Frankly, I don't understand why so much effort is being put toward
> allowing these "fragile commits" to be made in the first place. Why
> not require users to name the branch before creating any commits, just
> as has always been the case?
> 

Agreed. Possibly, we could have commit (or commit-tree) issue a big fat 
warning along the lines of:

*** WARNING ***
You are about to create a commit on a detached HEAD.
It is recommended that you run "git branch <name>" to create a branch to 
commit to first. If you don't, you might lose this commit further on.
*** WARNING ***

which could be suppressed by a "--silently-ignore-detached-head" in case 
scripts (securely) use this behaviour. Since committing on detached 
heads really should be a very rare case I don't think many people will 
find this terribly annoying.

> To me, the only real advantage to the new "detached head" stuff is
> simply making it easier to checkout previous state without having to
> name a new branch precisely _because_ the user has not intent to
> commit anything. If the user is going to commit something, then the
> user should be able to come up with a name for the branch.
> 

Indeed and as I've said before, *all* developers have "silly-names" they 
use for temporary stuff (foo, bar, frotz, nitfol, blaj, fnurg, sdf, ...) 
so it's not like we'll put a heavy burden on peoples imagination.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  9:04                       ` Andy Parkins
  2007-01-10  9:05                         ` Shawn O. Pearce
@ 2007-01-10  9:33                         ` Junio C Hamano
  2007-01-10 10:10                           ` Andy Parkins
  1 sibling, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  9:33 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git

Andy Parkins <andyparkins@gmail.com> writes:

> On Tuesday 2007 January 09 23:46, Linus Torvalds wrote:
>
>> I would suggest a solution:
>>
>>  - git checkout will refuse to switch AWAY from a detached head unless the
>>    SHA1 of the detached head exactly matches some other branch.
>
> If the detached HEAD matches another branch what did we need a detached HEAD 
> for in the first place?
>
> Seems that this check will in practice always be true.  A detached HEAD by 
> definition doesn't match some other branch.

You are forgetting this:

	git checkout v1.0.0

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 21:43                   ` Carl Worth
                                       ` (2 preceding siblings ...)
  2007-01-10  9:08                     ` Andreas Ericsson
@ 2007-01-10  9:40                     ` Junio C Hamano
  3 siblings, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  9:40 UTC (permalink / raw)
  To: Carl Worth; +Cc: git

Carl Worth <cworth@cworth.org> writes:

> Frankly, I don't understand why so much effort is being put toward
> allowing these "fragile commits" to be made in the first place. Why
> not require users to name the branch before creating any commits, just
> as has always been the case?

Then we would not be talking about detached HEAD at all.  Why
not require users to name the branch if they want to check out
what they should not be able to in the first place?

Convenience.

Some features of git are about being convenient by allowing you
to defer the decision.  You can start mucking with the working
tree files without knowing where it leads to and then from that
point with the dirty working tree state decide to fork what you
have started using "checkout -b newbranch".  Even though you may
have many dirty files in the working tree, you can selectively
update index (especially with the patch subcommand of the
interactive git-add) to prepare for commit -- you do not choose
what to edit, but you defer the decision of what to include in
the commit.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  9:08                     ` Andreas Ericsson
@ 2007-01-10  9:46                       ` Junio C Hamano
  2007-01-10 16:30                         ` Daniel Barkalow
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10  9:46 UTC (permalink / raw)
  To: Andreas Ericsson; +Cc: J. Bruce Fields, Jeff King, Carl Worth, git

Andreas Ericsson <ae@op5.se> writes:

> ... Since committing on
> detached heads really should be a very rare case I don't think many
> people will find this terribly annoying.

Quite the contrary, I would imagine it would be quite natural to
do throw-away commits and merges on detached head while
bisecting the history (e.g. commit small fixup to make it
compile and then mark the result for bisection to hunt for real
bugs that are hidden by silly compilation problems).  

The check suggested by Linus would be safe enough for people to
whom it is "very rare" for their workflow to commitg on detached
HEAD anyway, so you should not burden "git commit" with such an
annoying warning messages.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  9:33                         ` Junio C Hamano
@ 2007-01-10 10:10                           ` Andy Parkins
  2007-01-10 10:25                             ` Shawn O. Pearce
  2007-01-10 16:18                             ` Junio C Hamano
  0 siblings, 2 replies; 68+ messages in thread
From: Andy Parkins @ 2007-01-10 10:10 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

On Wednesday 2007 January 10 09:33, Junio C Hamano wrote:

> > If the detached HEAD matches another branch what did we need a detached
> > HEAD for in the first place?
> >
> > Seems that this check will in practice always be true.  A detached HEAD
> > by definition doesn't match some other branch.
>
> You are forgetting this:
>
> 	git checkout v1.0.0

No I'm not.  Linus's suggested check is "git checkout will refuse to switch 
AWAY from a detached head unless the SHA1 of the detached head exactly 
matches some other branch."

My question is what use is that?  In exactly the situation you describe HEAD 
doesn't match a branch.

  git checkout v1.0.0

HEAD after that doesn't match any branch so the next "git checkout" will find 
that HEAD doesn't match any branch and will refuse to switch away.  Why?  A 
checkout in this case isn't dangerous at all.

Of course I could still be misunderstanding.  If Linus meant "refuse to switch 
AWAY from a detached HEAD unless the hash of the detached head exactly 
matches some other ref", I would be less confused.


Andy
-- 
Dr Andy Parkins, M Eng (hons), MIEE
andyparkins@gmail.com

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10 10:10                           ` Andy Parkins
@ 2007-01-10 10:25                             ` Shawn O. Pearce
  2007-01-10 16:18                             ` Junio C Hamano
  1 sibling, 0 replies; 68+ messages in thread
From: Shawn O. Pearce @ 2007-01-10 10:25 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git, Junio C Hamano

Andy Parkins <andyparkins@gmail.com> wrote:
> Of course I could still be misunderstanding.  If Linus meant "refuse to switch 
> AWAY from a detached HEAD unless the hash of the detached head exactly 
> matches some other ref", I would be less confused.

I believe that's what Linus meant.  As otherwise you are right,
it doesn't make much sense.  :-)

-- 
Shawn.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-09 23:46                     ` Linus Torvalds
                                         ` (3 preceding siblings ...)
  2007-01-10  9:04                       ` Andy Parkins
@ 2007-01-10 14:04                       ` Jeff King
  2007-01-11  0:34                         ` Junio C Hamano
  4 siblings, 1 reply; 68+ messages in thread
From: Jeff King @ 2007-01-10 14:04 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, J. Bruce Fields, git

On Tue, Jan 09, 2007 at 03:46:32PM -0800, Linus Torvalds wrote:

> I would suggest a solution:
> 
>  - git checkout will refuse to switch AWAY from a detached head unless the 
>    SHA1 of the detached head exactly matches some other branch.

What about

  git checkout HEAD~20

I agree that checking out tags will be more common, but it feels like we
are discouraging this usage by presenting spurious warning messages.

-Peff

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10 10:10                           ` Andy Parkins
  2007-01-10 10:25                             ` Shawn O. Pearce
@ 2007-01-10 16:18                             ` Junio C Hamano
  1 sibling, 0 replies; 68+ messages in thread
From: Junio C Hamano @ 2007-01-10 16:18 UTC (permalink / raw)
  To: Andy Parkins; +Cc: git

Andy Parkins <andyparkins@gmail.com> writes:

> No I'm not.  Linus's suggested check is "git checkout will refuse to switch 
> AWAY from a detached head unless the SHA1 of the detached head exactly 
> matches some other branch."
>
> My question is what use is that?  In exactly the situation you describe HEAD 
> doesn't match a branch.
>
>   git checkout v1.0.0

You are taking it too literally.  Read what Linus wrote again.

    So if you do

            git checkout v1.4.4

    you'll be fine, because even though you got a detached HEAD that isn't 
    attached to any branch, it still exists as a tag, so checking out 
    something else is fine - you've not lost any state.

The version in "next" does that, in a quite straightforward way:

	git show-ref -d -s | grep "$old" || { barf }

which should be fairly fast in a repository with packed-pruned
refs.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10  9:46                       ` Junio C Hamano
@ 2007-01-10 16:30                         ` Daniel Barkalow
  2007-01-11  9:45                           ` Andreas Ericsson
  0 siblings, 1 reply; 68+ messages in thread
From: Daniel Barkalow @ 2007-01-10 16:30 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Andreas Ericsson, J. Bruce Fields, Jeff King, Carl Worth, git

On Wed, 10 Jan 2007, Junio C Hamano wrote:

> Andreas Ericsson <ae@op5.se> writes:
> 
> > ... Since committing on
> > detached heads really should be a very rare case I don't think many
> > people will find this terribly annoying.
> 
> Quite the contrary, I would imagine it would be quite natural to
> do throw-away commits and merges on detached head while
> bisecting the history (e.g. commit small fixup to make it
> compile and then mark the result for bisection to hunt for real
> bugs that are hidden by silly compilation problems).  

I don't think this would actually work. If you commit your build fix, and 
then mark the result as bad, won't bisect skew its choices due to 
suspecting that your build fix is the real bug?

I'd think that, if you make changes while bisecting, you probably want to 
leave those changes uncommitted, and merge or discard them when testing 
other commits.

If anything, I'd think you'd want a rather different sort of commit 
mechanism than the usual commit, which says, "whenever you consider commit 
{sha1-from-real-history}, use {tree-with-local-changes} instead of 
{tree-in-real-commit}." Or, more generally, "in order to get the trees 
I want to actually use, this patch (git diff HEAD) needs to be applied to 
every commit in some portion of the history including, at least, 
get_sha1(HEAD)".

I'm not seeing any actual benefit to causing the history to contain a 
dead-end fork off of an antique commit, and then throwing this away. And 
committing your change so that it won't get lost, with the intention of 
losing it in a little while, doesn't seem to make any sense, either.

(Of course, it also makes sense to do merges, but again, you probably want 
to create and temporarily use the working tree resulting from the merge, 
not create the commit.)

I think that the workflow that uses regular commits with a detached HEAD 
is this: do a series of commits representing real work on top of a remote 
branch or a tag, and decide later (once you've tested the results for 
worthiness) whether to turn this into a topic branch or throw it away.

But I don't think this is a good match for detached HEAD, because you may 
want to do exactly the same thing, but start with a regular local head. I 
think the right thing to do is something like "git checkout --anon", which 
puts you on a new branch with no name, which will evaporate if you leave 
it (as per "git branch -d"; you need to force it if it isn't fully 
merged).

So I think the feature which lets you make commits without being on a 
branch from refs/heads is actually a different feature from "detached 
HEAD", which only shares the aspect that "git branch" has no line with a 
"*", because there is no name for what HEAD points to.

(I'd implement "anonymous branch" by putting you on refs/heads/.anon, and 
adding rules for this situation to for_each_ref and update_ref; but that's 
an implementation detail, and shouldn't affect the intended semantics of 
the feature.)

	-Daniel
*This .sig left intentionally blank*

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10 14:04                       ` Jeff King
@ 2007-01-11  0:34                         ` Junio C Hamano
  2007-01-11  4:31                           ` J. Bruce Fields
  0 siblings, 1 reply; 68+ messages in thread
From: Junio C Hamano @ 2007-01-11  0:34 UTC (permalink / raw)
  To: Jeff King; +Cc: Linus Torvalds, J. Bruce Fields, git

Jeff King <peff@peff.net> writes:

> On Tue, Jan 09, 2007 at 03:46:32PM -0800, Linus Torvalds wrote:
>
>> I would suggest a solution:
>> 
>>  - git checkout will refuse to switch AWAY from a detached head unless the 
>>    SHA1 of the detached head exactly matches some other branch.
>
> What about
>
>   git checkout HEAD~20
>
> I agree that checking out tags will be more common, but it feels like we
> are discouraging this usage by presenting spurious warning messages.

Once the user knows what HEAD~20 means, I think it is safe to
assume that the user knows what the branches are.

"git checkout master" will barf and suggests the user possible
common exits; "checkout -f" if there is nothing of value,
"checkout -b <branch>" or if they want to build on the current
state.

And once the user who knows what the branches are sees such, and
especially with the help from $PS1 hack of bash-completion in
contrib/ section, the user will learn to do "checkout -f" after
wandering around for sightseeing on a detached HEAD, and at that
point the annoying error message will not be even seen.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-11  0:34                         ` Junio C Hamano
@ 2007-01-11  4:31                           ` J. Bruce Fields
  0 siblings, 0 replies; 68+ messages in thread
From: J. Bruce Fields @ 2007-01-11  4:31 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, Linus Torvalds, git

On Wed, Jan 10, 2007 at 04:34:57PM -0800, Junio C Hamano wrote:
> Jeff King <peff@peff.net> writes:
> 
> > On Tue, Jan 09, 2007 at 03:46:32PM -0800, Linus Torvalds wrote:
> >
> >> I would suggest a solution:
> >> 
> >>  - git checkout will refuse to switch AWAY from a detached head unless the 
> >>    SHA1 of the detached head exactly matches some other branch.
> >
> > What about
> >
> >   git checkout HEAD~20
> >
> > I agree that checking out tags will be more common, but it feels like we
> > are discouraging this usage by presenting spurious warning messages.
> 
> Once the user knows what HEAD~20 means, I think it is safe to
> assume that the user knows what the branches are.

I'm interested of course in making life easy for project admins when
they need to tell testers how to get code to test out of git.  It'll be
nice to able to say:

	"Install git, then run
	git clone git://ourproject.com/ourproject.git
	cd ourproject
	git checkout <version you want>
	"

Instead of having to say

	"Install git, then run
	git clone git://ourproject.com/ourproject.git
	cd ourproject
	git checkout -b FOO <version you want>

	Then if you later need to check out another version, run
	git reset --hard <other version>
	"

I suppose <version you want> will typically be either some tagged
release or the latest head.  But it's not that farfetched to imagine
asking someone to test version 01997b4....

> "git checkout master" will barf and suggests the user possible
> common exits; "checkout -f" if there is nothing of value,
> "checkout -b <branch>" or if they want to build on the current
> state.

That should make it easy enough, though, I guess.

--b.

^ permalink raw reply	[flat|nested] 68+ messages in thread

* Re: [PATCH] Detached HEAD (experimental)
  2007-01-10 16:30                         ` Daniel Barkalow
@ 2007-01-11  9:45                           ` Andreas Ericsson
  0 siblings, 0 replies; 68+ messages in thread
From: Andreas Ericsson @ 2007-01-11  9:45 UTC (permalink / raw)
  To: Daniel Barkalow
  Cc: Junio C Hamano, J. Bruce Fields, Jeff King, Carl Worth, git

Daniel Barkalow wrote:
> On Wed, 10 Jan 2007, Junio C Hamano wrote:
> 
>> Andreas Ericsson <ae@op5.se> writes:
>>
>>> ... Since committing on
>>> detached heads really should be a very rare case I don't think many
>>> people will find this terribly annoying.
>> Quite the contrary, I would imagine it would be quite natural to
>> do throw-away commits and merges on detached head while
>> bisecting the history (e.g. commit small fixup to make it
>> compile and then mark the result for bisection to hunt for real
>> bugs that are hidden by silly compilation problems).  
> 
> I don't think this would actually work. If you commit your build fix, and 
> then mark the result as bad, won't bisect skew its choices due to 
> suspecting that your build fix is the real bug?
> 
> I'd think that, if you make changes while bisecting, you probably want to 
> leave those changes uncommitted, and merge or discard them when testing 
> other commits.
> 
> If anything, I'd think you'd want a rather different sort of commit 
> mechanism than the usual commit, which says, "whenever you consider commit 
> {sha1-from-real-history}, use {tree-with-local-changes} instead of 
> {tree-in-real-commit}." Or, more generally, "in order to get the trees 
> I want to actually use, this patch (git diff HEAD) needs to be applied to 
> every commit in some portion of the history including, at least, 
> get_sha1(HEAD)".
> 
> I'm not seeing any actual benefit to causing the history to contain a 
> dead-end fork off of an antique commit, and then throwing this away. And 
> committing your change so that it won't get lost, with the intention of 
> losing it in a little while, doesn't seem to make any sense, either.
> 

Same here. I'd imagine temporary build-fixes to live as a patch-file 
generated by

	git diff > build-fixes.diff

after having hacked on the tree. There's no sane way of inserting 
commits into the middle of the DAG, so committing on something that 
isn't a branch with the intention of losing it is just plain weird.


> (Of course, it also makes sense to do merges, but again, you probably want 
> to create and temporarily use the working tree resulting from the merge, 
> not create the commit.)
> 

Yes. I'd imagine "git merge --no-commit" could be used for this, to 
merge things only in the working directory.


> I think that the workflow that uses regular commits with a detached HEAD 
> is this: do a series of commits representing real work on top of a remote 
> branch or a tag, and decide later (once you've tested the results for 
> worthiness) whether to turn this into a topic branch or throw it away.
> 

Perhaps, but this is also a bit weird, as you would normally hack things 
up to fit on top of some already existing branch, so then you'd detach 
the head but point it to something that already has a branch-name 
associated with it.

Otoh, I could imagine this would be sort of nifty for applying bugfixes 
on top of old tags, so perhaps it's not so weird after all. Then you'd 
probably want to create a new tag before releasing the bugfixed version, 
so Linus suggestion makes sense in this case (assuming it doesn't fsck 
up the bisect case, ofc).


> But I don't think this is a good match for detached HEAD, because you may 
> want to do exactly the same thing, but start with a regular local head. I 
> think the right thing to do is something like "git checkout --anon", which 
> puts you on a new branch with no name, which will evaporate if you leave 
> it (as per "git branch -d"; you need to force it if it isn't fully 
> merged).
> 


Yes. I'd imagine "git merge --no-commit" could be used for this, to 
merge things only in the working directory. We could easily create a 
hack for this by doing a "git reset --mixed HEAD^1" after the merge is 
complete.

> So I think the feature which lets you make commits without being on a 
> branch from refs/heads is actually a different feature from "detached 
> HEAD", which only shares the aspect that "git branch" has no line with a 
> "*", because there is no name for what HEAD points to.
> 


Agreed. They really are two completely different things. I see no harm 
in splitting them up codewise. Bisect could start working without its 
protected branch straight away, but commits (and merges) to detached 
heads wouldn't work at all. Then we can see what use people put this to 
and what walls they run into and make the feature accordingly.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply	[flat|nested] 68+ messages in thread

end of thread, other threads:[~2007-01-11  9:45 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-01-02  7:45 [PATCH] Detached HEAD (experimental) Junio C Hamano
2007-01-02 19:59 ` Edgar Toernig
2007-01-02 21:56 ` Carl Worth
2007-01-02 22:18   ` Jakub Narebski
2007-01-03  0:34     ` Carl Worth
2007-01-06 18:58       ` J. Bruce Fields
2007-01-06 20:48         ` Alan Chandler
2007-01-06 22:52           ` J. Bruce Fields
2007-01-02 22:44   ` Junio C Hamano
2007-01-02 23:34     ` Carl Worth
2007-01-03  2:45       ` Junio C Hamano
2007-01-08 11:19       ` Junio C Hamano
2007-01-08 13:17         ` Jeff King
2007-01-09  0:19           ` Junio C Hamano
2007-01-09  0:43             ` Carl Worth
2007-01-09  1:05               ` Junio C Hamano
2007-01-09  1:15                 ` Carl Worth
2007-01-09  3:26                   ` Shawn O. Pearce
2007-01-09  7:07                     ` Junio C Hamano
2007-01-09 10:41                       ` [PATCH 0/6] Expose in_merge_bases() via merge-base Junio C Hamano
2007-01-09  8:12                   ` [PATCH] Detached HEAD (experimental) Luben Tuikov
2007-01-09 14:21             ` Jeff King
2007-01-09 21:20               ` Junio C Hamano
2007-01-09 21:31                 ` J. Bruce Fields
2007-01-09 21:43                   ` Carl Worth
2007-01-09 21:53                     ` J. Bruce Fields
2007-01-09 23:44                     ` Shawn O. Pearce
2007-01-10  0:26                       ` Jakub Narebski
2007-01-10  0:34                         ` Shawn O. Pearce
2007-01-10  1:03                           ` J. Bruce Fields
2007-01-10  1:07                             ` Shawn O. Pearce
2007-01-10  1:15                           ` Nicolas Pitre
2007-01-10  1:24                             ` Junio C Hamano
2007-01-10  1:40                               ` Shawn O. Pearce
2007-01-10  1:54                                 ` Nicolas Pitre
2007-01-10  2:28                                   ` Shawn O. Pearce
2007-01-10  1:37                             ` Jakub Narebski
2007-01-10  9:08                     ` Andreas Ericsson
2007-01-10  9:46                       ` Junio C Hamano
2007-01-10 16:30                         ` Daniel Barkalow
2007-01-11  9:45                           ` Andreas Ericsson
2007-01-10  9:40                     ` Junio C Hamano
2007-01-09 22:37                   ` Junio C Hamano
2007-01-09 23:39                     ` Shawn O. Pearce
2007-01-09 23:46                     ` Linus Torvalds
2007-01-10  0:10                       ` Junio C Hamano
2007-01-10  0:18                         ` Shawn O. Pearce
2007-01-10  0:54                           ` Linus Torvalds
2007-01-10  0:51                       ` Carl Worth
2007-01-10  8:02                       ` Junio C Hamano
2007-01-10  9:04                       ` Andy Parkins
2007-01-10  9:05                         ` Shawn O. Pearce
2007-01-10  9:33                         ` Junio C Hamano
2007-01-10 10:10                           ` Andy Parkins
2007-01-10 10:25                             ` Shawn O. Pearce
2007-01-10 16:18                             ` Junio C Hamano
2007-01-10 14:04                       ` Jeff King
2007-01-11  0:34                         ` Junio C Hamano
2007-01-11  4:31                           ` J. Bruce Fields
2007-01-03 10:46     ` Jeff King
2007-01-03 11:59       ` Jeff King
2007-01-02 23:22 ` [PATCH] git-branch: show detached HEAD Lars Hjemli
2007-01-03  5:18   ` Shawn O. Pearce
2007-01-03  6:53     ` Junio C Hamano
2007-01-03  7:50       ` Lars Hjemli
2007-01-03  7:52         ` Junio C Hamano
2007-01-03  7:05   ` Junio C Hamano
2007-01-03  7:37     ` Lars Hjemli

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).