【问题标题】:Create a submodule repository from a folder and keep its git commit history从文件夹创建子模块存储库并保留其 git 提交历史记录
【发布时间】:2013-06-29 02:33:42
【问题描述】:

我有一个以特定方式探索其他 Web 应用程序的 Web 应用程序。它在demos 文件夹中包含一些网络演示,其中一个演示现在应该拥有自己的存储库。我想为这个演示应用程序创建一个单独的存储库,并使其成为主存储库中的 subpackage submodule 而不会丢失其提交历史记录。

是否可以保留存储库文件夹中文件的提交历史记录并从中创建存储库并将其用作submodule

【问题讨论】:

  • 我一直在搜索如何将目录 1 从 Git 存储库 A 移动到 Git 存储库 B。+1 以获得文章的链接。
  • 是的,这确实非常相似,解决方案略有不同,谢谢分享

标签: git git-submodules revision-history


【解决方案1】:

详细解决方案

有关使用 npm 的 git 子模块的快速替代方法,请参阅此答案末尾的注释(最后一段);)

在下面的答案中,您将知道如何从存储库中提取文件夹并从中创建一个 git 存储库,然后将其包含为 submodule 而不是文件夹。

灵感来自 Gerg Bayer 的文章 Moving Files from one Git Repository to Another, Preserving History

一开始,我们有这样的东西:

<git repository A>
    someFolders
    someFiles
    someLib <-- we want this to be a new repo and a git submodule!
        some files

在下面的步骤中,我会将这个someLib 称为&lt;directory 1&gt;

最后,我们会有这样的东西:

<git repository A>
    someFolders
    someFiles
    @submodule --> <git repository B>

<git repository B>
    someFolders
    someFiles

从另一个仓库中的文件夹创建一个新的 git 仓库

步骤 1

获取要拆分的存储库的新副本。

git clone <git repository A url>
cd <git repository A directory>

第二步

当前文件夹将是新的存储库,因此请移除当前远程。

git remote rm origin

第三步

提取所需文件夹的历史记录并提交

git filter-branch --subdirectory-filter <directory 1> -- --all

您现在应该有一个 git 存储库,其中包含来自存储库根目录中 directory 1 的文件以及所有相关的提交历史记录。

第四步

创建您的在线存储库并推送您的新存储库!

git remote add origin <git repository B url>
git push

您可能需要为第一次推送设置upstream 分支

git push --set-upstream origin master

清理&lt;git repository A&gt;(可选,见cmets)

我们想从&lt;git repository A&gt; 中删除&lt;git repository B&gt; 的跟踪记录(文件和提交历史记录),因此该文件夹的历史记录只存在一次。

这是基于来自 github 的 Removing sensitive data

转到一个新文件夹并

git clone <git repository A url>
cd <git repository A directory>
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <directory 1> -r' --prune-empty --tag-name-filter cat -- --all

&lt;directory 1&gt; 替换为您要删除的文件夹。 -r 将在指定的目录中递归执行:)。现在用--force推送到origin/master

git push origin master --force

Boss 阶段(见下方注释)

&lt;git repository B&gt; 创建一个submodule&lt;git repository A&gt;

git submodule add <git repository B url>
git submodule update
git commit

验证一切是否按预期工作,push

git push origin master

注意

在完成所有这些之后,我意识到在我的情况下使用npm 来管理我自己的依赖项更合适。我们可以指定git urls和版本,见package.json git urls as dependencies

如果你这样做,你想要用作要求的存储库必须是一个 npm 模块,所以它必须包含一个 package.json 文件,否则你会收到这个错误:@987654357 @。

tldr(替代解决方案)

您可能会发现使用npmmanage dependencies with git urls 更容易:

  • 将文件夹移至新存储库
  • 在两个存储库中运行 npm init
  • 运行npm install --save git://github.com/user/project.git#commit-ish 安装依赖项的位置

【讨论】:

  • 应避免步骤“清理 ”。这样做您无法从历史记录中完全恢复/签出旧版本/提交。您应该只 git rm 文件夹并添加子模块。因此,在签出较旧的提交时,请确保拥有完整的工作副本。
  • 您不应该在第 2 步之前执行cd someLib 吗?您说“当前文件夹将是新的存储库”,但实际上它不会;新的存储库(子模块)在 inside 该文件夹中。
  • 确认:是的,它适用于多个子模块。非常感谢详细的回答。此外,不必使用 npm。
  • 我将添加 information 关于在步骤 3 中创建的 refs/original/...
  • GitHub发了一篇关于如何实现文件夹提取到新仓库的文章:help.github.com/articles/…
【解决方案2】:

@GabLeRoux 的解决方案压缩了分支和相关的提交。

克隆和保留所有这些额外分支和提交的简单方法:

1 - 确保你有这个 git 别名

git config --global alias.clone-branches '! git branch -a | sed -n "/\/HEAD /d; /\/master$/d; /remotes/p;" | xargs -L1 git checkout -t'

2 - 克隆远程,拉取所有分支,更改远程,过滤目录,推送

git clone git@github.com:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin git@github.com:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags

【讨论】:

  • 它工作正常,除了 LFS(参见下面 ls 的答案)和标签:在我的例子中,它在新存储库中重新创建了整个父目录,因为标签是为整个父目录创建的。我不需要那个
【解决方案3】:

GabLeRoux 的解决方案运行良好,除非您使用 git lfs 并且在要分离的目录下有大文件。在这种情况下,在第 3 步之后,所有大文件将仍然是指针文件,而不是真实文件。我想这可能是由于在过滤器分支过程中删除了.gitattributes 文件。

意识到这一点,我发现以下解决方案对我有用:

cp .gitattributes .git/info/attributes

将 git lfs 用来跟踪大文件的.gitattributes 复制到.git/ 目录以避免被删除。

过滤分支完成后,如果您仍想为新存储库使用 git lfs,请不要忘记放回 .gitattributes

mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'

【讨论】:

  • 非常好用,好难找!
猜你喜欢
  • 2016-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多