Re: Detached checkout will clobber branch head when using symlink HEAD

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Oct 16, 2008 at 04:11:03PM -0400, Matt Draisey wrote:

> I am using the following system defaults:
> 
> core.prefersymlinkrefs=true
> gc.packrefs=false
> 
> so almost all my git repositories are still using a symlink HEAD.
> I have some old scripts That I use occasionally and still depend on it.
> Using detached checkout is the only problem I've had.

In your position I would consider updating my scripts. But I guess you
could also try to work up a patch that makes detached HEAD work
(replacing the symlink with a file, then bringing back the symlink when
you're on a branch). In the meantime, here is a cleaned-up version of my
patch, with a proper commit message and a test.

-- >8 --
do not clobber symlinked ref with detached HEAD

The default configuration for git uses a symref for HEAD.
When we detach the HEAD, we can simply write the detached
commit sha1 into the HEAD file.

It is still possible to use symlinks for HEAD (either by
setting it up manually, or by using core.prefersymlinkrefs).
In that case, moving to a detached HEAD is impossible, since
we have nowhere to store the sha1.

However, the current code doesn't realize this and actually
writes into the HEAD file anyway, meaning that it overwrites
the value of the currently checked out branch.

Instead, let's detect in the locking mechanism that we have
a symlink but the caller requested that we lock the original
ref name instead of its linked destination. This has two
advantages:

  - we don't have to add an extra stat call, since we
    discover the symlink during normal ref resolution

  - any code to update a ref should lock it, meaning that we
    should catch any other similar instances

Signed-off-by: Jeff King <peff@xxxxxxxx>
---
 refs.c                      |    9 ++++++++-
 refs.h                      |    1 +
 t/t7202-checkout-symlink.sh |   19 +++++++++++++++++++
 3 files changed, 28 insertions(+), 1 deletions(-)
 create mode 100755 t/t7202-checkout-symlink.sh

diff --git a/refs.c b/refs.c
index b680750..b4b3865 100644
--- a/refs.c
+++ b/refs.c
@@ -446,8 +446,11 @@ const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *
 				buffer[len] = 0;
 				strcpy(ref_buffer, buffer);
 				ref = ref_buffer;
-				if (flag)
+				if (flag) {
+					if (!(*flag & REF_ISSYMREF))
+						*flag |= REF_OUTER_IS_SYMLINK;
 					*flag |= REF_ISSYMREF;
+				}
 				continue;
 			}
 		}
@@ -817,6 +820,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *ref, const unsigned char
 		}
 		ref = resolve_ref(orig_ref, lock->old_sha1, mustexist, &type);
 	}
+	if (type & REF_OUTER_IS_SYMLINK && flags & REF_NODEREF) {
+		error("unable to directly lock symbolic link '%s'", orig_ref);
+		goto error_return;
+	}
 	if (type_p)
 	    *type_p = type;
 	if (!ref) {
diff --git a/refs.h b/refs.h
index 06ad260..9b0dcd9 100644
--- a/refs.h
+++ b/refs.h
@@ -12,6 +12,7 @@ struct ref_lock {
 
 #define REF_ISSYMREF 01
 #define REF_ISPACKED 02
+#define REF_OUTER_IS_SYMLINK 04
 
 /*
  * Calls the specified function for each ref file until it returns nonzero,
diff --git a/t/t7202-checkout-symlink.sh b/t/t7202-checkout-symlink.sh
new file mode 100755
index 0000000..cf09f5f
--- /dev/null
+++ b/t/t7202-checkout-symlink.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+test_description='checkout with symlinked HEAD'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo one > file && git add file && git commit -m one &&
+	echo two > file && git add file && git commit -m two &&
+	ln -sf refs/heads/master .git/HEAD
+'
+
+test_expect_success 'checkout detached HEAD does not clobber ref' '
+	test_must_fail git checkout HEAD^ &&
+	echo two >expect &&
+	git log -1 --pretty=tformat:%s >actual
+	test_cmp actual expect
+'
+
+test_done
-- 
1.6.0.2.711.gf1ba4.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux