42

I have a git repo, and currently I'm the only one using it. I want to take all the files and folders under the root folder, and put them inside a new folder.

Current structure:

main ->
  src
  res

New structure:

main ->
  app1
    src
    res

Is there a way I can do that so that the files don't lose their git history?

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
Chen Kinnrot
  • 20,609
  • 17
  • 79
  • 141
  • 3
    [This answer](http://stackoverflow.com/a/2314757/359059) shows you how to see history before rename/move. – jlilja May 31 '12 at 06:18
  • just do `git add -A .` after you have moved folder/files. Make sure you don't do any edits. – IsmailS Aug 21 '14 at 15:09
  • 1
    Similar question http://stackoverflow.com/questions/2314652/is-it-possible-to-move-rename-files-in-git-and-maintain-their-history – Michael Freidgeim Jan 25 '16 at 21:14
  • I had some similar problems. All answers seem to be missing some details, but did help me figure it out. I had to mkdir, git add {directory}, git mv ..., git commit, then check the old histories with git log --follow filename. Telling git to add the new directory before moving files into it made a big difference, even though it was empty and git status didn't show it before or after. (This should be the answer, but I'm not going to try to add a new answer 4 years later.) – Kenny Ostrom Jun 15 '16 at 21:20
  • 1
    @Kenny Ostrom not true, `git add {empty directory}` is a NOOP. Anyways, it *sucks* to have to use `--follow` just because we moved files – rfabbri Nov 06 '16 at 22:44

4 Answers4

56

TL;DR

Go ahead: move your files and directories around. Just make sure you don't make any edits to files in the same commit as your directory restructuring.

Why It Works

Git is a content tracker, not a file tracker. If you move/rename files, but make no other changes to the content of those files, then Git just rewrites the tree objects. The file blobs are not changed by directory operations; directory location information is stored separately in tree objects.

Actual rename detection is handled by diffing the blobs and trees, and looking for a configurable percentage of similarity between files. This means that Git doesn't really store moves or renames directly; it computes them from differences between commits.

The upshot of all this is that your history is not tied to a particular filename or directory structure. This works really well for most use cases, but stands in contrast to systems like Bazaar that track renames as first-class operations.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • When renaming a parent, I lose the history on the child files? – Cian Jul 29 '14 at 13:57
  • @Cian You either didn't understand the answer, are doing something wrong, or have an unusual edge case. You should open a new question with as much detail and supporting evidence as you can provide. – Todd A. Jacobs Jul 29 '14 at 14:08
  • I may have a strange case, or have misunderstood - I'll take a look in more detail and post a Q. Cheers – Cian Jul 29 '14 at 15:10
  • Git only detected renames done with git mv, for me. Furthermore, since the original question involved a mkdir (and my problem was similar), I had to git add {empty directory name} before moving files. – Kenny Ostrom Jun 15 '16 at 21:23
  • @CodeGnome git does track changes and movements. I did a small check and it seems it works. You can check this commit https://github.com/aoancea/git-history/commit/5ee8487733771a714e4b374b38b5db762d406ee1 – alexo Jul 10 '16 at 07:37
  • For clarity: do you move your files and directories around using `git mv` or simply `mv`? If I use `git mv` and commit, git log only shows the last commit for any given file. If I use `mv`, git status shows deleted files. – AstroFloyd Apr 10 '18 at 15:41
7

You can just move the files and Git will (or should) notice that the move has happened. It will keep the history.

If it doesn't notice the move for some reason you could try using the diff with --find-copies-harder option.

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Cameron Skinner
  • 51,692
  • 2
  • 65
  • 86
  • 1
    This answer is correct. Git can help you a bit if you do `mkdir app1 && git mv src res app1 && git commit`. Assuming you actually have some files in both `src` and `res` (if not, git ignores the empty dirs). – Adam Monsen May 31 '12 at 06:17
3

When I moved or renamed some files, I lost histories too. But I was trying to reach on TortoiseGit and SourceTree application.

When I tried to reach on git bash command, I figure out that I can see the history.

$Git log

After spending a couple of hour on the internet about the reason, Finally, I found my answer.

Tortoise git default settings, showing us just actual files history. I meant, if you rename of if you move any file or folder, you can not see history. For the seeing history, you have to click below check box on the TortoiseGit settings.

enter image description here

Mahmut EFE
  • 5,137
  • 5
  • 46
  • 56
0

Though this is an older question, I have experienced the marked answer as incorrect. Any folder moves using native commands will result in a "delete" and "add". However, git mv is what you would want to use.

https://git-scm.com/docs/git-mv

In the above case, it would be

git mv "main\src" "main\app1\"