在Git存储库中移动文件 [英] Moving Files in Git Repository

查看:43
本文介绍了在Git存储库中移动文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在Git存储库中重组我的文件和文件夹,而不会丢失历史记录.

当前的Git存储库已从SVN迁移而来,并且其中包含了SVN的历史记录.

现在,当我尝试在Git存储库中移动文件时,我正在丢失当前的Git历史记录,但是我有从SVN移植过来的旧SVN历史记录.但是,当我移动文件和文件夹时,我想拥有所有的历史记录.

我尝试了git mv,log --follow,只是剪切和粘贴等操作,但是没有什么可以跟踪新的Git历史.

我对互联网上的各种答案感到困惑.不幸的是,没有任何东西对我有用.:(

有什么建议吗?

谢谢,瓦什尼

解决方案

Git不跟踪文件历史记录.

Git 执行跟踪内容,并保留 commit 历史记录.

这意味着,如果您有一些现有的提交,然后在文件中移动并使用现有的提交作为历史记录进行新的提交,则新的提交会将旧的提交作为其提交历史记录.

移动文件没有历史记录,但旧文件也没有历史记录.使用 git log 时,您会查看 commit history ,从您命名的任何提交开始-如果未指定起始提交,则 git log HEAD 开始,然后从那里返回到较早的提交.

即使您使用 git log- path ,也是如此:您仍在查看提交历史记录.您只是简单地指示git向您显示提交历史记录的一个子集,即,在该提交与其先前的提交之间 path 已更改的提交.也就是说,如果您在日志中看到commit 1234567 ,则表示 git diff --name-status 1234567 ^ 1234567 会向您显示文件状态的变化由 path 命名(在其他所有名称和状态更改中).

(语法 commit ^ ,它是提交的任何有效名称,后跟一个 ^ 字符,意味着可以找到该提交的父级,即刚进行 commit 之前的提交.您也可以将其写为 commit 〜1 .)

添加-follow (并命名一个 path )时,这会告诉 git log 一个还有一点:如果给定的 path 的状态更改是重命名,则 git log 可以更改其查看先前提交的方式.我们已经知道,由于 git log 向您显示此提交,因此 git diff 将显示该文件的名称和状态.在大多数情况下,文件的状态仅为 M ,表明该文件之前存在且已被修改.但是,如果状态为 R ,则表明 git diff 计算出在父提交和该提交之间,文件已被重命名.

没有-follow git log 可能不再看到命名的 path (因为差异计算为已重命名),并将停止显示提交.(如果某些其他内容在这些较早的提交中具有相同的路径,则它可能会使用更早的提交再次出现,但这取决于较早的提交,并且并不常见.) With -跟随,但是 git log 注意到 git diff 刚决定进行比较时决定文件已经被保存的事实.重命名.然后,它停止寻找该名称下的 path ,并开始寻找 git diff 决定内容已重命名为的路径.来自.

也就是说,假设 git log 将较旧的(父)提交 ab93513 与较新的(子)提交 0cea944 进行比较.进一步假设 git diff 决定提交 ab93513 中的 dir1/dir2/old.txt 的内容变为文件的内容dir8/dir9/new.txt .最后,假设您要求 git log 向您展示 dir8/dir9/new.txt -follow 选项.然后,由于此时 git diff 所做的更改是内容相似,发生了重命名",因此 git log 会从寻找 dir8/dir9/new.txt切换到查找 dir1/dir2/old.txt .

此过程的关键是重命名检测.由于git不跟踪文件历史记录,因此它必须检测.重命名检测是非常可靠的,但不是完美的方法-它取决于您如何配置git以及文件的内容是完全匹配还是仅足够相似"匹配.并且-follow (在 git log 中)一次只能遵循一个路径(并且只能追溯到历史记录,这在使用时确实有效)-reverse ,但是实现-follow 的代码是一种骇人听闻的技巧,仅在一个时间方向上起作用.

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

解决方案

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).

这篇关于在Git存储库中移动文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆