Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git, sure-fire way to move/rename files while keeping the history

Tags:

git

rename

move

I know there are "lots" of existing questions that looks similar, so let me summarize them before asking mine.

  • The answer to Is it possible to move/rename files in git and maintain their history? is, "it is not possible".
  • The conclusion for git moving file while keeping history is, Git may see it as a move, or it may still treat it as a delete + addition.

The answer to the first one, I don't agree, because I've done that before. The answer to the second one is the reason why I'm asking this question. I.e.,

I found I am doing git mv all the times, but sometime it is treated as move/rename, and sometime it is treated as delete + addition. Thus, I want to know how I can make it always a move/rename?

Take this one as an example, at the bottom, we can see several move/rename cases, like easygenapi/tf-varcaser.go → tf-varcaser.go. Note that such moves are across/between the folders! I.e., I did it!

But there are many other cases git mv were treated as delete + addition, showing in the exactly same change log. Again, I am doing git mv all the times. Why git behave differently?

Is there any sure-fire way to move/rename git files while keeping the history?

like image 948
xpt Avatar asked Feb 25 '16 04:02

xpt


People also ask

How do I rename a directory in git without losing history?

emiller/git-mv-with-history. git utility to move/rename file or folder and retain history with it. # git-mv-with-history -- move/rename file or folder, with history. # Git has a rename command git mv, but that is just for convenience.

What is the most efficient way to rename a file in a repository?

In your repository, browse to the file you want to rename. In the upper right corner of the file view, click to open the file editor. In the filename field, change the name of the file to the new filename you want. You can also update the contents of your file at the same time.

What happens if you rename a file in git?

Git keeps track of changes to files in the working directory of a repository by their name. When you move or rename a file, Git doesn't see that a file was moved; it sees that there's a file with a new filename, and the file with the old filename was deleted (even if the contents remain the same).

How do I rename and move a file?

Use the mv command to move files and directories from one directory to another or to rename a file or directory. If you move a file or directory to a new directory without specifying a new name, it retains its original name. Attention: The mv command can overwrite many existing files unless you specify the -i flag.

How to move/rename file or folder with history in Git?

git utility to move/rename file or folder and retain history with it. · GitHub Instantly share code, notes, and snippets. git utility to move/rename file or folder and retain history with it. # git-mv-with-history -- move/rename file or folder, with history. # Git has a rename command git mv, but that is just for convenience.

How to move/rename file or folder and retain history with it?

git utility to move/rename file or folder and retain history with it. # git-mv-with-history -- move/rename file or folder, with history. # Git has a rename command git mv, but that is just for convenience. # with different name and the same content. # of anything via `filter-branch`. This utility just wraps that functionality,

What is Git-MV-with-history?

# git-mv-with-history -- move/rename file or folder, with history. # Git has a rename command git mv, but that is just for convenience. # with different name and the same content. # of anything via `filter-branch`. This utility just wraps that functionality, # time (since the `filter-branch` can be slow on big repos).

How to see the history of commits beyond the rename?

Move file into things directory However, the --follow flag will allow you to see the history of commits beyond the rename: $ git log --follow --pretty=oneline things/text.txt 8567d... Move file into things directory 1458a... Fix something 0aac5... Add something


2 Answers

tl;dr; no

Longer version: In my experience, git is very good at detecting the move/rename as long as the file is unmodified. Git uses heuristics to attempt and locate the move. It can be fooled by having several files that are too similar, or if the file has been modified during the move, causing it to be too dissimilar from its original.

The best way I have found to do this is to do multi-stage commits, separating all of your moves into one commit, followed by the changes in another. For example...

git mv foo.txt bar.txt
git commit

... modify bar.txt ...

git add bar.txt
git commit

It will not guarantee your move is detected correctly, as it can still get confused when there are multiple candidates. However it has worked very well for me and catches the majority of cases.

like image 154
Kevin Burdett Avatar answered Oct 26 '22 23:10

Kevin Burdett


Git doesn't track renames. Period. It also doesn't track adds. Or deletes. Or diffs. Or patches. Or moves. Or any sort of change, really.

Git is snapshot-based. Every commit records a snapshot of the entire project. That's it. How that snapshot came to be, Git neither knows nor cares.

Diffs, patches, adds, deletes, moves, renames, etc. are shown by various visualization tools, which infer them after the fact using heuristics (which is another way of saying "guessing"). Sometimes, they may guess correctly what you did, and sometimes they don't. It doesn't matter, though, because it's only visualization, it's not part of the history in any way, shape, or form.

Most tools use some form of similarity metric, and infer that a rename occurred if two files have a similarity greater than some threshold. In some tools, this threshold is configurable. In some tools, even the algorithm is configurable. (A slightly related example: git diff allows you to choose between different algorithms for inferring differences within files.)

Since Git doesn't record changes, it is possible to add new changes in later versions of the visualization tools which can infer those changes from older commits which were recorded before the new tools which understand new kinds of changes were even written. Imagine, for example, a tool which understands the syntax and semantics of the programming language you are using. It could visualize a certain commit not as a whole bunch of files each having a couple of lines changed, but as a single change which renames a subroutine and updates each callsite (i.e. the Rename Method Refactoring).

Renames are actually a good example of this. The rename detection heuristics and similarity metrics used by git log --follow, for example, were improved multiple times. IIRC, in the beginning, renames weren't inferred at all, that capability was added later. This would simply not have been possible, if Git recorded changes instead of snapshots.

like image 31
Jörg W Mittag Avatar answered Oct 26 '22 22:10

Jörg W Mittag