Git, a reliable way to move / rename files while saving history

I know that there are “many” existing questions that look the same, so let me summarize them before asking me.

  • Answer to Is it possible to move / rename files in git and save their history? , "it's impossible".
  • Conclusion for git to move the file while saving the story , git may see it as a move, or it may still refer to it as a deletion + addition.

The answer to the first, I do not agree, because I did it before. The answer to the second is the reason why I ask this question. Ie

I found myself doing git mv all the time, but sometime it was seen as move / rename, and sometime it was seen as delete + add. So I want to know how I can make it always move / rename?

Take this as an example, below, we can see several cases of redirection / renaming, for example easygenapi/tf-varcaser.go → tf-varcaser.go . Please note that such movements are between folders or between them! I did it!

But there are many other cases where git mv considered as delete + add, appearing in exactly the same change log. Again, I do git mv all the time. Why do git behave differently?

Is there any reliable way to move / rename git files while saving history?

+7
git rename move
source share
2 answers

TL; dg; not

Longer version: In my experience, git very well detects moving / renaming until the file is modified. git uses heuristics to try to find a location. It can be tricked if several files are too similar or if the file was changed during the move, which leads to the fact that it is too different from its original.

The best way I've found to do this is to execute multi-stage commits, splitting all your movements into one commit, and then changing to another. For example...

 git mv foo.txt bar.txt git commit ... modify bar.txt ... git add bar.txt git commit 

This does not guarantee that your move is detected correctly, as it can still get confused if there are several candidates. However, it worked very well for me and catches most cases.

+9
source share

Git does not track renames. Period. It also does not track uploads. Or deletes. Or different. Or patches. Or moves. Or some changes, really.

Git is based on a snapshot. Each commit records a snapshot of the entire project. It. How this snapshot became, Git does not know and does not care.

Differences, patches, add, delete, move, rename, etc. shown by various visualization tools that display them after the fact using heuristics (which is another way of saying “guessing”). Sometimes they can correctly guess what you did, and sometimes not. This does not matter, because since it is only a visualization, it is not part of the story in any way, form or form.

Most tools use some form of similarity metric and conclude that the renaming happened if two files have similarities that exceed a certain threshold. In some instruments, this threshold is configurable. In some tools, even the algorithm is customizable. (A slightly related example: git diff allows you to choose between different algorithms to display differences in files.)

Because Git does not record changes, you can add new changes to later versions of the visualization tools, which can push these changes out of older commits that were written before new tools that understand the new kinds of changes were even written. Imagine, for example, a tool that understands the syntax and semantics of your programming language. He could visualize a certain commit not as a whole bunch of files, each of which had a couple of lines, but as one change, which renames the subroutine and updates each callsite (i.e., renaming refactoring).

Renaming is actually a good example of this. For example, the rename detection heuristics and affinity indicators used by git log --follow have been improved several times. IIRC, at the beginning the renaming was not derived at all, this feature was added later. This would simply not be possible if Git recorded the changes instead of snapshots.

+12
source share

All Articles