【问题标题】:Moving part of a git repository’s history into another repository将 git 存储库的部分历史记录移动到另一个存储库
【发布时间】:2011-06-30 23:55:45
【问题描述】:

这里有很多关于使用git filter-branch 将文件夹从一个存储库移动到一个新存储库的帖子;我需要做的是将单个 file 移动到新的存储库中。

我已经创建了新的存储库,并将文件系统中的旧存储库添加为“远程”,并创建了一个新的“根提交”(只需为新的单文件项目添加一个 README。)现在我需要将与此特定文件有关的提交移植到新的根提交上。

(我应该提一下,这个文件在任何时候都没有在与任何其他文件相同的提交中被修改;我怀疑这可能会使这项任务稍微容易一些。)

【问题讨论】:

标签: git merge repository


【解决方案1】:

尝试了多种方法将文件或文件夹从一个 Git 存储库移动到另一个存储库,下面列出了唯一一种似乎可靠工作的方法。

它涉及克隆要从中移动文件或文件夹的存储库,将该文件或文件夹移至根目录,重写 Git 历史记录,克隆目标存储库并将具有历史记录的文件或文件夹直接拉入此目标存储库。

第一阶段

  1. 按照以下步骤制作存储库 A 的副本 对此副本的更改,您不应推送!

    git clone --branch <branch> --origin origin --progress -v <git repository A url>
    eg. git clone --branch master --origin origin --progress -v https://username@giturl/scm/projects/myprojects.git
    

    (假设 myprojects 是您要从中复制的存储库)

  2. cd进去

    cd <git repository A directory>          eg. cd /c/Working/GIT/myprojects
    
  3. 删除原始存储库的链接以避免意外 进行任何远程更改(例如通过推送)

    git remote rm origin
    
  4. 浏览您的历史记录和文件,删除任何不在其中的内容 目录1。结果是目录1的内容喷出来了 进入存储库 A 的基础。

    git filter-branch --subdirectory-filter <directory> -- --all
    eg. git filter-branch --subdirectory-filter subfolder1/subfolder2/FOLDER_TO_KEEP -- --all
    
  5. 仅适用于单个文件移动:检查剩下的内容并删除 除所需文件外的所有内容。 (您可能需要删除文件 你不希望同名并提交。)

    git filter-branch -f --index-filter \
    'git ls-files -s | grep $'\t'FILE_TO_KEEP$ |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
    git update-index --index-info && \
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE || echo "Nothing to do"' --prune-empty -- --all
    

    例如。 FILE_TO_KEEP = pom.xml 仅保留 FOLDER_TO_KEEP 中的 pom.xml 文件

第二阶段

  1. 清理步骤

    git reset --hard
    
  2. 清理步骤

    git gc --aggressive
    
  3. 清理步骤

    git prune
    

您可能希望将这些文件导入到存储库 B 中的目录而不是根目录中:

  1. 创建那个目录

    mkdir <base directory>             eg. mkdir FOLDER_TO_KEEP
    
  2. 将文件移动到该目录

    git mv * <base directory>          eg. git mv * FOLDER_TO_KEEP
    
  3. 将文件添加到该目录

    git add .
    
  4. 提交您的更改,我们已准备好将这些文件合并到 新仓库

    git commit
    

第三阶段

  1. 如果您还没有存储库 B,请制作一个副本

    git clone <git repository B url>
    eg. git clone https://username@giturl/scm/projects/FOLDER_TO_KEEP.git
    

    (假设 FOLDER_TO_KEEP 是您要复制到的新存储库的名称)

  2. cd进去

    cd <git repository B directory>          eg. cd /c/Working/GIT/FOLDER_TO_KEEP
    
  3. 创建到存储库 A 的远程连接作为存储库中的分支 乙

    git remote add repo-A-branch <git repository A directory>
    

    (repo-A-branch 可以是任何东西 - 它只是一个任意名称)

    eg. git remote add repo-A-branch /c/Working/GIT/myprojects
    
  4. 从此分支拉取(只包含你想要的目录 移动)到存储库 B。

    git pull repo-A-branch master
    

    pull 复制文件和历史记录。注意:您可以使用合并而不是拉取,但拉取效果更好。

  5. 最后,您可能想通过移除遥控器来清理一下 连接到存储库 A

    git remote rm repo-A-branch
    
  6. 按下,一切就绪。

    git push
    

【讨论】:

    【解决方案2】:

    另一种解决方案 - 将旧的 repo 添加为另一个远程,然后 rebase 和cherry-pick 可以工作。

    git clone old_repo
    git clone new_repo
    cd new_repo
    git remote add temp_repo old_repo
    git fetch temp_repo
    
    # bring the changed from old_repo into new_repo
    git rebase --onto <...> temp_repo/master
    OR
    git cherry-pick [list of relevant commits]
    
    git remote rm temp_repo
    git push origin HEAD
    

    【讨论】:

      【解决方案3】:

      我最终使用来自此(否则不相关)帖子的响应来构建解决方案。我修改了旧根并--onto-将内容重新定位到新根:

      Can I remove the initial commit from a Git repo?

      【讨论】:

        【解决方案4】:

        这是基于filter-branch manpage中的一个例子:

        git filter-branch --index-filter 'git ls-files -s | grep $'\t'<file-to-keep>$ | \
            GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && \
            mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' --prune-empty -- --all
        

        索引过滤器使用 git ls-files -s 打印索引的当前内容,仅 grep 出要保留的文件(grep 相当强迫 - 字段是制表符分隔的,文件名是最后一个),然后创建使用该信息的新索引,并将其移动到旧索引之上。

        --prune-empty 选项导致 filter-branch 删除任何现在什么都不做的提交(即它们只触及其他文件),-- --all 告诉它重写所有引用。

        与 filter-branch 一样,最好在新的克隆中执行此操作,因此,如果您把任何事情搞砸了,您是安全的,即使 filter-branch 确实在 refs/originals 中保留了备份。您可能还想阅读手册页中的checklist for shrinking a repository;结果是,一旦你完成了,真正摆脱所有不再需要的东西的最佳方法就是简单地克隆过滤后的存储库。

        即使文件在与其他文件相同的提交中被修改,这实际上也可以工作,尽管我想你可以尝试偷偷摸摸地利用这一事实,只需为所有提交生成补丁 em> 触摸那个文件,然后通过应用这些补丁来构建一个新的存储库......但是为什么要麻烦呢?

        (旁注:删除单个文件比保留单个文件要容易得多。在这种情况下,您所要做的就是使用git rm --cached --ignore-unmatch &lt;filename&gt;一个索引过滤器。)

        【讨论】:

        • 看起来很棒!我一到家就运行它,如果可行,请接受您的回答。 ^_^ 感谢您的宝贵时间。
        • 嗯,失败了:Rewrite bb6a446cc395e38cdcb7af7953b151e0a706929d (1/15)mv: /Users/elliottcable/Code/Cest.c/.git-rewrite/t/../index.new: No such file or directory
        • @elliottcable:啊,我以前也遇到过,但我不记得是什么原因造成的,也不记得如何解决。我确实在 repo 上对此进行了测试,它确实有效……但是当我解决问题时,我确实遇到了几次错误。我认为在变基期间工作目录有些混乱。既然你已经用另一种方式处理了它,我想我现在不会去尝试解决它。​​
        • 感谢您的宝贵时间,无论如何。 :D
        猜你喜欢
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        • 2023-04-09
        • 2022-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多