如何将git repo中的单个文件拆分为新的repo?

时间:2016-09-13 21:20:18

标签: git

我有一个包含多个目录的git repo和一个文件MyFile.ext

/
  LargeDir1/
  LargeDir2/
  LargeDir3/
      .
      .
      .
  MyFile.ext

我想开始一个只有MyFile.ext的新回购,并保留所有与之相关的历史记录,但忽略其他一切(所有LargeDir s)。我怎么能这样做?

对于目录,我已成功使用this answer,但我在单个文件上尝试过,但它无法正常工作。

我还尝试了this answer,它会删除除我的文件以外的所有内容,但它似乎也会留下所有历史记录。

3 个答案:

答案 0 :(得分:12)

使用git fast-export

首先,您将文件的历史记录导出到快速导入流。请确保在master分支上执行此操作。

cd oldrepo
git fast-export HEAD -- MyFile.ext >../myfile.fi

然后您创建一个新的仓库并导入。

cd ..
mkdir newrepo
cd newrepo
git init
git fast-import <../myfile.fi
git checkout

答案 1 :(得分:0)

我有同样的问题,我终于明白了。我有一个旧的旧脚本目录 - 这么老,它们最初都受RCS控制。几年前,我把它变成了一个git repo(我真的不知道我在做什么),然后我转换了RCS日志并更新了git日志。但我选择了其中一个脚本的开发并决定它需要自己的回购。那里的各种解决方案(子树和过滤器分支)取决于您要拆分为目录的部分。您可以将该文件放在一个目录中并将其拆分,但是您没有获得它的修订历史记录。所以这就是我如何弄清楚如何提取单个文件的修订历史并用它创建一个新的回购:

  1. 创建一个分支新的仓库[我在与源仓库相同的水平上做了]

    git init <new-repo>
    
  2. 现在进入你的源代码库并创建一个我们稍后将用来挑选文件提交的文件:

    cd <source-repo>
    git log --reverse <target-file.ext> | \
        grep ^commit | cut -d ' ' -f 2 | cut -c 1-7 | \
        perl -ne 'print("pick $_")' > ../commits-to-keep.txt
    
  3. 创建一个临时分支并将其推送到新的仓库(然后将其删除)

    git checkout -b tmpbranch
    git push ../new-repo tmpbranch
    git checkout master
    git branch -d tmpbranch
    
  4. 现在转到你的新回购并创建一个空的提交,我们将改变:

     cd ../<new-repo>
     git commit --allow-empty -m 'root commit'
     git rebase --onto master --root tmpbranch -i
    
  5. [唯一的手动步骤]在上面最后一个命令的编辑器中,删除所有内容并粘贴您之前创建的文件的内容:../ commices-to-keep.txt

  6. 现在您可以切换回主分支,合并,然后清理临时分支:

     git checkout master
     git merge tmpbranch
     git branch -d  tmpbranch
    
  7. 这里唯一的缺点是你最终得到了额外的空根提交。我发现有一些方法可以删除它,但就我的目的而言,这已经足够了。

答案 2 :(得分:0)

  1. 克隆回购。
  2. 过滤掉除一个文件以外的所有内容。
  3. 克隆可以通过git clone正常完成。这在git clone /path/to/the/repo这样的目录上可以正常工作。然后删除远程指向回克隆。

    git clone /path/to/the/repo
    git remote rm origin
    

    然后使用git filter-branch过滤除一个文件以外的所有内容。使用索引过滤器删除所有文件,然后只恢复一个文件,这是最容易实现的。

    git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- YOURFILENAME
    

    索引过滤器的工作原理是检查每个单独的提交,并进行所有更改。您正在运行此命令,然后重新启动它。它首先从暂存中删除所有更改,然后将该文件还原到该提交中的状态。 $GIT_COMMIT是要重写的提交。 YOURFILENAME是您要保留的文件。

    如果您使用--all执行所有分支和标记,请添加标记过滤器以确保重写标记。这就像--tag-name-filter cat一样简单。它不会改变标签的内容,但会确保它们被转移到重写的提交。

    最后,您需要--prune-empty删除任何不涉及该文件的空提交。会有很多。

    这就是一起。

    git filter-branch \
        --index-filter 'git rm --cached -qr -- . && git reset -q $GIT_COMMIT -- YOURFILENAME' \
        --tag-name-filter cat
        --prune-empty \
        -- --all