2016-01-31 171 views
0

在git中,如何删除和重命名文件,从某个分支中的某个提交开始,同时保留每个文件(删除和重命名)的更改历史记录?如何删除历史记录中的删除和重命名?

我的用例是我带了一个分支,并从那里开始一个新的分支,我删除了一些文件并重新命名了一些其他分支。然后我修改了其余的(并且经常重命名的)文件(还添加了一些文件)。现在我想恢复到原来的名称并恢复已删除的文件(这些文件仍然存在于公共基础上),同时保留所有内容的历史记录。我的最终目标是能够合并回原始分支(所以without the renames and file deletions that I introduced)。

可以这样做吗?我想知道这是多么容易,尤其是因为重命名的文件被修改(如此天真地删除重命名将切断原始文件和修改之间的历史链接,我反而想保留)...

PS:变化因为分支分支很广泛(至少在“清洁”分支上)。

+0

Git不会跟踪文件名的历史。这是一个内容跟踪器;它会在运行时计算来自deltas的文件名更改。 –

+0

“*由于重命名的文件被修改得如此天真,删除重命名将切断原始文件和修改之间的历史链接*”这不一定是真的。 Git甚至可以通过文件修改来计算重命名。此外,如果您使用正常提交将文件重命名为原始名称,您的分支应该合并正常。 – Schwern

回答

2

您不必重写历史记录即可进行合并工作。您可以恢复重命名并重新引入已删除的文件,然后进行提交和合并。使用git mv重新命名文件。删除的文件可以使用git checkout <rev-which-deleted-the-file>^ -- <filename>恢复。 See this answer for details

删除并重新命名的文件可以使用git-log--diff-filter找到。

Git不存储重命名,它用一些启发式方法计算它们以处理小编辑。 git-loggit-diffgit-blame都像-C-M选项来控制的Git如何努力找到复制和重命名(移动)文件。所以历史的连续性不一定会被分支中的重新命名所遗失。


如果你真的想重写历史,第一次发现使用git log --diff-filter=D master..branch其删除文件的所有更改。然后,您可以使用git rebase -i来更改这些提交并恢复已删除的文件。

重复写是有点棘手,因为你必须撤消重命名,然后重命名该文件在以后的每个承诺。这是git-filter-branch的工作,它可以对一系列提交应用相同的更改。

git filter-branch --tree-filter 'if [ -f new ]; mv new old; fi' master..branch 

--tree-filter运行外壳命令上的每个提交数据并改变了由添加和删除文件在必要时提交。

和以前一样,找到你的重命名使用git log --diff-filter=R master..branch

+0

谢谢。我使用了第一种方法(无历史重写):'git mv'和'git checkout ...'用于删除文件。然后我将每个分支合并到另一个分支(并检查更新)。不知怎的,一个文件的历史记录从'git log'中消失了许多。但是,它确实出现在拉取请求中。有没有办法获得这样的历史? – EOL

+0

@EOL我不确定你的意思。作为一个新问题,这会更好。 – Schwern

+0

为了完整:我从'master'重命名一个文件:'git mv old_name.txt new_name.txt',以便它匹配来自其他分支('production')的名称。合并'production'后,我在'git log new_name.txt'时没有看到'new_name.txt'的完整更改历史记录。现在我意识到必须执行'git log --follow new_name.txt'才能遵循重命名和列表更改。感谢您的反馈意见。 :) – EOL

0

您可以尝试在分支点为违规分支做一个git rebase -i。为了安全起见,我首先在要破解的分支尖端创建一个新分支,以防万一(哈!墨菲定律无情)出现问题。

如果变化是非常广泛的,有办法自动执行此,但这是更加前途未卜。有关详细信息,请参阅Pro git book

+0

我相信'git rebase -i'的问题是,如果您在一次提交中撤消重命名,则任何更改了重命名文件的提交都将导致冲突或导致文件副本出现。 – Schwern

+0

@Schwern,“不要删除文件”是什么原因导致冲突,如果一些稍后提交重新创建它。你必须决定你想要什么,没有办法, – vonbrand

+0

谢谢。不幸的是,这些变化很... – EOL

相关问题