Re: [PATCH] checkout.c: unstage empty deleted ita files
- From
Varun Naik <vcnaik94@gmail.com>
- Date
- Jul 29, 2019, 06:54 UTC
- Message-ID
- <CAK_rgsH6hL3g+PVfcMuq1dQLeNJcii=D_dQ8anmWLvYrShmkNg@mail.gmail.com>
- In-Reply-To
- <20190726085756.GA20017@sigill.intra.peff.net>
On Fri, Jul 26, 2019 at 1:57 AM Jeff King <peff@peff.net> wrote:
Show 29 quoted lines
> > On Thu, Jul 25, 2019 at 09:56:45PM -0700, Varun Naik wrote: > > > It is possible to delete a committed file from the index and then add it > > as intent-to-add. After `git checkout HEAD` or `git restore --staged`, > > the file should be identical in the index and HEAD. This patch provides > > the desired behavior even when the file is empty in the index. > > OK, so the issue is that ITA entries have an empty-file sha1, so they > confuse the logic to decide if we can use the old entry. Your fix makes > sense. > > > --- > > CC Jeff because you wrote the code that I am changing now. > > > > checkout.c:update_some() discards the newly created cache entry when its > > mode and oid match those of the old entry. Since an ita file has the > > same oid as an empty file, an empty deleted ita file passes both of > > these checks, and the new entry is discarded. In this case, the file > > should be added to the cache instead. > > > > This change should not affect newly added ita files. For those, inside > > tree.c:read_tree_1(), tree_entry_interesting() returns > > entry_not_interesting, so fn (which points to update_some()) is never > > called. > > These two paragraphs would be a nice addition to the actual commit > message. >
I will add them to the commit message, with some minor changes.
Show 54 quoted lines
> > diff --git a/builtin/checkout.c b/builtin/checkout.c
> > index 91f8509f85..27daa09c3c 100644
> > --- a/builtin/checkout.c
> > +++ b/builtin/checkout.c
> > @@ -126,6 +126,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
> > if (pos >= 0) {
> > struct cache_entry *old = active_cache[pos];
> > if (ce->ce_mode == old->ce_mode &&
> > + !ce_intent_to_add(old) &&
> > oideq(&ce->oid, &old->oid)) {
> > old->ce_flags |= CE_UPDATE;
> > discard_cache_entry(ce);
>
> My first thought here was that we could skip ITA entries here only when
> the HEAD hash is also the empty blob, which would let us retain index
> results in more cases. But it doesn't help. If the HEAD entry isn't the
> empty blob, then we'll have !oideq() and we'll skip anyway, because an
> ITA entry must be the empty blob (if we `git add` some other content,
> then it ceases to be ITA).
>
> So it makes sense to just always skip this "retain the old index entry"
> block for any ITA entry.
>
> > +test_expect_success 'checkout HEAD adds deleted intent-to-add file back to index' '
> > + echo "nonempty" >nonempty &&
> > + >empty &&
> > + git add nonempty empty &&
> > + git commit -m "create files to be deleted" &&
> > + git rm --cached nonempty empty &&
> > + git add -N nonempty empty &&
> > + git checkout HEAD nonempty empty &&
> > + git diff --staged --exit-code
> > +'
>
> This clearly demonstrates the problem. Nice.
>
> > +test_expect_success 'restore --staged adds deleted intent-to-add file back to index' '
> > + echo "nonempty" >nonempty &&
> > + >empty &&
> > + git add nonempty empty &&
> > + git commit -m "create files to be deleted" &&
> > + git rm --cached nonempty empty &&
> > + git add -N nonempty empty &&
> > + git restore --staged nonempty empty &&
> > + git diff --staged --exit-code
> > +'
>
> Hmm. This git-restore test means we don't apply to maint. But wouldn't
> we want the fix for "checkout" there?
>
> I.e., I'd expect a patch to fix and test git-checkout, and then an
> additional patch to be added on the merge of that plus master to test
> git-restore.
>To make sure I understand, do you mean that I should omit the test case for "restore" right now, wait for the patch to reach master, and then create another patch for the "restore" test case?
> Other than that, the patch looks good to me. > > -Peff
Varun