如何从我的主存储库子树上的子项目中变基一个“过滤器分支”?

How to rebase a `filter-branch` from a subproject on my main repository's subtree?

如何从我的主存储库子树上的子项目变基 filter-branch

对我来说,这是对子模块执行的正常操作。我只想按照此处所述进行正常的变基:Rebasing everyone onto changed git history after filter-branch

我所做的操作是在我的子项目上,在它自己的存储库上。这是操作:

git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch "some_folder/path" -r -f' \
--prune-empty --tag-name-filter cat -- --all

之后我将更改推送到子项目自己的存储库:

git push origin --force --all
git push origin --force --tags

现在我想将更改集成到我的主存储库中,其中我的子项目是一个子树。所以,这不是一个普通的存储库。为什么我在 git 子树上看不到变基选项?

解决这个问题的方法只有这个:git subtree: possible to change subtree branch/path in a forked repository?,要删除它并重新添加它吗?

尝试

做的时候:

git subtree pull --prefix=subprojectFolder subprojectRemoteRepository.git 

输出为:

 * branch            master     -> FETCH_HEAD
fatal: refusing to merge unrelated histories

使用git subtree merge

git remote add subproject_remote subprojectRemoteRepository.git
git fetch --no-tags
git checkout master
git subtree merge --prefix=subprojectFolder subproject_remote/master

fatal: refusing to merge unrelated histories

如何使它们相关联?

--allow-unrelated-histories 只会导致:

error: unknown option `allow-unrelated-histories'
usage: git subtree add   --prefix=<prefix> <commit>
   or: git subtree add   --prefix=<prefix> <repository> <ref>
   or: git subtree merge --prefix=<prefix> <commit>
   or: git subtree pull  --prefix=<prefix> <repository> <ref>
   or: git subtree push  --prefix=<prefix> <repository> <ref>
   or: git subtree split --prefix=<prefix> <commit...>

我现在正在应用这个解决方案,而没有更方便的东西。

第 1 部分

  1. 克隆 subproject dedicated repository 并在其上结帐。
  2. 按照我喜欢的方式执行 filter-branch 操作。
  3. 执行 git push origin --force --all 和标记。

第 2 部分

  1. 克隆 main project 存储库并检出它。
  2. 要执行与 第 1 部分 完全相同的 filter-branch,并删除当前的子项目树,或使用 bfg-repo-cleaner 与:

    git clone --mirror mainRepository.git
    java -jar bfg.jar --no-blob-protection --delete-folders 'subprojectFolder' mainRepository.git
    cd mainRepository.git
    git reflog expire --expire=now --all && git gc --prune=now --aggressive
    git push origin --force --all
    git push origin --force --tags
    cd ..
    rm -r mainRepository.git
    

第 3 部分

  1. 终于读取刚刚清理过的子树:

    git clone mainRepository.git
    cd mainRepository
    git checkout master
    git subtree add --prefix=subprojectFolder subproject.git master
    git push
    
  2. 告诉大家Rebasing everyone onto changed git history after filter-branch你的主项目,以及子项目的专用克隆,如果有的话。

结束

  1. 请注意,目前使用 bfg-repo-cleaner,只有在主项目上没有其他文件夹与子项目名称相同的情况下,您才能删除该文件夹。这是因为 BFG 将删除所有匹配 subprojectFolder 名称的文件夹。指定文件夹路径的功能仍在开发中:How to delete one folder/directory using BFG repo cleaner?。否则您可以使用 filter-branch 删除项目的 subtree.

  2. 要完全删除内容,请在完成存储库中的 filter-branch(s) 后,从另一个答案 Why is my git repository so big? 中执行此操作:

    rm -Rf .git/refs/original && \
        git reflog expire --expire=now --all && \
        git gc --aggressive && \
        git prune
    
  3. 要列出最大的文件,请使用:

    git rev-list --all --objects | \
        sed -n $(git rev-list --objects --all | \
        cut -f1 -d' ' | \
        git cat-file --batch-check | \
        grep blob | \
        sort -n -k 3 | \
        tail -n40 | \
        while read hash type size; do 
             echo -n "-e s/$hash/$size/p ";
        done) | \
        sort -n -k1
    
  4. 从另一个答案 How to remove unreferenced blobs from my git repo 中,您可能希望在 filter-branch 拉取之后执行此操作。记得看原文哦

    git tag | xargs git tag -d && \
    git remote rm origin && \
    rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/ && \
    git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d && \
    git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 \
        -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"