Git squash commits of renamed files (an keep history)
Asked Answered
T

1

15

Backround

Hi, I'm working on a local feature branch. This local branch is messed up with lots of small commits. Before pushing the branch to the remote I would like to tidy things up.

For this I'd do a interactively rebase:

git rebase -i

No problem so far.

Problem

Now here's the difficult part: During the development of the feature I've done several refactorings including renames and moves of files. The history of the renamed files are available, due to renaming them with:

git -mv

But when I squash the commits before and after the rename-commits, the history is gone and git notifies the changes as deletion and addition of a file.

What is the Problem?

How can I squash commits including rename without loosing file history?

Tanya answered 19/2, 2015 at 12:10 Comment(0)
C
8

Git does not track renames directly, it compares file contents and detects renames by similarity.

When you squash a history you put all changes of a file in one commit. The file might then change a lot compared to the previous commit. Thus it is not very similar to the previous commit and git thinks it is a delete/add.

if you want to see the history of such a file you must adjust the find-renames threshold. E.g. for 50% similarity use

git log --follow --find-rename=50 -- someFile

Similar options are also available for diff, merge and rebase. Take a look at the docs:

git rebase

rename-threshold=n Controls the similarity threshold used for rename detection. See also git-diff1 -M.

git diff

--find-renames[=n]

Detect renames. If n is specified, it is a threshold on the similarity index (i.e. amount of addition/deletions compared to the file’s size). For example, -M90% means Git should consider a delete/add pair to be a rename if more than 90% of the file hasn’t changed. Without a % sign, the number is to be read as a fraction, with a decimal point before it. I.e., -M5 becomes 0.5, and is thus the same as -M50%. Similarly, -M05 is the same as -M5%. To limit detection to exact renames, use -M100%. The default similarity index is 50%.

Cryoscope answered 19/2, 2015 at 12:44 Comment(5)
Thanks for your answer. So, renaming files with git mvactually doesn't tell git to keep the history of a file, instead it just renames the file and later it auto detects that the file has been renamed? In other words: there is no possibility to do what I wanted? The only possibility is to do the rename in a separate commit.Tanya
Is there a way for forcing the git to recognize a file as rename instead of new file by specifying a similarity when checking in?Edithe
Wow this is shocking news and really bad. I always preached Do a rename with git mv to allow git to track the rename to git newbees and now I am also stuck in an impossible rebase of commits that renamed files heavily.Serranid
@Serranid I often had problems when one git commit contains a lot of changes to a file as well as it's rename. This often happens when developers squash a lot of commits. I usually prefer to either rename or change a file in one commit. Of course in some languages like Java a move will also change the source file's content since there is a package declaration, but this is a small content change and git can easily track it.Encomiast
@RenéLink Yep, small commits are key. I basically squashed only those commits containing no renames after posting my last comment.Serranid

© 2022 - 2024 — McMap. All rights reserved.