{"thread":{"id":"27764","subject":"[PATCH] checkout: do not write bogus reflog entry out","startedAt":"2011-07-06T23:17:43Z","lastAt":"2011-07-06T23:17:43Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"170950","messageId":"7vk4bvhuco.fsf@alter.siamese.dyndns.org","threadId":"27764","inReplyTo":null,"subject":"[PATCH] checkout: do not write bogus reflog entry out","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-07-06T23:17:43Z","receivedAt":"2011-07-06T23:17:43Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The code called resolve_ref(\"HEAD\") and stored the result in old.path to\nrecord which branch it used to be on, so that it can say between which\nbranches the switch took place in the reflog.\n\nHowever, lookup_commit_reference_gently() is called immediately after\nold.path is initialized.  This call can prime replace-object machinery\nwhich in turn collects the loose refs, and calls resolve_ref() inside.  As\nthe string returned from resolve_ref() is a static buffer that is local to\nit, this ended up clobbering the value of old.path. The reflog either\nrecorded a wrong \"switched from\" branch (when the last call to resolve_ref\nhappens to be from the branch namespace), or recorded from a detached HEAD\n(otherwise). Neither is correct.\n\nStore the returned string away with xstrdup() to avoid this.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * This was present ever since checkout was rewritten in C at 782c2d6\n   (Build in checkout, 2008-02-07), but probably got a lot easier to\n   trigger recently due to the addition of object replacement code.\n\n   As it depends on the order readdir() in refs.c::get_ref_dir() returns\n   the entries, there is no universally reproducible test, but I found it\n   in real life inside my git.git primary working repository.\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 28cdc51..48de146 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -715,10 +715,12 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)\n \tunsigned char rev[20];\n \tint flag;\n \tmemset(&old, 0, sizeof(old));\n-\told.path = resolve_ref(\"HEAD\", rev, 0, &flag);\n+\told.path = xstrdup(resolve_ref(\"HEAD\", rev, 0, &flag));\n \told.commit = lookup_commit_reference_gently(rev, 1);\n-\tif (!(flag & REF_ISSYMREF))\n+\tif (!(flag & REF_ISSYMREF)) {\n+\t\tfree((char *)old.path);\n \t\told.path = NULL;\n+\t}\n \n \tif (old.path && !prefixcmp(old.path, \"refs/heads/\"))\n \t\told.name = old.path + strlen(\"refs/heads/\");\n@@ -741,6 +743,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)\n \tupdate_refs_for_switch(opts, &old, new);\n \n \tret = post_checkout_hook(old.commit, new->commit, 1);\n+\tfree((char *)old.path);\n \treturn ret || opts->writeout_error;\n }\n"}]}