git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Martin von Zweigbergk <martin.von.zweigbergk@gmail.com>
To: Jeff King <peff@peff.net>
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>, git@vger.kernel.org
Subject: Re: First/oldest entry in reflog dropped
Date: Sun, 21 Nov 2010 17:57:46 -0500	[thread overview]
Message-ID: <AANLkTikS00FN9-_MoSGvBMxdUefzk5K_8Zz2V14KCDLJ@mail.gmail.com> (raw)
In-Reply-To: <20101121053545.GA10520@sigill.intra.peff.net>

On Sun, Nov 21, 2010 at 12:35 AM, Jeff King <peff@peff.net> wrote:
> On Sat, Nov 20, 2010 at 10:11:34PM -0500, Martin von Zweigbergk wrote:
>
>> Can someone explain the behavior in the execution below?
>>
>> # I expected this reflog...
>> $ git branch tmp
>> $ git reflog show refs/heads/tmp
>> b60a214 refs/heads/tmp@{0}: branch: Created from master
>>
>> # ... and this one as well...
>> $ git update-ref refs/heads/tmp HEAD^
>> $ git reflog show refs/heads/tmp
>> 7d1a0b8 refs/heads/tmp@{0}:
>> b60a214 refs/heads/tmp@{1}: branch: Created from master
>>
>> # ... but why is the first entry (i.e. "branch: Created from master")
>> # dropped here?
>> $ git update-ref refs/heads/tmp HEAD
>> $ git reflog show refs/heads/tmp
>> b60a214 refs/heads/tmp@{0}:
>> 7d1a0b8 refs/heads/tmp@{1}:
>>
>> If the ref is updated once more (to e.g. HEAD^^) before being moved back
>> to HEAD, the first entry will be shown in the output.
>>
>> If this is a bug, it seems to be in reflog, rather than in update-ref,
>> because the first entry does exist in .git/logs/refs/heads/tmp.
>
> I think it's a bug in the reflog-walking machinery, which is sort of
> bolted onto the regular revision traversal machinery. When we hit
> b60a214 the first time, we show it and set the SHOWN flag (since the
> normal traversal machinery would not want to show a commit twice). When
> we hit it again, simplify_commit() sees that it is SHOWN and tells us to
> skip it.
>
> However, the bolted-on reflog-walking machinery does have a way of
> handling this. While we are traversing via get_revision(), we notice
> that we are doing a reflog walk and call fake_reflog_parent. This
> function is responsible for replacing the actual parents of the commit
> with a fake list consisting of the previous reflog entry (so we
> basically pretend that the history consists of a string of commits, each
> one pointing to the previous reflog entry, not the actual parent).
>
> This function _also_ clears some flags, including the SHOWN flag, in
> what almost seems like a tacked-on side effect. So if we hit the same
> commit twice, we will actually show it again. Which is what makes
> reflogs with repeated commits work at all.
>
> However, there is a subtle bug: it clears the flags at the very end of
> the function. But through the function, if we see that there are no fake
> parents (because we are on the very first reflog entry), we do an early
> return. But we not only skip the later "set up parents" code, we also
> accidentally skip the "clear SHOWN flag" side-effect code.
>
> So I believe we will always fail to show the very first reflog if it is
> a repeated commit.
>
> The fix, AFAICT, is to just move the flag clearing above the early
> returns (patch below). But I have to admit I do not quite understand
> what the ADDED and SEEN flags are doing here, as this is the first time
> I have ever looked at the reflog-walk code. So possibly just the SHOWN
> flag should be unconditionally cleared.
>
> This patch clears up your bug, and doesn't break any tests. But I'd
> really like to get a second opinion on the significance of those other
> flags, or why the flag clearing was at the bottom of the function in the
> first place.
>
> -Peff
>
> ---
> diff --git a/reflog-walk.c b/reflog-walk.c
> index 4879615..d5d055b 100644
> --- a/reflog-walk.c
> +++ b/reflog-walk.c
> @@ -210,44 +210,45 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
>        add_commit_info(commit, commit_reflog, &info->reflogs);
>        return 0;
>  }
>
>  void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
>  {
>        struct commit_info *commit_info =
>                get_commit_info(commit, &info->reflogs, 0);
>        struct commit_reflog *commit_reflog;
>        struct reflog_info *reflog;
>
> +       commit->object.flags &= ~(ADDED | SEEN | SHOWN);
> +
>        info->last_commit_reflog = NULL;
>        if (!commit_info)
>                return;
>
>        commit_reflog = commit_info->util;
>        if (commit_reflog->recno < 0) {
>                commit->parents = NULL;
>                return;
>        }
>
>        reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
>        info->last_commit_reflog = commit_reflog;
>        commit_reflog->recno--;
>        commit_info->commit = (struct commit *)parse_object(reflog->osha1);
>        if (!commit_info->commit) {
>                commit->parents = NULL;
>                return;
>        }
>
>        commit->parents = xcalloc(sizeof(struct commit_list), 1);
>        commit->parents->item = commit_info->commit;
> -       commit->object.flags &= ~(ADDED | SEEN | SHOWN);
>  }
>
>  void get_reflog_selector(struct strbuf *sb,
>                         struct reflog_walk_info *reflog_info,
>                         enum date_mode dmode,
>                         int shorten)
>  {
>        struct commit_reflog *commit_reflog = reflog_info->last_commit_reflog;
>        struct reflog_info *info;
>        const char *printed_ref;
>
>

Good job! And yes, if the first commit is included in any cycles, it
seems to be dropped. I must have been blind yesterday...

      parent reply	other threads:[~2010-11-21 22:58 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-11-21  3:11 First/oldest entry in reflog dropped Martin von Zweigbergk
2010-11-21  5:35 ` Jeff King
2010-11-21 11:36   ` Johannes Schindelin
2010-11-22  4:42     ` Jeff King
2010-11-22  9:32       ` Johannes Schindelin
2010-11-24  0:35       ` Junio C Hamano
2010-11-25 16:15         ` Jeff King
2010-11-21 22:57   ` Martin von Zweigbergk [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AANLkTikS00FN9-_MoSGvBMxdUefzk5K_8Zz2V14KCDLJ@mail.gmail.com \
    --to=martin.von.zweigbergk@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=johannes.schindelin@gmx.de \
    --cc=peff@peff.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).