【问题标题】:Remove a file from whole git history从整个 git 历史记录中删除文件
【发布时间】:2018-09-25 17:02:36
【问题描述】:

我知道已经有人问过这个问题,但是在每个答案中,我发现情况与我的情况略有不同,我不知道如何适应它。

那么问题来了:

我克隆了一个存储库并添加了一个文件夹以在其中工作。在这个文件夹中,我添加了 .csv 文件和使用 csv 文件的 .py 文件。 我试图推动这一点,但意识到这需要很长时间,因为 2 个 csv 文件非常大。所以我

git rm files

然后提交。我尝试再次推送,然后才意识到删除文件不会将其从 git 历史记录中删除。// 所以现在,从上次完成的推送中,我有 2 次提交:1 次我添加了文件,1 次我删除了一些 .csv。

我希望您能帮助我删除最后 2 个提交。这可行吗? 谢谢

【问题讨论】:

    标签: git commit git-rm


    【解决方案1】:

    我发现git filter-branch 文档中的第一个示例非常适合您的上下文。看看(source):

    假设您想从所有提交中删除一个文件(包含机密信息或侵犯版权):

    git filter-branch --tree-filter 'rm filename' HEAD
    # and see also the variant further in the example description
    git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
    

    (请参阅文档页面上的详细信息,我没有在这里复制粘贴整个内容)

    【讨论】:

      【解决方案2】:

      filter-branch,正如我们所建议的那样,如果我们谈论的是 biiiig 历史,那很好。如果我们只讨论少数几个修订版,您可以通过修改添加文件的修订版和樱桃挑选或 rebase 交互式来做到这一点(删除文件)。

      一个例子.....说我在master~2上添加了文件a.txt。我不想再让它载入史册了。

      git checkout master~2 git rm --cached a.txt git commit --amend --no-edit git cherry-pick master~2..master git branch -f master # point master in this revision git checkout master

      应该够了。

      【讨论】:

        【解决方案3】:

        ...我想...删除最后 2 个提交。这可行吗?

        你不能完全删除提交,但你可以很容易地告诉 Git 忘记它们。

        最后,它的工作方式非常简单。我们首先注意到每个提交都会保存一个快照,并且还存储其 提交的哈希 ID(以及您的提交日志消息和您作为作者的姓名等)。这形成了一个向后指向的提交链。

        如果我们让单个大写字母代表提交哈希 ID,我们可以绘制这个链:

        ... <-F  <-G  <-H   <--master
        

        请注意,分支名称,在本例中为master,将last 提交的哈希ID 存储在链中。 (当某个东西存储了提交的哈希 ID 时,我们说这个东西 指向 提交,因此是箭头。名称 master 指向 HH 指向 @987654326 @,等等。)

        Git 找到这些提交的方法是从master 中读取H 的哈希ID,它定位到提交H,然后读取提交H 并显示它。然后,在读取H 后,Git 的哈希 ID 为提交 G,因此 Git 可以读取 G 并显示它,依此类推。

        当我们进行新的提交时,Git 实际上会这样做:

        • 写出快照;
        • 写出作者和日志信息等;
        • new 指向 current 提交;
        • 最后也是最重要的,将 new 提交的哈希 ID 写入分支名称。

        如果我们有:

        ...--F--G--H
        

        我们添加了--I:

        ...--F--G--H--I
        

        然后 Git 更改了 name master 以存储提交 I 的哈希 ID。最终我们有:

        ...--F--G--H--I--J   <-- master
        

        如果我们做了几个不需要的提交,我们可以告诉 Git:重新设置名称 master 指向提交 H 而不是提交 J 有几种方法可以做到那个,但在这种情况下,第一个要达到的是git reset --hard(虽然我们已经检查了master,并确保你没有任何担心丢失的东西,因为git reset --hard告诉Git扔掉所有东西):

        git checkout master
        git reset --hard HEAD~2
        

        ~2 后缀告诉 Git 倒数两步——从技术上讲,两个 第一父级 步,这在我们的链中有一些合并提交时很重要,但在这里,我们没有不要紧。如果 master 当前指向 J,那么 Git 会倒数两次:JI,然后是 IH。然后,Git 用来自提交 H 的内容替换我们的工作 并且 使名称 master 指向 H 而不是 J

                     I--J
                    /
        ...--F--G--H   <-- master
        

        现在J 很难找到,它似乎被删除了。

        这样做的缺点是,如果我们让我们的 Git 告诉其他 Git:在这里,复制提交 IJ 其他 Git 有两个提交和即使在我们的 Git 忘记了它们之后,它们也会重新引入到我们自己的 Git 中。但是,如果我们从未在其他任何地方成功发送过这两个提交,那么我们是唯一拥有它们的人,所以如果 我们忘记它们,它们就如同消失了一样.

        (如果我们推送了它们,我们可以拥有我们的 Git,他们的 Git,以及所有其他的 Git从那时起,all 忘记它们,然后然后它们就会消失。但显然这很快就会变得困难。)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-12-05
          • 2014-06-19
          • 2020-03-20
          • 1970-01-01
          • 1970-01-01
          • 2017-10-01
          • 1970-01-01
          • 2019-03-17
          相关资源
          最近更新 更多