Subject: Re: git mv after the fact

From: Junio C Hamano <[email-masked]>
Date: Fri, 29 May 2026 05:36:21 +0900

Ben Knoble <[email-masked]> writes:

>> Le 27 mai 2026 à 19:24, Junio C Hamano <[email-masked]> a écrit :
>> 
>> Chris Torek <[email-masked]> writes:
>> 
>>>> Chris Torek <[email-masked]> writes:
>>>>> A flag for "git mv" would be convenient (and slightly moreefficient ...
>>>> 
>>> 
>>> On Tue, May 26, 2026 at 8:09 PM Junio C Hamano <[email-masked]> wrote:
>>>> May be convenient, but I do not get the "efficient" part.
>>> 
>>> A normal `git mv` renames the index entry and the file in the working
>>> tree without running `git add` on the *contents*, so there's no new hash
>>> computation.  Presumably a `git mv --after foo bar` would do the same: verify
>>> that there is no existing `bar` in the index, that there is an existing `foo` in
>>> the index, and that there is no `foo` but there is a `bar` in the working tree,
>>> and then it would rename (add-and-remove, really, because of sorting)
>>> the index entry, without scanning the working tree contents.
>>> 
>>> In other words, we skip reading the 3 terabyte file, or whatever.
>> 
>> Yup, that matches what I wrote.  We do not rehash and we only write
>> the index just once.
>
> One thing I wondered: if we don’t have an exact move but assume (by not hashing), doesn’t that mean the index would differ from what’s on disk? I originally thought that might be a problem, but the more I thought the more I realized that’s a fairly typical state anyway.
>
> Just seemed like a potential footgun to me, but perhaps not worth worrying about. 

Good point.  Actually with or without --after/--cached, we do not
have to rehash, and more importantly, we should not rehash.

As you can do this already

    $ date >old.txt
    $ git add old.txt
    $ date >>old.txt
    ... now old.txt is _dirty_
    $ git mv old.txt new.txt

I do not think it is unusual to have the contents you have in your
working tree files diverge from the contents you last 'git add'ed to
the index.  You do *not* want to rehash.  The index entry for new.txt
must be left not-up-to-date, which is achieved in the above sequence
by retaining the file timestamp of old.txt at the "git add" time
even after "git mv" (i.e. new.txt has the timestamp and size of the
old.txt after it got the second "date" output, the index entry
records one generation old one, and would not match).  If we do the
"index-entry only" move, i.e.

    $ date >old.txt
    $ git add old.txt
    $ date >>old.txt
    ... now old.txt is _dirty_
    $ mv old.txt new.txt
    ... oops, we forgot to tell git
    $ git mv --cached old.txt new.txt

we need to make sure that we leave the cache entry dirty for
new.txt in the index.