{"thread":{"id":"33017","subject":"[PATCH/RFC] Record original ref in detached HEAD","startedAt":"2013-02-26T14:28:17Z","lastAt":"2013-02-26T14:57:36Z","messageCount":3,"participants":["Nguyễn Thái Ngọc Duy","Matthieu Moy","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"210321","messageId":"1361888897-1821-1-git-send-email-pclouds@gmail.com","threadId":"33017","inReplyTo":null,"subject":"[PATCH/RFC] Record original ref in detached HEAD","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2013-02-26T14:28:17Z","receivedAt":"2013-02-26T14:28:17Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Many times I checkout a remote branch, or a tag and after a while I\nforget remember what ref I checked it out from. Saving the original\nref would help (or is it already saved somewhere?).\n\nThis exploits the fact that FETCH_HEAD stores extra info after the\nSHA-1 and at least C Git is prepared to ignore the rest after 40-hex\nis successfully parsed for all refs, including HEAD. We could use this\nto store the original ref in detached case, as demonstrated in this\npatch. \"git status\" and \"git branch\" could be modified to show this\ninformation later on. I think it should work even with Git 0.99.8\n(I have not really verified though).\n\nSo far C Git runs well for me. Other implementations like libgit2 or\nJGit may be stricter and reject modified HEAD. I have to check. But I\nthink HEAD is a local matter and this is not a big deal.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/checkout.c |  6 ++++--\n refs.c             | 37 ++++++++++++++++++++++++++++++-------\n refs.h             |  5 +++++\n 3 files changed, 39 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex a9c1b5a..82fccbe 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -594,8 +594,10 @@ static void update_refs_for_switch(const struct checkout_opts *opts,\n \tif (!strcmp(new->name, \"HEAD\") && !new->path && !opts->force_detach) {\n \t\t/* Nothing to do. */\n \t} else if (opts->force_detach || !new->path) {\t/* No longer on any branch. */\n-\t\tupdate_ref(msg.buf, \"HEAD\", new->commit->object.sha1, NULL,\n-\t\t\t   REF_NODEREF, DIE_ON_ERR);\n+\t\tupdate_ref_with_note(msg.buf, \"HEAD\",\n+\t\t\t\t     new->commit->object.sha1,\n+\t\t\t\t     new->path, NULL,\n+\t\t\t\t     REF_NODEREF, DIE_ON_ERR);\n \t\tif (!opts->quiet) {\n \t\t\tif (old->path && advice_detached_head)\n \t\t\t\tdetach_advice(new->name);\ndiff --git a/refs.c b/refs.c\nindex 175b9fc..b67c3b1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -2045,10 +2045,13 @@ static int is_branch(const char *refname)\n \treturn !strcmp(refname, \"HEAD\") || !prefixcmp(refname, \"refs/heads/\");\n }\n \n-int write_ref_sha1(struct ref_lock *lock,\n-\tconst unsigned char *sha1, const char *logmsg)\n+static int write_ref_sha1_with_note(struct ref_lock *lock,\n+\t\t\t\t    const unsigned char *sha1,\n+\t\t\t\t    const char *note,\n+\t\t\t\t    const char *logmsg)\n {\n \tstatic char term = '\\n';\n+\tstatic char note_separator = '\\t';\n \tstruct object *o;\n \n \tif (!lock)\n@@ -2071,7 +2074,10 @@ int write_ref_sha1(struct ref_lock *lock,\n \t\treturn -1;\n \t}\n \tif (write_in_full(lock->lock_fd, sha1_to_hex(sha1), 40) != 40 ||\n-\t    write_in_full(lock->lock_fd, &term, 1) != 1\n+\t    (note &&\n+\t     (write_in_full(lock->lock_fd, &note_separator, 1) != 1 ||\n+\t      write_in_full(lock->lock_fd, note, strlen(note)) != strlen(note))) ||\n+\t     write_in_full(lock->lock_fd, &term, 1) != 1\n \t\t|| close_ref(lock) < 0) {\n \t\terror(\"Couldn't write %s\", lock->lk->filename);\n \t\tunlock_ref(lock);\n@@ -2114,6 +2120,13 @@ int write_ref_sha1(struct ref_lock *lock,\n \treturn 0;\n }\n \n+int write_ref_sha1(struct ref_lock *lock,\n+\t\t   const unsigned char *sha1,\n+\t\t   const char *logmsg)\n+{\n+\treturn write_ref_sha1_with_note(lock, sha1, NULL, logmsg);\n+}\n+\n int create_symref(const char *ref_target, const char *refs_heads_master,\n \t\t  const char *logmsg)\n {\n@@ -2411,9 +2424,11 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)\n \treturn retval;\n }\n \n-int update_ref(const char *action, const char *refname,\n-\t\tconst unsigned char *sha1, const unsigned char *oldval,\n-\t\tint flags, enum action_on_err onerr)\n+int update_ref_with_note(const char *action, const char *refname,\n+\t\t\t const unsigned char *sha1,\n+\t\t\t const char *note,\n+\t\t\t const unsigned char *oldval,\n+\t\t\t int flags, enum action_on_err onerr)\n {\n \tstatic struct ref_lock *lock;\n \tlock = lock_any_ref_for_update(refname, oldval, flags);\n@@ -2426,7 +2441,7 @@ int update_ref(const char *action, const char *refname,\n \t\t}\n \t\treturn 1;\n \t}\n-\tif (write_ref_sha1(lock, sha1, action) < 0) {\n+\tif (write_ref_sha1_with_note(lock, sha1, note, action) < 0) {\n \t\tconst char *str = \"Cannot update the ref '%s'.\";\n \t\tswitch (onerr) {\n \t\tcase MSG_ON_ERR: error(str, refname); break;\n@@ -2438,6 +2453,14 @@ int update_ref(const char *action, const char *refname,\n \treturn 0;\n }\n \n+int update_ref(const char *action, const char *refname,\n+\t       const unsigned char *sha1, const unsigned char *oldval,\n+\t       int flags, enum action_on_err onerr)\n+{\n+\treturn update_ref_with_note(action, refname, sha1, NULL,\n+\t\t\t\t    oldval, flags, onerr);\n+}\n+\n struct ref *find_ref_by_name(const struct ref *list, const char *name)\n {\n \tfor ( ; list; list = list->next)\ndiff --git a/refs.h b/refs.h\nindex 1b2e2d3..9fbba2e 100644\n--- a/refs.h\n+++ b/refs.h\n@@ -146,6 +146,11 @@ enum action_on_err { MSG_ON_ERR, DIE_ON_ERR, QUIET_ON_ERR };\n int update_ref(const char *action, const char *refname,\n \t\tconst unsigned char *sha1, const unsigned char *oldval,\n \t\tint flags, enum action_on_err onerr);\n+int update_ref_with_note(const char *action, const char *refname,\n+\t\t\t const unsigned char *sha1,\n+\t\t\t const char *note,\n+\t\t\t const unsigned char *oldval,\n+\t\t\t int flags, enum action_on_err onerr);\n \n extern int parse_hide_refs_config(const char *var, const char *value, const char *);\n extern int ref_is_hidden(const char *);\n-- \n1.8.1.2.536.gf441e6d\n"},{"id":"210322","messageId":"vpqsj4jqgy4.fsf@grenoble-inp.fr","threadId":"33017","inReplyTo":"1361888897-1821-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH/RFC] Record original ref in detached HEAD","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2013-02-26T14:37:39Z","receivedAt":"2013-02-26T14:37:39Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n\n> Many times I checkout a remote branch, or a tag and after a while I\n> forget remember what ref I checked it out from. Saving the original\n> ref would help (or is it already saved somewhere?).\n\nIt is :-). Try e.g.\n\n  git checkout --detach\n  git checkout -\n\n(analogous to \"cd -\": return back to where you were before)\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"210323","messageId":"CACsJy8BJqoCVHm=jY+Y6LB_aKuyE5HsGA=eHmYur-Lfrp+PE4A@mail.gmail.com","threadId":"33017","inReplyTo":"vpqsj4jqgy4.fsf@grenoble-inp.fr","subject":"Re: [PATCH/RFC] Record original ref in detached HEAD","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-02-26T14:57:36Z","receivedAt":"2013-02-26T14:57:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Feb 26, 2013 at 9:37 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n>\n>> Many times I checkout a remote branch, or a tag and after a while I\n>> forget remember what ref I checked it out from. Saving the original\n>> ref would help (or is it already saved somewhere?).\n>\n> It is :-). Try e.g.\n>\n>   git checkout --detach\n>   git checkout -\n>\n> (analogous to \"cd -\": return back to where you were before)\n\nYeah. I always manage to forget reflog when I need it. Time to show\nthe information in \"git branch\", oh wait I still have a wip about\ngit-branch on pu..\n-- \nDuy\n"}]}