All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH/RFC] Record original ref in detached HEAD
@ 2013-02-26 14:28 Nguyễn Thái Ngọc Duy
  2013-02-26 14:37 ` Matthieu Moy
  0 siblings, 1 reply; 3+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2013-02-26 14:28 UTC (permalink / raw)
  To: git; +Cc: Nguyễn Thái Ngọc Duy

Many times I checkout a remote branch, or a tag and after a while I
forget remember what ref I checked it out from. Saving the original
ref would help (or is it already saved somewhere?).

This exploits the fact that FETCH_HEAD stores extra info after the
SHA-1 and at least C Git is prepared to ignore the rest after 40-hex
is successfully parsed for all refs, including HEAD. We could use this
to store the original ref in detached case, as demonstrated in this
patch. "git status" and "git branch" could be modified to show this
information later on. I think it should work even with Git 0.99.8
(I have not really verified though).

So far C Git runs well for me. Other implementations like libgit2 or
JGit may be stricter and reject modified HEAD. I have to check. But I
think HEAD is a local matter and this is not a big deal.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 builtin/checkout.c |  6 ++++--
 refs.c             | 37 ++++++++++++++++++++++++++++++-------
 refs.h             |  5 +++++
 3 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/builtin/checkout.c b/builtin/checkout.c
index a9c1b5a..82fccbe 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -594,8 +594,10 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 	if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
 		/* Nothing to do. */
 	} else if (opts->force_detach || !new->path) {	/* No longer on any branch. */
-		update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
-			   REF_NODEREF, DIE_ON_ERR);
+		update_ref_with_note(msg.buf, "HEAD",
+				     new->commit->object.sha1,
+				     new->path, NULL,
+				     REF_NODEREF, DIE_ON_ERR);
 		if (!opts->quiet) {
 			if (old->path && advice_detached_head)
 				detach_advice(new->name);
diff --git a/refs.c b/refs.c
index 175b9fc..b67c3b1 100644
--- a/refs.c
+++ b/refs.c
@@ -2045,10 +2045,13 @@ static int is_branch(const char *refname)
 	return !strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/");
 }
 
-int write_ref_sha1(struct ref_lock *lock,
-	const unsigned char *sha1, const char *logmsg)
+static int write_ref_sha1_with_note(struct ref_lock *lock,
+				    const unsigned char *sha1,
+				    const char *note,
+				    const char *logmsg)
 {
 	static char term = '\n';
+	static char note_separator = '\t';
 	struct object *o;
 
 	if (!lock)
@@ -2071,7 +2074,10 @@ int write_ref_sha1(struct ref_lock *lock,
 		return -1;
 	}
 	if (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||
-	    write_in_full(lock->lock_fd, &term, 1) != 1
+	    (note &&
+	     (write_in_full(lock->lock_fd, &note_separator, 1) != 1 ||
+	      write_in_full(lock->lock_fd, note, strlen(note)) != strlen(note))) ||
+	     write_in_full(lock->lock_fd, &term, 1) != 1
 		|| close_ref(lock) < 0) {
 		error("Couldn't write %s", lock->lk->filename);
 		unlock_ref(lock);
@@ -2114,6 +2120,13 @@ int write_ref_sha1(struct ref_lock *lock,
 	return 0;
 }
 
+int write_ref_sha1(struct ref_lock *lock,
+		   const unsigned char *sha1,
+		   const char *logmsg)
+{
+	return write_ref_sha1_with_note(lock, sha1, NULL, logmsg);
+}
+
 int create_symref(const char *ref_target, const char *refs_heads_master,
 		  const char *logmsg)
 {
@@ -2411,9 +2424,11 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
 	return retval;
 }
 
-int update_ref(const char *action, const char *refname,
-		const unsigned char *sha1, const unsigned char *oldval,
-		int flags, enum action_on_err onerr)
+int update_ref_with_note(const char *action, const char *refname,
+			 const unsigned char *sha1,
+			 const char *note,
+			 const unsigned char *oldval,
+			 int flags, enum action_on_err onerr)
 {
 	static struct ref_lock *lock;
 	lock = lock_any_ref_for_update(refname, oldval, flags);
@@ -2426,7 +2441,7 @@ int update_ref(const char *action, const char *refname,
 		}
 		return 1;
 	}
-	if (write_ref_sha1(lock, sha1, action) < 0) {
+	if (write_ref_sha1_with_note(lock, sha1, note, action) < 0) {
 		const char *str = "Cannot update the ref '%s'.";
 		switch (onerr) {
 		case MSG_ON_ERR: error(str, refname); break;
@@ -2438,6 +2453,14 @@ int update_ref(const char *action, const char *refname,
 	return 0;
 }
 
+int update_ref(const char *action, const char *refname,
+	       const unsigned char *sha1, const unsigned char *oldval,
+	       int flags, enum action_on_err onerr)
+{
+	return update_ref_with_note(action, refname, sha1, NULL,
+				    oldval, flags, onerr);
+}
+
 struct ref *find_ref_by_name(const struct ref *list, const char *name)
 {
 	for ( ; list; list = list->next)
diff --git a/refs.h b/refs.h
index 1b2e2d3..9fbba2e 100644
--- a/refs.h
+++ b/refs.h
@@ -146,6 +146,11 @@ enum action_on_err { MSG_ON_ERR, DIE_ON_ERR, QUIET_ON_ERR };
 int update_ref(const char *action, const char *refname,
 		const unsigned char *sha1, const unsigned char *oldval,
 		int flags, enum action_on_err onerr);
+int update_ref_with_note(const char *action, const char *refname,
+			 const unsigned char *sha1,
+			 const char *note,
+			 const unsigned char *oldval,
+			 int flags, enum action_on_err onerr);
 
 extern int parse_hide_refs_config(const char *var, const char *value, const char *);
 extern int ref_is_hidden(const char *);
-- 
1.8.1.2.536.gf441e6d

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

* Re: [PATCH/RFC] Record original ref in detached HEAD
  2013-02-26 14:28 [PATCH/RFC] Record original ref in detached HEAD Nguyễn Thái Ngọc Duy
@ 2013-02-26 14:37 ` Matthieu Moy
  2013-02-26 14:57   ` Duy Nguyen
  0 siblings, 1 reply; 3+ messages in thread
From: Matthieu Moy @ 2013-02-26 14:37 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:

> Many times I checkout a remote branch, or a tag and after a while I
> forget remember what ref I checked it out from. Saving the original
> ref would help (or is it already saved somewhere?).

It is :-). Try e.g.

  git checkout --detach
  git checkout -

(analogous to "cd -": return back to where you were before)

-- 
Matthieu Moy
http://www-verimag.imag.fr/~moy/

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

* Re: [PATCH/RFC] Record original ref in detached HEAD
  2013-02-26 14:37 ` Matthieu Moy
@ 2013-02-26 14:57   ` Duy Nguyen
  0 siblings, 0 replies; 3+ messages in thread
From: Duy Nguyen @ 2013-02-26 14:57 UTC (permalink / raw)
  To: Matthieu Moy, Tomas Carnecky; +Cc: git

On Tue, Feb 26, 2013 at 9:37 PM, Matthieu Moy
<Matthieu.Moy@grenoble-inp.fr> wrote:
> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:
>
>> Many times I checkout a remote branch, or a tag and after a while I
>> forget remember what ref I checked it out from. Saving the original
>> ref would help (or is it already saved somewhere?).
>
> It is :-). Try e.g.
>
>   git checkout --detach
>   git checkout -
>
> (analogous to "cd -": return back to where you were before)

Yeah. I always manage to forget reflog when I need it. Time to show
the information in "git branch", oh wait I still have a wip about
git-branch on pu..
-- 
Duy

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

end of thread, other threads:[~2013-02-26 14:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-26 14:28 [PATCH/RFC] Record original ref in detached HEAD Nguyễn Thái Ngọc Duy
2013-02-26 14:37 ` Matthieu Moy
2013-02-26 14:57   ` Duy Nguyen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.