Getting Git to Acknowledge Previously Moved Files

Git

Git Problem Overview


I've moved a bunch of files around manually without thinking, and can't find a way to get git to recognize that the files are just moved and not actually different files. Is there a way to do this other than removing old and adding the new (and thus losing the history), or redoing all the changes with git-mv?

Git Solutions


Solution 1 - Git

To have git remove files that are removed or moved already, just enter

git add -u

Solution 2 - Git

I think it already does this. Now, I could be wrong, but I've read that git tracks files based on their contents not based on their position in the file system or based on delta/differences. In the stack I think it shows it as if the files are being removed and the then re-added, but I think I've tried this once and it still maintained the history, due to the aforementioned way that git tracks things.

Still would be helpful for someone to verify if I'm correct or not. Sorry if I misunderstood your question.

Solution 3 - Git

git doesn't track the history of individual files and it doesn't treat moves and copies specially, that is there is no special metadata that indicates that a move or copy occurred. Instead each git commit is a complete snapshot of the working tree.

If you want to see moves in git log you can supply -M in addition to an option that lists which files have changed, e.g.

git log --summary -M

git will look at the adjacent trees in the commit history and infer if any files where moved by each commit.

To find copies as well as renames you can use the -C option, you can supply it twice to make git look harder for possible copy sources at the expense of some performance.

git log --summary -M -C -C

Note, that as git doesn't store file history (only commit history), even if you did git rm and git mv the file, you wouldn't lose any history. All changes to the path would still be recorded and visible in a git log.

Solution 4 - Git

To better understand why Git does do rename detection instead of (more common) explicit rename tracking, and how git log path limiting works, you can read read Linus's ultimate content tracking tool blog post by Junio C Hamano, maintainer of Git (and references therein).

Solution 5 - Git

You can move/rename the new file back to its old name and path outside of git and then use git mv to stage just the move; for example in bash:

mv $NEW $OLD && git mv $OLD $NEW

Its somewhat cumbersome1, especially if you have to do it by hand. But it has the advandage that it leaves other changes such as changing the namespace or the class name unstaged so that you can inspect them and only stage them when you intent to do so.


1 I hope to find a better alternative and will update my answer when I find it.

Example: I moved a bunch of files fom oldDir to newDir and started enthusiastically with some other changes. Now I want to check what other modifications were made. Using [tag:git] [tag:xargs] [tag:gawk] and [tag:bash] resulted in the following (on a single line):

git status --short |
gawk '/^\?\?/ && match($0, /newDir\/(*.\.cs)/, a) {print "newDir/" a[1] " " "oldDir/" a[1]}' |
xargs -n 2 bash -c 'mv $0 $1; git mv $1 $0'

Now git status shows the renames as "Changes to be committed" and the textual modifications under "Changes not staged for commit"

Solution 6 - Git

It happens to me, when I move and edit the file, it will no longer recognize it as moving file but a new one, so I lost history.

What I do it is to create 2 separated commits, one when I move the file, and then another editing the file. In this way I keep the history.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichaelView Question on Stackoverflow
Solution 1 - GitHugoView Answer on Stackoverflow
Solution 2 - GitJorge Israel PeñaView Answer on Stackoverflow
Solution 3 - GitCB BaileyView Answer on Stackoverflow
Solution 4 - GitJakub NarębskiView Answer on Stackoverflow
Solution 5 - GitKasper van den BergView Answer on Stackoverflow
Solution 6 - GitJaiderView Answer on Stackoverflow