我有一个网络应用程序,探索其他网络应用程序在一个特定的方式。它包含一些网络演示在 demos文件夹,其中一个演示现在应该有自己的存储库。我想为这个演示应用程序创建一个单独的存储库,并在不丢失其提交历史的情况下从主存储库中将其设置为 子包 子舱。
demos
是否有可能从存储库文件夹中的文件保留提交历史,并从中创建一个存储库,而将其用作 子舱?
有关使用 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>。
someLib
<directory 1>
最后,我们会有这样的东西:
<git repository A> someFolders someFiles @submodule --> <git repository B> <git repository B> someFolders someFiles
获取要拆分的存储库的新副本。
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文件以及所有相关的提交历史记录。
directory 1
创建您的在线存储库并推送您的新存储库!
git remote add origin <git repository B url> git push
您可能需要设置 upstream分支来进行第一次推送
upstream
git push --set-upstream origin master
<git repository A>
我们希望从 <git repository A>中删除 <git repository B>的跟踪(文件和提交历史记录) ,因此此文件夹的历史记录只存在一次。
<git repository B>
这是基于来自 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将在指定的目录中递归地执行此操作:)。现在用 --force推到 origin/master
-r
--force
origin/master
git push origin master --force
创建一个从 <git repository B>到 <git repository A>的 子舱
git submodule add <git repository B url> git submodule update git commit
验证是否一切按预期运行和 push
push
git push origin master
在做完所有这些之后,我意识到在我的情况下,使用 Npm来管理我自己的依赖关系更合适。我们可以指定 git url 和版本,请参见 Json git urls 作为依赖项。
如果这样做,那么作为需求使用的存储库必须是一个 Npm 模块,因此它必须包含一个 package.json文件,否则就会得到这个错误: Error: ENOENT, open 'tmp.tgz-unpack/package.json'。
package.json
Error: ENOENT, open 'tmp.tgz-unpack/package.json'
你可能会发现使用 Npm和 使用 git url 管理依赖关系更容易:
npm init
npm install --save git://github.com/user/project.git#commit-ish
通过@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'
克隆远程,拉所有的分支,改变远程,过滤你的目录,推
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
GabLeRoux 的解决方案工作得很好,除非您使用 git lfs并且在您想要分离的目录下有大文件。在这种情况下,在第3步之后,所有的大文件将保持为指针文件,而不是真正的文件。我想这可能是由于在过滤器分支过程中删除了 .gitattributes文件。
git lfs
.gitattributes
意识到这一点,我发现下面的解决方案对我很有效:
cp .gitattributes .git/info/attributes
复制 .gitattributes,git lfs 使用它来跟踪大文件到 .git/目录,以避免被删除。
.git/
当过滤器分支完成后,如果您仍然想对新的存储库使用 git lfs,不要忘记放回 .gitattributes:
mv .git/info/attributes .gitattributes git add .gitattributes git commit -m 'added back .gitattributes'