1

I have created a diff of my changes from other branch called `main like so:

// while on another branch that is not `main`
git diff main > my-diff.patch

however when I run git apply my-diff.patch, I see that my file renames (using git mv) are not being respected. Instead, I see the renamed filed as deleted and the file that was created using git mv as an entirely new file.

How do I get git apply to respect my file renames I had used prior using git mv?

Clifford Fajardo
  • 1,357
  • 1
  • 17
  • 28
  • 1
    I don't believe there's any way to express "rename this file" in a patch. The change will always be "delete the old name, create a new file with identical content". – larsks Oct 25 '21 at 17:30
  • yeah - there doesnt seem to be a builtin feature into apply for this. I bet there is a way to do it with a shell script, but I'd need to investigate it =/ – Clifford Fajardo Oct 25 '21 at 17:41
  • You are blaming the wrong command. `apply` applies what is in the patch. If the patch specifies a rename, `apply` will apply it. You must convince `git diff` to emit a rename operation if you insist in that a rename is applied. – j6t Oct 25 '21 at 20:39

2 Answers2

0

Git is a little peculiar about tracking file renames - in short, it doesn't.

This sort of makes sense, because git doesn't actually track changes at all - every commit is a snapshot of the entire repository. So although there's a "git mv" command, there isn't actually anywhere to record that you used it - all git records is the result, which is exactly the same as if you deleted the original file, and retyped the new one from memory.

What makes this a bit confusing is that git occasionally pretends to know what moving or copying files means. It does this by guessing when it looks at a diff that a creation and a deletion actually go together. It can do that guessing at any time, and some commands have options to make it not guess, or try harder to guess, when displaying things.

So "git apply" did exactly the right thing: it created a state of the repository equivalent to moving the file. Commit that state, and the file will show as renamed or not in all the same places as if you'd run "git mv".

IMSoP
  • 89,526
  • 13
  • 117
  • 169
0

This could work better with Git 2.35 (Q1 2022).

"git apply --3way"(man) bypasses the attempt to do a three-way application in more cases to address the regression caused by the recent change to use direct application as a fallback.

See commit 34d6070 (17 Dec 2021) by Jerry Zhang (jerry-skydio).
(Merged by Junio C Hamano -- gitster -- in commit bc61dba, 10 Jan 2022)

git-apply: skip threeway in add / rename cases

Signed-off-by: Jerry Zhang

Certain invocations of "git apply --3way"(man) will attempt threeway and fail due to missing objects, even though git(man) is able to fall back on apply_fragments and apply the patch successfully with a return value of 0. To fix, return early from try_threeway() in the following cases:

  • When the patch is a rename and no lines have changed. In this case, "git diff"(man) doesn't record the blob info, so 3way is neither possible nor necessary.
  • When the patch is an addition and there is no add/add conflict, i.e. direct_to_threeway is false.
    In this case, threeway will fail since the preimage is not in cache, but isn't necessary anyway since there is no conflict.

This fixes a few unecessary error messages when applying these kinds of patches with --3way.

It also fixes a reported issue where applying a concatenation of several git(man) produced patches will fail when those patches involve a deletion followed by creation of the same file.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250