从文件夹创建子模块存储库并保留其 git 提交历史记录

问题描述 投票:0回答:4

我有一个 Web 应用程序,它以特定方式探索其他 Web 应用程序。它在

demos
文件夹中包含一些 Web 演示,其中一个演示现在应该拥有自己的存储库。我想为此演示应用程序创建一个单独的存储库,并使其成为主存储库中的subpackagesubmodule,而不丢失其提交历史记录。

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

git git-submodules revision-history
4个回答
238
投票

详细解决方案

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

在下面的答案中,您将了解如何从存储库中提取文件夹并从中创建 git 存储库,然后将其作为子模块而不是文件夹包含在内。

受到 Gerg Bayer 的文章将文件从一个 Git 存储库移动到另一个,保留历史记录

的启发

一开始,我们有这样的事情:

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

在下面的步骤中,我将把这个

someLib
称为
<directory 1>

最后,我们会得到这样的结果:

<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>

步骤2

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

git remote rm origin

步骤3

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

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

您现在应该有一个 git 存储库,其中包含存储库根目录中

directory 1
中的文件以及所有相关的提交历史记录。

步骤4

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

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

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

upstream
分支

git push --set-upstream origin master

清洁
<git repository A>
(可选,见评论)

我们想要从

<git repository B>
中删除
<git repository A>
的痕迹(文件和提交历史记录),因此该文件夹的历史记录仅存在一次。

这是基于 从 github 中删除敏感数据

转到新文件夹并

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

<directory 1>
替换为您要删除的文件夹。
-r
将在指定目录中递归执行此操作:)。现在用
origin/master
 推至 
--force

git push origin master --force

Boss 阶段(见下面的注释)

<git repository B>

<git repository A>
 创建一个 
子模块

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

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

push

git push origin master

注意

完成所有这些之后,我意识到就我而言,使用 npm 来管理我自己的依赖项更合适。我们可以指定 git url 和版本,请参阅 package.json git url 作为依赖项

如果您这样做,您想要用作要求的存储库必须是 npm 模块,因此它必须包含

package.json
文件,否则您将收到此错误:
Error: ENOENT, open 'tmp.tgz-unpack/package.json'

tldr(替代解决方案)

您可能会发现使用 npm使用 git url 管理依赖项更容易:

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

13
投票

@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 [email protected]:user/existing-repo.git new-repo
cd new-repo
git clone-branches
git remote rm origin
git remote add origin [email protected]:user/new-repo.git
git remote -v
git filter-branch --subdirectory-filter my_directory/ -- --all
git push --all
git push --tags

7
投票

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'

0
投票

filter-branch
已被
filter-repo
取代。

使用

filter-repo
拆分子文件夹的过程记录在此处:

https://docs.github.com/en/get-started/using-git/splitting-a-subfolder-out-into-a-new-repository

© www.soinside.com 2019 - 2024. All rights reserved.