git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: print errors from git-update-ref

From
Shawn Pearce <spearce@spearce.org>
Date
Jul 27, 2006, 01:28 UTC
Message-ID
<20060727012856.GB32492@spearce.org>
In-Reply-To
<7vk663h6zi.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> wrote:
Show 11 quoted lines
> "Alex Riesen" <raa.lkml@gmail.com> writes:
> 
> > ...otherwise it not clear what happened when update-ref fails.
> >
> > E.g., git checkout -b a/b/c HEAD would print nothing if refs/heads/a
> > exists and is a directory (it does return 1, so scripts checking for
> > return code should be ok).
> 
> My gut feeling is that complaining from update-ref is fine, but
> I am still tired after a long week and not thinking straight, so
> I will not be applying this tonight.

So I looked into this issue tonight. For starters I can't seem to reproduce the situtation reported by Alex, and since he didn't supply new test cases its difficult to actually fix it.

I did however find problems with git-update-ref a/b/c when a is actually an existing ref. This didn't report any error, so here's a fix. It may resolve Alex's problem - or maybe not.

-->8-- Display an error from update-ref if target ref name is invalid.

Alex Riesen (raa.lkml@gmail.com) recently observed that git branch would fail with no error message due to unexpected situations with regards to refs. For example, if .git/refs/heads/gu is a file but `git branch -b refs/heads/gu/fixa HEAD` was invoked by the user it would fail silently due to refs/heads/gu being a file and not a directory.

This change adds a test for trying to create a ref within a directory that is actually currently a file, and adds error printing within the ref locking routine should the resolve operation fail.

The error printing code probably belongs at this level of the library as other failures within the ref locking, writing and logging code are also currently at this level of the code.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 refs.c                |   33 +++++++++++++++++++++++++++++++++
 t/t1400-update-ref.sh |   12 ++++++++++++
 2 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/refs.c b/refs.c
index 56db394..e99e9e4 100644
--- a/refs.c
+++ b/refs.c
@@ -290,10 +290,33 @@ static struct ref_lock *verify_lock(stru
 	return lock;
 }
 
+static char* not_a_directory (const char *orig_path)
+{
+	char *p = strdup(orig_path);
+	struct stat st;
+
+	do {
+		char * s = strrchr(p, '/');
+		if (s) {
+			*s = 0;
+			if (lstat(p, &st) == 0 && S_ISDIR(st.st_mode)) {
+				*s = '/';
+				break;
+			}
+		} else {
+			strcpy(p, orig_path);
+			break;
+		}
+	} while (errno == ENOTDIR);
+
+	return p;
+}
+
 static struct ref_lock *lock_ref_sha1_basic(const char *path,
 	int plen,
 	const unsigned char *old_sha1, int mustexist)
 {
+	const char *orig_path = path;
 	struct ref_lock *lock;
 	struct stat st;
 
@@ -303,7 +326,17 @@ static struct ref_lock *lock_ref_sha1_ba
 	plen = strlen(path) - plen;
 	path = resolve_ref(path, lock->old_sha1, mustexist);
 	if (!path) {
+		int last_errno = errno;
+		if (errno == ENOTDIR) {
+			char* p = not_a_directory(orig_path);
+			error("unable to resolve reference %s: %s",
+				p, strerror(errno));
+			free(p);
+		} else
+			error("unable to resolve reference %s: %s",
+				orig_path, strerror(errno));
 		unlock_ref(lock);
+		errno = last_errno;
 		return NULL;
 	}
 	lock->lk = xcalloc(1, sizeof(struct lock_file));
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index 04fab26..e73827c 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -14,6 +14,8 @@ D=44444444444444444444444444444444444444
 E=5555555555555555555555555555555555555555
 F=6666666666666666666666666666666666666666
 m=refs/heads/master
+n_dir=refs/heads/gu
+n=$n_dir/fixes
 
 test_expect_success \
 	"create $m" \
@@ -26,6 +28,16 @@ test_expect_success \
 rm -f .git/$m
 
 test_expect_success \
+	"fail to create $n" \
+	'touch .git/$n_dir
+	 git-update-ref $n $A >out 2>err
+	 test $? = 1 &&
+	 test "" = "$(cat out)" &&
+	 grep "error: unable to resolve reference" err &&
+	 grep $n_dir err'
+rm -f .git/$n_dir out err
+
+test_expect_success \
 	"create $m (by HEAD)" \
 	'git-update-ref HEAD $A &&
 	 test $A = $(cat .git/$m)'
-- 
1.4.2.rc1.g802da
Previous: Junio C HamanoNext: Johannes Schindelin
Message 3 of 7 in “print errors from git-update-ref”
  1. Alex RiesenJul 18, 2006
  2. Junio C HamanoJul 24, 2006
  3. Shawn PearceJul 27, 2006
  4. Johannes SchindelinJul 27, 2006
  5. Shawn PearceJul 28, 2006
  6. Junio C HamanoJul 28, 2006
  7. Shawn PearceJul 29, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.