我想在 Git 中重命名 / 移动项目子树,将其从
/project/xyz
至
/components/xyz
如果我使用普通的git mv project components
xyz project
所有提交历史记录都将丢失。有什么办法可以移动历史记录吗?
Git 会检测到重命名,而不是通过提交保留操作,因此无论您使用git mv
还是mv
都无关紧要。
log
命令采用--follow
参数,该参数在重命名操作之前延续历史记录,即,它使用启发式搜索相似的内容:
http://git-scm.com/docs/git-log
要查找完整的历史记录,请使用以下命令:
git log --follow ./path/to/file
简短的答案是 “否” 。无法在 Git 中重命名文件并记住历史记录。这是一种痛苦。
有传言说git log --follow
--find-copies-harder
可以工作,但即使文件内容更改为零,并且对git mv
进行了移动,它也对我不起作用。
(起初,我使用 Eclipse 在一个操作中重命名和更新程序包,这可能会使 Git 感到困惑。但这是很常见的事情--follow
的确在仅mv
然后执行commit
和mv
不太远。)
Linus 说,您应该全面了解软件项目的全部内容,而无需跟踪单个文件。好吧,可悲的是,我的小脑无法做到这一点。
如此多的人无意识地重复了 Git 自动跟踪移动的说法,这真是令人讨厌。他们浪费了我的时间。 Git 没有这样的事情。 根据设计(!),Git 根本不会跟踪移动。
我的解决方案是将文件重命名为其原始位置。更改软件以适合源代码管理。使用 Git,您似乎只需要在第一时间正确进行 “git” 操作即可。
不幸的是,这破坏了 Eclipse,后者似乎使用了--follow
。 git log --follow
有时不显示具有复杂重命名历史记录的文件的完整历史记录,即使git log
可以显示。 (我不知道为什么。)
(有一些非常聪明的 hacks 可以返回并重新提交旧工作,但是它们相当令人恐惧。请参阅 GitHub-Gist: emiller / git-mv-with-history 。)
简而言之:如果Subversion 这样做是错误的,那么 Git 这样做也是错误的 - 这样做不是某些功能(错误!),这是一个错误。
可以重命名文件并保持历史记录完整,尽管这会导致在存储库的整个历史记录中重命名文件。这可能仅适用于痴迷 git-log-lovers 的人,并且会产生一些严重的影响,包括:
现在,由于您仍在我身边,您可能是一个重命名完全隔离的文件的单独开发人员。让我们使用filter-tree
移动文件!
假设您要将old
文件移到文件夹dir
并命名为new
这可以用git mv old dir/new && git add -u dir/new
,但这打破了历史。
反而:
git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD
将重做分支中的每个提交,在每次迭代的滴答声中执行命令。当您这样做时,很多东西都会出错。我通常会测试文件是否存在(否则该文件尚未移动),然后执行必要的步骤来拔出我喜欢的树。在这里,您可能会遍历文件以更改对该文件的引用,依此类推。把自己打昏! :)
完成后,文件将被移动并且日志保持不变。你觉得自己像个忍者海盗。
还; 当然,只有将文件移动到新文件夹时,才需要 mkdir dir。如果使用 if,将避免在历史记录中早于文件存在创建此文件夹。