如何在运行git filter-branch后删除旧的历史记录? [英] How to delete the old history after running git filter-branch?

查看:208
本文介绍了如何在运行git filter-branch后删除旧的历史记录?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有这样的树:

  ...  -  a  -  b  -  c  -  d  - ... 
\
e - a - k

和I希望它变成正好

  ...  -  a  -  b  -  c  -  d  -  ... 

我知道如何将分支名称附加到e。我知道我要做的事情会改变历史,这是不好的。另外我想我需要使用类似rebase或filter-branch的东西。但是,究竟如何 - 我迷路了。



好的。情况如下:我现在有一棵相当大的树(像这样)

  s  -  p  -  r 
/
a - b - c - d - e - g - w
\\\
t - p - ly - k

但是在我第一次提交的时候(比如前面的b),我添加了二进制文件,这使得整个回购非常重。所以我决定把它们带走。我用filter-branch做了。现在我有两个长的分支,从第二次提交开始相互完全相同。

  s  -  p  -  r 
/
a - b - c - d - e - g - w
\\\\
\ t - p - ly - k
\
\ s' - p' - r'
\ /
b' - c' - d' - e' --- g' - w'
\\
t' - p' - l'y' - k'

其中b'是在没有二进制文件的情况下提交的。所以我不能合并。我不希望整棵树在历史上重复如此。

解决方案

导入具有多年历史记录的Subversion存储库后,我遇到了大量二元资产膨胀的类似问题。在 git:缩小Subversion导入中,我描述了从4.5 GiB修剪我的git repo假设您想从所有提交中删除 删除媒体文件(6fe87d),您可以调整从我的博客文章到您的回购的方法:

 $ git filter-branch -d / dev / shm / git --index-filter \ 
git rm --cached -f --ignore-unmatch media / Optika.1.3。 ?。*; \
git rm --cached -f --ignore-unmatch media / lens.svg; \
git rm --cached -f --ignore-unmatch media / lens_simulation。 swf; \
git rm --cached -f --ignore-unmatch media / v.html\
--tag-name-filter cat --prune-empty - --all

您的github回购没有任何标签,但我包含标签名称过滤器te标签。



git filter-branch 文档涵盖 - prune-empty 选项。



< blockquote>

- prune-empty

某些类型的过滤器会生成空提交不触摸树。这个开关允许 git-filter-branch 忽略这样的提交...


使用此选项意味着您的重写历史记录不会包含删除媒体文件提交,因为它不再影响树。媒体文件不会在新的历史记录中创建。



此时,由于存在另一个记录的行为


原始参考文献,如果不同从重写的那些中,将被存储在命名空间 refs / original / 中。

如果您对新重写的历史记录感到满意,请删除备份副本。

 $ git for-each-ref --format =% (refname)refs / original / | \ 
xargs -n 1 git update-ref -d

Git对保护您的工作保持警惕,所以即使在所有这些有意的重写和删除推荐日志是保持旧的提交活着。使用两个命令序列清除它们:

$ g $ ref $ exp $ - -prune = 0

现在您的本地存储库已准备就绪,但您需要将更新推送到GitHub。你可以一次做一个。对于一个本地分支,比如master,你可以运行
$ b $ $ p $ git push -f origin master

假设您没有本地issue5分支。您的克隆仍然有一个名为origin / issue5的ref,它跟踪您的GitHub存储库中的位置。运行 git filter-branch 也会修改所有的原始参考文件,因此您可以在没有分支的情况下更新GitHub。

<$ p $如果你所有的本地分支匹配它们在GitHub端的相应提交( ie / em>,没有unpushed提交),那么你可以执行批量更新。

 $ git for-each-ref --format =%(refname )refs / remotes / origin / | \ 
grep -v'HEAD $'| perl -pe's,^ refs / remotes / origin / ,,'| \
xargs -n 1 -I'{}'git push -f origin'refs / remotes / origin / {}:{}'



<第一阶段的输出是一个refname列表:

 $ git for-each-ref --format =%(refname)refs /远程/原产地/ 
参考/远程/原产地/头部
参考/遥控器/原产地/发行2
参考/遥控器/原产地/发行3
参考/遥控器/原产地/发行5
refs / remotes / origin / master
refs / remotes / origin / section_merge
refs / remotes / origin / side-media-icons
refs / remotes / origin / side-pane- splitter
refs / remotes / origin / side-popup
refs / remotes / origin / v2

我们不想要HEAD伪引用并使用 grep -v 将其删除。其余的,我们使用Perl剥离 refs / remotes / origin / 前缀,并为每一个运行一个形式命令

 $ git push -f原始参考/远程/原点/ BRANCH:BRANCH 


Suppose I have such tree:

... -- a -- b -- c -- d -- ...
             \
              e -- a -- k

and I want it become just

... -- a -- b -- c -- d -- ...

I know how to attach branch name to "e". I know that what I'm going to do will change history, and this is bad. Also I guess I need to use something like rebase or filter-branch. But how exactly - I'm lost.

Ok. Situation is following: I have rather big tree now (like this)

                 s -- p -- r   
                /
a -- b -- c -- d -- e --- g -- w
           \               \
            t -- p -- l     y -- k

but in my one of first commits (like to "b" for ex.) I added binary files, which makes whole repo very heavy. So I decided to take them away. I did it with filter-branch. And Now I have 2 long branches of commits identical to each other starting from second commit.

                 s -- p -- r   
                /
a -- b -- c -- d -- e --- g -- w
      \    \               \
       \    t -- p -- l     y -- k
        \
         \             s'-- p'-- r'  
          \           /
           b'-- c'-- d'-- e'--- g'-- w'
                 \               \
                  t'-- p'-- l'    y'-- k'

where b' is commit without binary file in it. So I can't do merge. I don't want this whole tree to be in history duplicated so.

解决方案

After importing a Subversion repository with multiple years of history, I ran into a similar problem with bloat from lots of binary assets. In git: shrinking Subversion import, I describe trimming my git repo from 4.5 GiB to around 100 MiB.

Assuming you want to delete from all commits the files removed in "Delete media files" (6fe87d), you can adapt the approach from my blog post to your repo:

$ git filter-branch -d /dev/shm/git --index-filter \
  "git rm --cached -f --ignore-unmatch media/Optika.1.3.?.*; \
   git rm --cached -f --ignore-unmatch media/lens.svg; \
   git rm --cached -f --ignore-unmatch media/lens_simulation.swf; \
   git rm --cached -f --ignore-unmatch media/v.html" \
  --tag-name-filter cat --prune-empty -- --all

Your github repo doesn't have any tags, but I include a tag-name filter in case you have private tags.

The git filter-branch documentation covers the --prune-empty option.

--prune-empty
Some kinds of filters will generate empty commits that leave the tree untouched. This switch allows git-filter-branch to ignore such commits …

Using this option means your rewritten history will not contain a "Delete media files" commit because it no longer affects the tree. The media files are never created in the new history.

At this point, you'll see duplication in your repository due to another documented behavior.

The original refs, if different from the rewritten ones, will be stored in the namespace refs/original/.

If you're happy with the newly rewritten history, then delete the backup copies.

$ git for-each-ref --format="%(refname)" refs/original/ | \
  xargs -n 1 git update-ref -d

Git is vigilant about protecting your work, so even after all this intentional rewriting and deleting the reflog is keeping the old commits alive. Purge them with a sequence of two commands:

$ git reflog expire --verbose --expire=0 --all
$ git gc --prune=0

Now your local repository is ready, but you need to push the updates to GitHub. You could do them one at a time. For a local branch, say master, you'd run

$ git push -f origin master

Say you don't have a local issue5 branch any more. Your clone still has a ref called origin/issue5 that tracks where it is in your GitHub repository. Running git filter-branch modifies all the origin refs too, so you can update GitHub without a branch.

$ git push -f origin origin/issue5:issue5

If all your local branches match their respective commits on the GitHub side (i.e., no unpushed commits), then you can perform a bulk update.

$ git for-each-ref --format="%(refname)" refs/remotes/origin/ | \
  grep -v 'HEAD$' | perl -pe 's,^refs/remotes/origin/,,' | \
  xargs -n 1 -I '{}' git push -f origin 'refs/remotes/origin/{}:{}'

The output of the first stage is a list of refnames:

$ git for-each-ref --format="%(refname)" refs/remotes/origin/
refs/remotes/origin/HEAD
refs/remotes/origin/issue2
refs/remotes/origin/issue3
refs/remotes/origin/issue5
refs/remotes/origin/master
refs/remotes/origin/section_merge
refs/remotes/origin/side-media-icons
refs/remotes/origin/side-pane-splitter
refs/remotes/origin/side-popup
refs/remotes/origin/v2

We don't want the HEAD pseudo-ref and remove it with grep -v. For the rest, we use Perl to strip off the refs/remotes/origin/ prefix and for each one run a command of the form

$ git push -f origin refs/remotes/origin/BRANCH:BRANCH

这篇关于如何在运行git filter-branch后删除旧的历史记录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆