1

In my experience, when I rename a file, git will detect the rename on my next commit. However, now I want to rename a file, say from old_name to new_name, and in the same commit, I want to create a new file named old_name. Since a (different) file named old_name exists, git is not automatically detecting that this is, in fact, a rename. Is there a way to force git to detect this rename?

So far, I have not been using git mv because I hear it is almost the same as renaming via any ordinary method, but would this help in my situation?

I can see that git is not detecting the rename by running commit -a --dry-run; it lists it as a new file and a modified file.

Even if I am able to force the commit to detect the rename, will this cause any issues down the road when I try to track code across renames e.g. via git log --follow?

DBear
  • 312
  • 2
  • 9

1 Answers1

3

There isn't really any such thing as a rename in Git. Git knows nothing of the concept of renaming a file. No information about any such thing is built into a commit or anywhere else. The use of git mv is totally irrelevant to the matter.

What Git does do is try to be helpful to you, the human, when doing a diff between two commits, by noticing if two files with different pathnames seem to be "the same file" — that is, a file is deleted and a file is created, and they seem to have very similar contents.

So if you want to help Git help you, make a commit consisting entirely of renaming the file. Then make another commit where you create a new file with the old name. Thus when Git walks the parent chain, one commit at a time, it will stand a better chance of drawing the "right" conclusion at every step.

In general, however, you should not count on this behavior on the part of Git.

Here's an example, where I renamed a to c in one commit, and then created a new a in another commit. I'll show excerpts of the log listing so that you can see what Git thinks happened in each commit:

% git log -p

diff --git a/a b/a
new file mode 100644
index 0000000..b680253
--- /dev/null
+++ b/a

diff --git a/a b/c
similarity index 100%
rename from a
rename to c

diff --git a/b b/b
new file mode 100644
index 0000000..6178079
--- /dev/null
+++ b/b

diff --git a/a b/a
new file mode 100644
index 0000000..7898192
--- /dev/null
+++ b/a

As you can see, reading backwards, Git thinks I performed the following steps:

  1. Create a.
  2. Create b.
  3. Rename a to c.
  4. Create a.

And that is exactly what I think I did too, so Git is "helpful" in the desired way here.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thanks. I was expecting that detecting a rename would make a difference in the commit and make the commit smaller (in terms of storage space), but based on what you just said, I suppose that is not the case. – DBear Jun 14 '22 at 14:03
  • Commits are not diffs. Every commit contains the _entire_ project. In general try not to think about meta-non-issues like this and just let Git do what it does. – matt Jun 14 '22 at 14:05
  • Added an actual log as a proof of concept. – matt Jun 14 '22 at 14:06
  • 2
    @DBear yeah, it's not the case. Git will opportunistically store a diff between two similar objects *completely independently* of rename detection. – hobbs Jun 14 '22 at 14:08