GIT:如何将文件添加到第一次提交(并在此过程中重写历史记录)?

时间:2014-01-25 17:16:42

标签: git

我想将一个文件添加到git存储库,就像它从一开始就存在一样。我只找到了解释如何从整个历史记录中删除文件,而不是如何添加文件。

我试过了git filter-branch --tree-filter 'git add LICENSE.txt',但是我收到了无法找到该文件的错误。

3 个答案:

答案 0 :(得分:20)

git filter-branch 可以这样做,但可能比需要的重量轻得多。

你的历史有多大和分支?如果它很小又简短,最简单的方法是立即添加新文件,然后使用git rebase -i --root将新提交移动到第二个位置并将其压缩到根提交中。

例如,假设你有:

$ git log --oneline --graph --decorate --all
* e8719c9 (HEAD, master) umlaut
* b615ade finish
* e743479 initial

(您的SHA-1值当然会有所不同)并且您希望将LICENSE.txt(已在工作目录中)添加到树中作为根提交的一部分。你现在可以这样做:

$ git add LICENSE.txt && git commit -m 'add LICENSE, for fixup into root'
[master 924ccd9] add LICENSE, for fixup into root
 1 file changed, 1 insertion(+)
 create mode 100644 LICENSE.txt

然后运行git rebase -i --root。抓住最后一行(pick ... add LICENSE, ...)并将其移至第二行,将pick更改为fixup,然后写出rebase-commands文件并退出编辑器:

".git/rebase-merge/git-rebase-todo" 22L, 705C written
[detached HEAD 7273593] initial
 2 files changed, 4 insertions(+)
 create mode 100644 LICENSE.txt
 create mode 100644 x.txt
Successfully rebased and updated refs/heads/master.

(新的,完全重写的)历史现在看起来更像是这样:

git log --oneline --graph --decorate --all
* bb71dde (HEAD, master) umlaut
* 7785112 finish
* 7273593 initial

LICENSE.txt在所有提交中。


如果您确实有一个更复杂(多分支)的历史记录,并希望使用git filter-branch来更新所有内容,那么您需要的--tree-filter不是:

'git add LICENSE.txt'

而是:

'cp /somewhere/outside/the/repo/LICENSE.txt LICENSE.txt'

每次将新文件复制到树中。 (更快的方法是使用--index-filter,但这更复杂。)

答案 1 :(得分:6)

--index-filter提供了一个简单快速的解决方案:

git filter-branch --index-filter "cp /abs/path/to/LICENSE.txt . && git add LICENSE.txt"

这是一个针对其他提议方法的非常简单的基准。

第一列(large)显示Git项目存储库副本中每个过滤器的一次运行的时间(以秒为单位)(45885提交,结账约30M)。 rebase方法不适用,因为即使使用-c选项,它也不会自动处理合并。

第二列(medium)显示了中等大小的存储库副本中每个方法的三次运行的中位数时间,这些存储库具有线性历史和相当大的树(2430次提交,结账时间约为80M)。

第三列(small)显示了小型存储库副本中每个方法的三次运行的中位数时间(554次提交,结账时间约为100K)。

              large medium  small
index-filter   1064     38     10
tree-filter    4319     81     15
rebase            -    116     28

另请注意,rebase在功能上与filter-branch变体不同,因为它会更新提交日期。

答案 2 :(得分:0)

   --tree-filter <command>
       This is the filter for rewriting the tree and its contents. The
       argument is evaluated in shell with the working directory set to
       the root of the checked out tree. The new tree is then used as-is
       (new files are auto-added, disappeared files are auto-removed -
       neither .gitignore files nor any other ignore rules HAVE ANY
       EFFECT!).

请注意,您将从每个版本的新结帐开始。所以你想要的命令就像--tree-filter 'cp $HOME/LICENSE.txt .'我更喜欢torek的答案(使用rebase),除非你有这么多的修改,这是不切实际的。