threads / discuss / 12515

error: refs/remotes/origin/HEAD points nowhere!

Subject: error: refs/remotes/origin/HEAD points nowhere!

## tl;dr

10 messages between Mar 5, 2008 and Mar 9, 2008.

replies: 9people: 3as markdown or json

Teemu Likonen· Mar 5, 2008, 11:38 UTC · lore
Hi,

Very annoying error "error: refs/remotes/origin/HEAD points nowhere!" keeps popping up almost all the time after user has removed remote repository "origin". Here's a kind of real-life example:

I have cloned some remote repository:
  git clone git://project/project.git
After a while I start tracking some other remote repository. I do this:
  git remote add ng git://project-ng/project.git

Then I do "git fetch ng" and probably also "git checkout --track -b master-ng ng/master". Then I find the old "origin" useless to me so I remove it with "git remote rm origin".

It seems that refs/remotes/origin/HEAD is still left in my repository and hence I keep getting these annoying error messages all the time. Well, I know how to delete this file, but I believe that git should have deleted it when I called "git remote rm origin". Am I right? What is the purpose of this refs/remotes/origin/HEAD in the first place?

Anyway, thank you guys for this excellent tool and VCS/SCM system. Generally git is really joy to use and very powerful. Thanks.

Junio C Hamano· Mar 5, 2008, 21:24 UTC · re: Teemu Likonen · lore

Re: error: refs/remotes/origin/HEAD points nowhere!

Teemu Likonen <tlikonen@iki.fi> writes:
Show 10 quoted lines
> After a while I start tracking some other remote repository. I do this:
>
>   git remote add ng git://project-ng/project.git
>
> Then I do "git fetch ng" and probably also "git checkout --track -b 
> master-ng ng/master". Then I find the old "origin" useless to me so I 
> remove it with "git remote rm origin".
>
> It seems that refs/remotes/origin/HEAD is still left in my repository 
> and hence I keep getting these annoying error messages all the time. 
> Well, I know how to delete this file, but I believe that git should have
> deleted it when I called "git remote rm origin". Am I right?

Good analysis. I would say "git remote rm" should have removed it and it would be a bug if it didn't.

> What is the purpose of this refs/remotes/origin/HEAD in the first place?

To let you say things like "git diff remotes/origin" as a short-hand for "git diff remotes/origin/master" (or whichever branch 'origin' repository considered the primary one, which is determined when you cloned from it).

Teemu Likonen· Mar 6, 2008, 07:50 UTC · re: Junio C Hamano · lore

Re: error: refs/remotes/origin/HEAD points nowhere!

Junio C Hamano kirjoitti:
Show 19 quoted lines
> Teemu Likonen <tlikonen@iki.fi> writes:
> > After a while I start tracking some other remote repository. I do
> > this:
> >
> >   git remote add ng git://project-ng/project.git
> >
> > Then I do "git fetch ng" and probably also "git checkout --track -b
> > master-ng ng/master". Then I find the old "origin" useless to me so
> > I remove it with "git remote rm origin".
> >
> > It seems that refs/remotes/origin/HEAD is still left in my
> > repository and hence I keep getting these annoying error messages
> > all the time.
> >
> > Well, I know how to delete this file, but I believe that git should
> > have deleted it when I called "git remote rm origin". Am I right?
>
> Good analysis.  I would say "git remote rm" should have removed
> it and it would be a bug if it didn't.

Yes, "git remote rm <remote>" certainly doesn't remove the refs/remotes/<remote>/HEAD file. I can reproduce this bug anytime with current 'master' branch from git://git.kernel.org/pub/scm/git/git.git

Johannes Schindelin· Mar 8, 2008, 22:40 UTC · re: Junio C Hamano · lore

[PATCH] builtin remote rm: remove symbolic refs, too

"git remote add" can add a symbolic ref "HEAD", and "rm" should delete it, too.

Noticed by Teemu Likonen.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin-remote.c  |    5 +++++
 t/t5505-remote.sh |    1 +
 2 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/builtin-remote.c b/builtin-remote.c
index aa90cc9..f7653b6 100644
--- a/builtin-remote.c
+++ b/builtin-remote.c
@@ -267,6 +267,11 @@ static int add_branch_for_removal(const char *refname,
 
 	if (!prefixcmp(refname, branches->prefix)) {
 		struct path_list_item *item;
+
+		/* make sure that symrefs are deleted */
+		if (flags & REF_ISSYMREF)
+			return unlink(git_path(refname));
+
 		item = path_list_append(refname, branches->branches);
 		item->util = xmalloc(20);
 		hashcpy(item->util, sha1);
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index f45ea68..2822a65 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -80,6 +80,7 @@ test_expect_success 'add another remote' '
 test_expect_success 'remove remote' '
 (
 	cd test &&
+	git symbolic-ref refs/remotes/second/HEAD refs/remotes/second/master &&
 	git remote rm second
 )
 '
-- 
1.5.4.3.653.gbc310
Junio C Hamano· Mar 9, 2008, 10:24 UTC · re: Johannes Schindelin · lore

Re: [PATCH] builtin remote rm: remove symbolic refs, too

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 24 quoted lines
> "git remote add" can add a symbolic ref "HEAD", and "rm" should delete
> it, too.
>
> Noticed by Teemu Likonen.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin-remote.c  |    5 +++++
>  t/t5505-remote.sh |    1 +
>  2 files changed, 6 insertions(+), 0 deletions(-)
>
> diff --git a/builtin-remote.c b/builtin-remote.c
> index aa90cc9..f7653b6 100644
> --- a/builtin-remote.c
> +++ b/builtin-remote.c
> @@ -267,6 +267,11 @@ static int add_branch_for_removal(const char *refname,
>  
>  	if (!prefixcmp(refname, branches->prefix)) {
>  		struct path_list_item *item;
> +
> +		/* make sure that symrefs are deleted */
> +		if (flags & REF_ISSYMREF)
> +			return unlink(git_path(refname));
> +
Heh, doing this in C is much easier and simpler ;-)
Teemu Likonen· Mar 7, 2008, 21:02 UTC · re: Teemu Likonen · lore

[PATCH/RFC] Make "git remote rm <remote>" remove file refs/remotes/<remote>/HEAD

The command "git remote rm <remote>" used to leave the refs/remotes/<remote>/HEAD file lying in the directory. This usually happens when user has cloned a remote repository and later decided to remove the default "origin" with "git remote rm origin". The result is that several git commans display the error message

  error: refs/remotes/origin/HEAD points nowhere!
This patch makes "git remote rm" remove the HEAD file if it exists.
Signed-off-by: Teemu Likonen <tlikonen@iki.fi>
---

I have never written or even read any perl code before this (I'm not really a programmer) but I managed to come up with this. This seems to work well. If more error checking or something is needed, I guess somebody else has to do it; my skills aren't quite enough. :)

Any comments?
 git-remote.perl |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/git-remote.perl b/git-remote.perl
index b30ed73..f1f2a1a 100755
--- a/git-remote.perl
+++ b/git-remote.perl
@@ -323,6 +323,7 @@ sub update_remote {
 
 sub rm_remote {
 	my ($name) = @_;
+	my $git_dir = $ENV{GIT_DIR} || ".git";
 	if (!exists $remote->{$name}) {
 		print STDERR "No such remote $name\n";
 		return 1;
@@ -340,6 +341,11 @@ sub rm_remote {
 		}
 	};
 
+	my $remotes_dir = "$git_dir/refs/remotes/$name";
+	if (-f "$remotes_dir/HEAD") {
+		unlink "$remotes_dir/HEAD";
+	}
+
 	my @refs = $git->command('for-each-ref',
 		'--format=%(refname) %(objectname)', "refs/remotes/$name");
 	for (@refs) {
-- 
1.5.4.3.451.ga9908.dirty
Teemu Likonen· Mar 7, 2008, 22:18 UTC · re: Teemu Likonen · lore

Re: [PATCH/RFC] Make "git remote rm <remote>" remove file refs/remotes/<remote>/HEAD

Teemu Likonen kirjoitti:
> If more error checking or something is needed,

Such as finding the .git directory even if $PWD is somewhere else in the tree.

> I guess 
> somebody else has to do it; my skills aren't quite enough. :)
I'm out.
Junio C Hamano· Mar 8, 2008, 01:45 UTC · re: Teemu Likonen · lore

Re: [PATCH/RFC] Make "git remote rm <remote>" remove file refs/remotes/<remote>/HEAD

Teemu Likonen <tlikonen@iki.fi> writes:
Show 19 quoted lines
> The command "git remote rm <remote>" used to leave the
> refs/remotes/<remote>/HEAD file lying in the directory. This usually
> happens when user has cloned a remote repository and later decided to
> remove the default "origin" with "git remote rm origin". The result is
> that several git commans display the error message
>
>   error: refs/remotes/origin/HEAD points nowhere!
>
> This patch makes "git remote rm" remove the HEAD file if it exists.
>
> Signed-off-by: Teemu Likonen <tlikonen@iki.fi>
> ---
>
> I have never written or even read any perl code before this (I'm not really
> a programmer) but I managed to come up with this. This seems to work well. If
> more error checking or something is needed, I guess somebody else has to do it;
> my skills aren't quite enough. :)
>
> Any comments?

Hmm. The loop grabs everything under refs/remotes/$that_remote/ and runs "update-ref -d" on them.

I somehow had an impression that --no-deref option to update-ref was invented to allow operating on the symbolic ref itself, instead of operating on the ref it points at, but it does not seem to work.

I think "update-ref -d" should remove the ref without dereferencing anyway. How about not doing your patch at all (you would need to manually remove the symref in "prune" codepath as well), and instead doing this?

I do not know how this reacts when the tracked HEAD points at a ref that lexicographically sorts earlier, say branch "A".

-- >8 -- delete_ref(): when symref is given, delete it, not the underlying ref.

Removing the underlying ref without touching the symref does not make any sense. An alternative would be to remove the symref _and_ the underlying ref, but this should do for now.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 refs.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/refs.c b/refs.c
index c979fb1..e7c0c38 100644
--- a/refs.c
+++ b/refs.c
@@ -887,7 +887,7 @@ int delete_ref(const char *refname, const unsigned char *sha1)
 	struct ref_lock *lock;
 	int err, i, ret = 0, flag = 0;
 
-	lock = lock_ref_sha1_basic(refname, sha1, 0, &flag);
+	lock = lock_ref_sha1_basic(refname, sha1, REF_NODEREF, &flag);
 	if (!lock)
 		return 1;
 	if (!(flag & REF_ISPACKED)) {
Junio C Hamano· Mar 8, 2008, 01:46 UTC · re: Teemu Likonen · lore

Re: [PATCH/RFC] Make "git remote rm <remote>" remove file refs/remotes/<remote>/HEAD

Junio C Hamano <gitster@pobox.com> writes:
Show 6 quoted lines
> I think "update-ref -d" should remove the ref without dereferencing
> anyway.  How about not doing your patch at all (you would need to manually
> remove the symref in "prune" codepath as well), and instead doing this?
>
> I do not know how this reacts when the tracked HEAD points at a ref that
> lexicographically sorts earlier, say branch "A".

And it turns out it does not react very well. You would want to do something like this on top of that one.

-- >8 -- "remote rm": first remove symbolic and then real refs

This teaches a new %(reftype) to for-each-ref that returns "symref", "packed", or "plain" (we never pack symrefs, so this is the complete enumeration), and updates "git remote rm" to first remove the symrefs and then the actual refs.

Signed-off-by: Junio C Hamano <junio@pobox.com>
---
 builtin-for-each-ref.c |   13 +++++++++++++
 git-remote.perl        |   14 ++++++++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index 07d9c57..50e9eed 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -31,6 +31,7 @@ struct ref_sort {
 
 struct refinfo {
 	char *refname;
+	int reftype;
 	unsigned char objectname[20];
 	struct atom_value *value;
 };
@@ -40,6 +41,7 @@ static struct {
 	cmp_type cmp_type;
 } valid_atom[] = {
 	{ "refname" },
+	{ "reftype" },
 	{ "objecttype" },
 	{ "objectsize", FIELD_ULONG },
 	{ "objectname" },
@@ -568,6 +570,16 @@ static void populate_value(struct refinfo *ref)
 			char *s = xmalloc(len + 4);
 			sprintf(s, "%s^{}", ref->refname);
 			v->s = s;
+		} else if (!strcmp(name, "reftype")) {
+			char *s = xmalloc(20);
+			/* We do not pack symrefs */
+			if (ref->reftype & REF_ISSYMREF)
+				strcpy(s, "symref");
+			else if (ref->reftype & REF_ISPACKED)
+				strcpy(s, "packed");
+			else
+				strcpy(s, "plain");
+			v->s = s;
 		}
 	}
 
@@ -658,6 +670,7 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
 	 */
 	ref = xcalloc(1, sizeof(*ref));
 	ref->refname = xstrdup(refname);
+	ref->reftype = flag;
 	hashcpy(ref->objectname, sha1);
 
 	cnt = cb->grab_cnt;
diff --git a/git-remote.perl b/git-remote.perl
index b30ed73..c57e29d 100755
--- a/git-remote.perl
+++ b/git-remote.perl
@@ -341,9 +341,19 @@ sub rm_remote {
 	};
 
 	my @refs = $git->command('for-each-ref',
-		'--format=%(refname) %(objectname)', "refs/remotes/$name");
+				 '--format=%(refname) %(reftype) %(objectname)',
+				 "refs/remotes/$name");
+	my @nonsym = ();
 	for (@refs) {
-		my ($ref, $object) = split;
+		my ($ref, $type, $object) = split;
+		if ($type !~ /symref/) {
+			push @nonsym, $_;
+		} else {
+			$git->command(qw(update-ref -d), $ref, $object);
+		}
+	}
+	for (@nonsym) {
+		my ($ref, $type, $object) = split;
 		$git->command(qw(update-ref -d), $ref, $object);
 	}
 	return 0;
Teemu Likonen· Mar 8, 2008, 06:16 UTC · re: Junio C Hamano · lore

Re: [PATCH/RFC] Make "git remote rm <remote>" remove file refs/remotes/<remote>/HEAD

Junio C Hamano kirjoitti:
Show 11 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
> > I think "update-ref -d" should remove the ref without dereferencing
> > anyway.  How about not doing your patch at all (you would need to
> > manually remove the symref in "prune" codepath as well), and
> > instead doing this?
> >
> > I do not know how this reacts when the tracked HEAD points at a ref
> > that lexicographically sorts earlier, say branch "A".
>
> And it turns out it does not react very well.  You would want to do
> something like this on top of that one.

This turned out to be much more complicated than just deleting a file. Thank you, these patches seem to work (at least from user's point of view).

← back to recent threads