删除一些最早的包含数据文件的提交

时间:2019-03-22 14:24:56

标签: git

我有一个远程git存储库。遥控器包含一堆提交。我错误地将数据集(数据文件将近3 GB)推到了远程。我想删除/删除一些最古老的提交,包括本地和远程存储库中的数据集,以减小存储库的大小。 git log --oneline打印:

993ebd6 last commit
cd882ce blah blah blah
...     ...
289a7dd blah blah blah
d750b6c data file ignored (added to .gitignore)
8005019 repo still includes data files
2a85665 repo still includes data files
83601d3 data added!
89b7a4a initial commit

我要删除包含数据文件(在d750b6c89b7a4a之间)的提交。我的意思是,它不仅需要删除提交,还需要删除相关提交中的文件。据我所知,git reset --hard确实会删除,但是它只会删除本地文件,并且在存在共享的远程存储库时会导致错误。

感谢您的帮助。

2 个答案:

答案 0 :(得分:0)

在没有--graph的情况下,git log --oneline省略了一些信息。此处省略的信息 可能很重要。 可能是,但这可能无关紧要。让我们假设它是相关的,并绘制它。

让我们看一下 Git存储了什么(关于 how 部分,现在不用太费神了)。无论如何,Git存储的内容都是 commits 。每个提交都包含所有文件的完整和完整快照-嗯,提交时Git的 index 中存在的所有文件。因此,您的大数据文件正在提交83601d3data added!)中。在提交2a856658005019中,。它也可能位于d750b6c(此处标记为data file ignored (added to .gitignore)的那个)中,因为在.gitignore中添加名称不会更改文件中是否存在文件 1 .gitignore中列出文件通常只是关闭git status,告诉它不要抱怨文件是否在工作树中,但不在文件树中。索引。

但是保存的快照不是提交中的“仅” 。每次提交还保存一些元数据-有关已保存快照的一些数据。例如,您所做的每个提交都有您的姓名和电子邮件地址。它具有您的日志消息-Git保存的有关您进行此提交的为什么的信息,以便您可以查看当时的想法。它有一个日期和时间戳记。而且,至关重要的是,它具有 parent 提交的哈希ID (例如83601d3(但长度为40个字符))。

Git通过这些哈希ID查找提交。实际上,ID是提交的真实名称。每个ID对于该特定提交都是唯一的。实际上,该ID是通过计算提交内容的内容上的冷冻散列而形成的-因此,这意味着子提交内容的 parent ID是该提交内容的关键部分孩子的身份。请记住,在您的脑后,我们花了一点时间来绘制以下提交链:

993ebd6 last commit
   ↓

cd882ce blah blah blah
   ↓
...     ...
   ↓

289a7dd blah blah blah
   ↓

d750b6c data file ignored (added to .gitignore)
   ↓

8005019 repo still includes data files
   ↓

2a85665 repo still includes data files
   ↓

83601d3 data added!
   ↓

89b7a4a initial commit

嵌入在每个提交中,换句话说,是一种向后箭头(在此垂直图中为向下箭头)。在有或没有--graph的情况下,向git log添加--oneline,使Git绘制相同类型的箭头/线条(主要使用竖线|连接*每次提交时都带有标记,而不隐含箭头方向)。

要实现的另一件事是,因为哈希ID对提交中的数据的每一位都非常敏感,例如,如果您尝试更改,例如,通过从文件中删除文件,您得到的不是更改提交,而是新的和不同的提交。新的提交可能更好,但具有不同的哈希ID。

因此,让我们用一个更好的新提交替换错误的提交83601d3。我们还不知道它的哈希ID是什么,但是我们仍然可以绘制它:

2a85665 repo still includes data files
   ↓
83601d3 data added!                       XXXXXXX improved: no extra data
   ↓                                         │
89b7a4a initial commit                 ←─────┘

所以...很好,但是现在我们也需要重新复制2a85665。无论如何,我们都会这样做,因为它仍然具有大文件,因此我们必须进行不包含它们的新改进的提交。新的和改进的2a85665 parent 将具有一些新的哈希ID YYYYYYYY

现在,我们也必须复制8005019,减去大文件。然后,由于这得到了一个新的哈希ID,因此我们也必须 也复制d750b6c,即使d750b6c没有大文件也必须复制d750b6c 。我们必须制作一个具有新哈希ID作为其父级的新副本。

复制了993ebd6之后,我们必须复制子级,以再次替换父哈希ID,如果没有其他要求的话。直到我们到达993ebd6为止,其他所有提交都会对此产生影响。复制完该副本后,我们将获得一个新链,该链以该新哈希值结束。我们让Git用最新的replace-commit的hash ID替换名称master(或您使用的任何分支名称)下存储的hash ID git rebase,实际上是“忘记”了原始的提交链。 / p>

此操作是对早期提交进行一些更改,然后在整个提交链中进行更改,然后使用新的改进版本复制并替换每个 git rebase -i可以做到。使用origin,您将有机会修复先前的提交,然后将所有后续提交复制到新的和改进的版本中。结果是形成了一个新的提交链,所有使用旧链的人(您在Git存储库中),以及所有其他拥有单独 Git存储库的人,例如{{1} }-需要切换到新链。对于您来说,这只是使用git push --force来更新origin上的遥控器的问题。


1 有关索引的更多信息,又名临时区域,有时甚至是缓存,请参阅其他描述Git构建方式的文章来自当时索引中的内容的新提交。这就是Git快照的产生方式:将苍蝇复制到索引中,然后运行git commit。 “复制到索引”步骤实际上是压缩文件并对其进行Git处理,使其准备好 提交。之后,Git继续从提交中取出经过Git验证的文件,并将其复制到索引中,以便它们准备好进入 next 提交。

文件在索引中的存在决定了文件是否被跟踪。您可以使用git rm --cached从索引中删除文件,而无需从工作树中删除文件:现在它已取消跟踪,即不在索引中,因此不会在 next 提交,除非您进行类似选择具有文件的现有提交的操作,以便Git再次将文件复制回索引中。

答案 1 :(得分:0)

我有一个似乎可行的示例。

据说我有仓库d1的提交master

* 20e4a1f added c.txt
* 79422f7 removed big file
* bc0d9c7 added b.txt
* 5b0c75d big file
* 5a8df10 initial

5b0c75d中添加了一个大文件,在79422f7中将其删除了。中间和之后发生了一些事情。

以下一组动作可以完成工作:

git checkout 5a8df10  -b update
git cherry-pick bc0d9c7 
git cherry-pick 20e4a1f 

现在创建另一个存储库“ d2”,并在其中添加新的早午餐。

cd ../d2
git init
git pull ../d1 update

现在您的d2存储库会更小。

当然,您需要解决所有冲突。但是git checkout --theirs在这种情况下似乎可以通用。

您肯定会丢失跳过的提交的历史记录。