【发布时间】:2014-01-25 17:16:41
【问题描述】:
我想将一个文件添加到 git 存储库,就好像它从一开始就在那里一样。我只找到了如何从整个历史记录中删除文件的说明,而不是如何添加文件的说明。
我尝试了git filter-branch --tree-filter 'git add LICENSE.txt',但我收到了找不到文件的错误。
【问题讨论】:
标签: git
我想将一个文件添加到 git 存储库,就好像它从一开始就在那里一样。我只找到了如何从整个历史记录中删除文件的说明,而不是如何添加文件的说明。
我尝试了git filter-branch --tree-filter 'git add LICENSE.txt',但我收到了找不到文件的错误。
【问题讨论】:
标签: git
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,但这更复杂。)
【讨论】:
--index-filter 提供了一个简单快速的解决方案:
git filter-branch --index-filter "cp /abs/path/to/LICENSE.txt . && git add LICENSE.txt" --tag-name-filter cat --prune-empty -- --all
这是一个针对其他建议方法的非常简单的基准。
第一列 (large) 显示了 Git 项目存储库副本中每个过滤器的一次运行时间(以秒为单位)(45885 次提交,约 30M 检出)。 rebase 方法不适用,因为它不会自动处理合并,即使使用 -c 选项也是如此。
第二列 (medium) 显示了在具有线性历史和相当大的树(2430 次提交,约 80M 签出)的中型存储库副本中每种方法运行 3 次的中值时间。
第三列 (small) 显示了在小型存储库副本中每种方法运行三次的中位时间(554 次提交,约 100K 检出)。
large medium small
index-filter 1064 38 10
tree-filter 4319 81 15
rebase - 116 28
另请注意,rebase 在功能上不等同于 filter-branch 变体,因为它会更新提交者日期。
【讨论】:
-- --all 附加到命令。
-- --all,它对我有用。非常感谢!顺便说一句,git docs说--分隔了路径和修订。
--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),除非你有太多的修订,这是不切实际的。
【讨论】: