{"thread":{"id":"28381","subject":"git checkout --orphan skips reflogging","startedAt":"2011-09-13T18:28:50Z","lastAt":"2011-09-14T11:55:40Z","messageCount":3,"participants":["Dmitry Ivankov","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"175416","messageId":"CA+gfSn-tVgj=FYiVGK7kmH4gpnXF3HUbs+f=DfRey6GrpadVYg@mail.gmail.com","threadId":"28381","inReplyTo":null,"subject":"git checkout --orphan skips reflogging","fromName":"Dmitry Ivankov","fromEmail":"divanorama@gmail.com","sentAt":"2011-09-13T18:28:50Z","receivedAt":"2011-09-13T18:28:50Z","isPatch":false,"sender":{"key":"divanorama@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158999?v=4"},"body":"In short, git checkout --orphan doesn't write\nHEAD_sha1 -> 00000\nentry to logs/HEAD, while git-comit will write\n00000 -> new_orphan_HEAD_sha1\nentry. And then reflog backward walk will stop on 000 -> entry and\nwon't see earlier history.\n\nHow to reproduce:\n$ git init test && cd test\n$ git commit -m A --allow-empty\n$ git checkout --orphan topic\n$ git commit -m B --allow-empty\n$ git log -g --oneline HEAD\nsome_sha1 HEAD@{0}: commit (initial): B\n# oops, where are my old HEADs?\n$ cat .git/logs/HEAD\n000.. another_sha1 ... commit (initial): A\n000.. some_sha1 ... commit (initial): B\n# phew, at least I can find them by hand\n\nIsn't  it also a bug in reflog walking that we rely on each old_sha1\nbeing new_sha1 of a previous entry?\n"},{"id":"175434","messageId":"7vaaa8vyc8.fsf@alter.siamese.dyndns.org","threadId":"28381","inReplyTo":"CA+gfSn-tVgj=FYiVGK7kmH4gpnXF3HUbs+f=DfRey6GrpadVYg@mail.gmail.com","subject":"Re: git checkout --orphan skips reflogging","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-09-13T23:04:07Z","receivedAt":"2011-09-13T23:04:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Dmitry Ivankov <divanorama@gmail.com> writes:\n\n> In short, git checkout --orphan doesn't write\n> HEAD_sha1 -> 00000\n> entry to logs/HEAD, while git-comit will write\n> 00000 -> new_orphan_HEAD_sha1\n> entry. And then reflog backward walk will stop on 000 -> entry and\n> won't see earlier history.\n\nFunny. From the point of view of the _current_ branch, it sort of makes\nsense to stop the traversal at that point, but I agree for HEAD reflog\nthat records branch switching, the traversal should not stop.\n\nI am not sure if recording 0{40} after --orphan is the right thing to do\neither (for that matter, I do not necessarily think running --orphan is a\nsane thing to do, but that is a separate issue).\n\n> Isn't  it also a bug in reflog walking that we rely on each old_sha1\n> being new_sha1 of a previous entry?\n\nI am not all that familiar with the reflog walking (which is admittedly a\nbolted-on hack that injects commits with fake ancestry) code, but I think\nit assumes the old sha1 field on the current entry matches the new sha1\nfield on the previous entry, and we could change it to be a bit more\nrobust.\n\nThe attached patch _may_ (I didn't even compile test it) remove the\ndependency on osha1[] and make the code consistently use nsha1[], but I\nthink stopping at the 0{40} is pretty much fundamental in the revision\nwalking machinery the reflog walking code is piggy-backing on, and I do\nnot think this patch would change that.\n\n reflog-walk.c |   17 ++++++++++++-----\n 1 files changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/reflog-walk.c b/reflog-walk.c\nindex 5d81d39..261d300 100644\n--- a/reflog-walk.c\n+++ b/reflog-walk.c\n@@ -211,6 +211,13 @@ int add_reflog_for_walk(struct reflog_walk_info *info,\n \treturn 0;\n }\n \n+static struct reflog_info *peek_reflog_ent(struct commit_reflog *clog)\n+{\n+\tif (clog->recno < 0)\n+\t\treturn NULL;\n+\treturn &clog->reflogs->items[clog->recno];\n+}\n+\n void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)\n {\n \tstruct commit_info *commit_info =\n@@ -223,20 +230,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)\n \t\treturn;\n \n \tcommit_reflog = commit_info->util;\n-\tif (commit_reflog->recno < 0) {\n+\treflog = peek_reflog_ent(commit_reflog);\n+\tif (!reflog) {\n \t\tcommit->parents = NULL;\n \t\treturn;\n \t}\n-\n-\treflog = &commit_reflog->reflogs->items[commit_reflog->recno];\n \tinfo->last_commit_reflog = commit_reflog;\n \tcommit_reflog->recno--;\n-\tcommit_info->commit = (struct commit *)parse_object(reflog->osha1);\n-\tif (!commit_info->commit) {\n+\treflog = peek_reflog_ent(commit_reflog);\n+\tif (!reflog) {\n \t\tcommit->parents = NULL;\n \t\treturn;\n \t}\n \n+\tcommit_info->commit = (struct commit *)parse_object(reflog->nsha1);\n \tcommit->parents = xcalloc(sizeof(struct commit_list), 1);\n \tcommit->parents->item = commit_info->commit;\n }\n"},{"id":"175467","messageId":"CA+gfSn8fHYEdQHzamyWqQ0zCvMCTdnVnJM_dxaq9D_hjq7x1zQ@mail.gmail.com","threadId":"28381","inReplyTo":"7vaaa8vyc8.fsf@alter.siamese.dyndns.org","subject":"Re: git checkout --orphan skips reflogging","fromName":"Dmitry Ivankov","fromEmail":"divanorama@gmail.com","sentAt":"2011-09-14T11:55:40Z","receivedAt":"2011-09-14T11:55:40Z","isPatch":false,"sender":{"key":"divanorama@gmail.com","avatar":"https://avatars.githubusercontent.com/u/158999?v=4"},"body":"On Wed, Sep 14, 2011 at 5:04 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Dmitry Ivankov <divanorama@gmail.com> writes:\n>\n>> In short, git checkout --orphan doesn't write\n>> HEAD_sha1 -> 00000\n>> entry to logs/HEAD, while git-comit will write\n>> 00000 -> new_orphan_HEAD_sha1\n>> entry. And then reflog backward walk will stop on 000 -> entry and\n>> won't see earlier history.\n>\n> Funny. From the point of view of the _current_ branch, it sort of makes\n> sense to stop the traversal at that point, but I agree for HEAD reflog\n> that records branch switching, the traversal should not stop.\n>\n> I am not sure if recording 0{40} after --orphan is the right thing to do\n> either (for that matter, I do not necessarily think running --orphan is a\n> sane thing to do, but that is a separate issue).\nIn fact, my purpose is more like finding out what branches I were recently\non, most of the time even what branches I've updated recently. So, being\nable to see chronologically (by ref modification time) ordered list of refs\nmay be a better way (than git log -g --decorate).\n\n>> Isn't  it also a bug in reflog walking that we rely on each old_sha1\n>> being new_sha1 of a previous entry?\n>\n> I am not all that familiar with the reflog walking (which is admittedly a\n> bolted-on hack that injects commits with fake ancestry) code, but I think\n> it assumes the old sha1 field on the current entry matches the new sha1\n> field on the previous entry, and we could change it to be a bit more\n> robust.\n>\n> The attached patch _may_ (I didn't even compile test it) remove the\n> dependency on osha1[] and make the code consistently use nsha1[], but I\n> think stopping at the 0{40} is pretty much fundamental in the revision\n> walking machinery the reflog walking code is piggy-backing on, and I do\n> not think this patch would change that.\nThe patch compiles fine, and walks past osha1 == 0{40}. Probably osha1\nbecomes completely hidden from the walking machinery, and since nsha1 is\nnever 0{40} (for now) whole history is walked.\n"}]}