2

我的仓库中有几个子树(例如./sub1/,,./sub2/..),我想将它们提取到单独的仓库中,保持提交历史和相同的目录结构,即一个新的仓库sub1应该有./sub1/来自主仓库的子树。我怎样才能做到这一点?

4

1 回答 1

5

您可以将 git 的过滤器分支与子树过滤器一起使用。

以下是步骤:

  1. 克隆工作副本。此操作将更改本地 repo,因此我们必须首先有一个工作副本。你可以像下面那样做一个 git clone 或者只是复制它。

    git clone --no-hardlinks <original repository> <working copy>
    
  2. 使用子树过滤器。

    cd <working copy>
    
    git filter-branch --subdirectory-filter <subdir path to be splited> --prune-empty --tag-name-filter cat -- --all
    
    # reset current working directory
    git reset --hard
    
  3. 我们已经完成了我们的任务,最好做一些清理工作,因为很多旧对象变得无法访问。

    1. 删除旧遥控器

      git remote rm origin
      
    2. 删除旧的 reflog

      # clean unneeded reflog in order to free space
      refbak=$(git for-each-ref --format="%(refname)" refs/original/)
      if [ -n "$refbak" ];then
          echo -n $refbak | xargs -n 1 git update-ref -d
      fi
      git reflog expire --expire=now --all
      
    3. 重新打包并压缩 repo

      # prune loose objects
      git gc --aggressive --prune=now
      

这将使回购结构从

repo/
    |-- sub1/
        |-- sub11
        |-- sub12
    |-- sub2

repo/
    |-- sub11
    |-- sub12

但是,看起来你希望它变成

repo/
    |-- sub1/
        |-- sub11
        |-- sub12

然后,还需要做一个步骤,用 index-filter 重写 git commit 历史。

# replace <subdir path> with the actual subdir path, for this case, it should be "sub1"
git filter-branch --index-filter 'git ls-files -s | sed "s-\t-&<subdir path>/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
于 2012-10-10T11:41:06.327 回答