问题
I want to restructure my files and folders in Git repo without losing the Histories.
The current Git repo has been migrated from SVN and it has got the SVN histories in it.
Now, when I try to move the files around the Git repo, I am losing the current Git history, but I have the old SVN histories which got migrated from SVN. But, I want to have all the histories when I move the files and folders.
I have tried git mv, log --follow, just cut and paste, etc... but nothing keeps track of the new Git histories.
I am confused from various answers around the internet. Nothing works for me unfortunately. :(
Any suggestion?
Thanks, Vashni
回答1:
Git does not track file history.
Git does track content, and keeps commit history.
What this means is that if you have some existing commits, and then you move files around and make new commits with existing commits as their history, the new commits have the old commits as their commit history.
The moved-around files have no history, but the old files had no history either. When you use git log
you are looking at commit history, starting with whichever commit you name—if you do not specify a starting commit, git log
starts with HEAD
—and working back from there, to older commits.
This is true even if you use git log -- path
: you are still looking at commit history. You have simply instructed git to show you just a subset of commit history, namely, commits where path
has changed between that commit and its predecessor commit. That is, if you see commit 1234567
in the log, this means that git diff --name-status 1234567^ 1234567
would show you a change in the status of the file named by path
(among any other name-and-status changes).
(The syntax commit^
, which is any valid name for a commit followed by a single ^
character, means to find the commit's parent, i.e., the commit that was current just before commit
was made. You can also write this as commit~1
.)
When you add --follow
(and name a single path
), this tells git log
one more thing: if the status change for the given path
is a rename, git log
can change the way it looks at previous commits. We already know that, since git log
is showing you this commit, the git diff
will show a name-and-status for that file. In most cases the status for the file will just be M
, indicating that the file existed before and was modified. But if the status is R
, this indicates that git diff
calculated that between the parent commit and this commit, the file was renamed.
Without --follow
, git log
will probably no longer see the named path
(because the diff computed it as having been renamed), and will stop showing commits. (It may pick up again with even-earlier commits if some other content has the same path in those earlier commits, but this depends on the earlier commits, and is not all that common.) With --follow
, however, git log
takes note of the fact that git diff
decided, when it made the diff just now, that the file had been renamed. It then stops looking for path
under that name, and starts looking instead for the path that git diff
decided the content had been renamed from.
That is, suppose that git log
compares older (parent) commit ab93513
to newer (child) commit 0cea944
. Suppose further that git diff
decides that the contents of dir1/dir2/old.txt
in commit ab93513
became instead the contents of file dir8/dir9/new.txt
. And, finally, suppose that you asked git log
to show you dir8/dir9/new.txt
with the --follow
option. Then, since the change git diff
computes at this point is "contents similar, rename occurred", git log
switches from looking for dir8/dir9/new.txt
to looking for dir1/dir2/old.txt
.
The key to this process is rename detection. Since git does not track file history, it must detect the rename. Rename detection is pretty reliable, but not perfect—and it depends on how you configure git, and whether the contents of files match exactly or merely "sufficiently similarly". And --follow
, in git log
, only follows one path at a time (and only backwards through history—this really should work when using --reverse
, but the code is that implements --follow
is a horrible hack and only works in one time direction).
来源:https://stackoverflow.com/questions/36563500/moving-files-in-git-repository