从文件夹创建子模块存储库并保留其 git 提交历史记录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17413493/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Create a submodule repository from a folder and keep its git commit history
提问by GabLeRoux
I have a web application that explores other web applications in a particular way. It contains some web demos in a demos
folder and one of the demo should now have it's own repository. I would like to create a separate repository for this demo application and make it a subpackagesubmodulefrom main repository without losing its commit history.
我有一个以特定方式探索其他 Web 应用程序的 Web 应用程序。它在一个demos
文件夹中包含一些 Web 演示,其中一个演示现在应该有自己的存储库。我想为此演示应用程序创建一个单独的存储库并使其成为子包来自主存储库的子模块而不会丢失其提交历史记录。
Is it possible to keep the commit history from the files in a repository's folder and create a repository from it and use it as a submoduleinstead?
是否可以保留存储库文件夹中文件的提交历史记录并从中创建存储库并将其用作子模块?
回答by GabLeRoux
Detailed Solution
详细解决方案
See the note at the end of this answer (last paragraph) for a quick alternative to git submodules using npm ;)
有关使用 npm 的 git 子模块的快速替代方法,请参阅本答案末尾的注释(最后一段);)
In the following answer, you will know how to extract a folder from a repository and make a git repository from it and then including it as a submoduleinstead of a folder.
在下面的答案中,您将知道如何从存储库中提取文件夹并从中创建一个 git 存储库,然后将其作为子模块而不是文件夹包含在内。
Inspired from Gerg Bayer's article Moving Files from one Git Repository to Another, Preserving History
灵感来自 Gerg Bayer 的文章将文件从一个 Git 存储库移动到另一个,保存历史
At the beginning, we have something like this:
一开始,我们有这样的事情:
<git repository A>
someFolders
someFiles
someLib <-- we want this to be a new repo and a git submodule!
some files
In the steps bellow, I will refer this someLib
as <directory 1>
.
在下面的步骤中,我将其someLib
称为<directory 1>
.
At the end, we will have something like this:
最后,我们会有这样的事情:
<git repository A>
someFolders
someFiles
@submodule --> <git repository B>
<git repository B>
someFolders
someFiles
Create a new git repository from a folder in an other repository
从另一个存储库中的文件夹创建一个新的 git 存储库
Step 1
第1步
Get a fresh copy of the repository to split.
获取要拆分的存储库的新副本。
git clone <git repository A url>
cd <git repository A directory>
Step 2
第2步
The current folder will be the new repository so remove the current remote.
当前文件夹将是新的存储库,因此删除当前的远程。
git remote rm origin
Step 3
第 3 步
Extract history of the desired folder and commit it
提取所需文件夹的历史记录并提交
git filter-branch --subdirectory-filter <directory 1> -- --all
You should now have a git repository with the files from directory 1
in your repo's root with all related commit history.
您现在应该有一个 git 存储库,其中包含来自directory 1
您的存储库根目录中的所有相关提交历史记录的文件。
Step 4
第四步
Create your online repository and push your new repository!
创建您的在线存储库并推送您的新存储库!
git remote add origin <git repository B url>
git push
You may need to set the upstream
branch for your first push
您可能需要upstream
为第一次推送设置分支
git push --set-upstream origin master
Clean <git repository A>
(optional, see comments)
清洁<git repository A>
(可选,见评论)
We want to delete traces (files and commit history) of <git repository B>
from <git repository A>
so history for this folder is only there once.
我们想删除<git repository B>
from 的痕迹(文件和提交历史),<git repository A>
所以这个文件夹的历史只有一次。
This is based on Removing sensitive datafrom github.
这是基于从 github 中删除敏感数据。
Go to a new folder and
转到一个新文件夹并
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
Replace <directory 1>
by the folder you want to remove. -r
will do it recursively inside the specified directory :). Now push to origin/master
with --force
替换<directory 1>
为要删除的文件夹。-r
将在指定目录内递归执行:)。现在推到origin/master
与--force
git push origin master --force
Boss Stage (See Note below)
Boss 阶段(见下面的注释)
Create a submodulefrom <git repository B>
into <git repository A>
从into创建子模块<git repository B>
<git repository A>
git submodule add <git repository B url>
git submodule update
git commit
Verify if everything worked as expected and push
验证一切是否按预期进行,并且 push
git push origin master
Note
笔记
After doing all of this, I realized in my case that it was more appropriate to use npmto manage my own dependencies instead. We can specify git urls and versions, see the package.json git urls as dependencies.
完成所有这些之后,我意识到在我的情况下,使用npm来管理我自己的依赖项更合适。我们可以指定 git urls 和版本,参见package.json git urls as dependencies。
If you do it this way, the repository you want to use as a requirement must be an npm moduleso it must contain a package.json
file or you'll get this error: Error: ENOENT, open 'tmp.tgz-unpack/package.json'
.
如果你这样做,你想用作需求的存储库必须是一个npm 模块,所以它必须包含一个package.json
文件,否则你会得到这个错误:Error: ENOENT, open 'tmp.tgz-unpack/package.json'
.
tldr (alternative solution)
tldr(替代解决方案)
You may find it easier to use npmand manage dependencies with git urls:
您可能会发现使用git urls更容易使用npm和管理依赖项:
- Move folder to a new repository
- run
npm init
inside both repositories - run
npm install --save git://github.com/user/project.git#commit-ish
where you want your dependencies installed
- 将文件夹移动到新的存储库
npm init
在两个存储库中 运行- 运行
npm install --save git://github.com/user/project.git#commit-ish
您希望安装的依赖关系
回答by oodavid
The solution by @GabLeRoux squashes the branches, and the related commits.
@GabLeRoux 的解决方案压缩了分支和相关的提交。
A simple way to clone and keep all those extra branches and commits:
一种克隆和保留所有这些额外分支和提交的简单方法:
1 - Make sure you have this git alias
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 - Clone the remote, pull all branches, change the remote, filter your directory, push
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
回答by ls.
GabLeRoux's solution works well except if you use git lfs
and has large files under the directory you want to detach. In that case, after step 3 all the large files will remain to be pointer files instead of real files. I guess it's probably due to the .gitattributes
file being removed in the filter branch process.
GabLeRoux 的解决方案效果很好,除非您使用git lfs
并在要分离的目录下有大文件。在这种情况下,在第 3 步之后,所有大文件都将保留为指针文件而不是实际文件。我想这可能是由于.gitattributes
在过滤器分支过程中删除了文件。
Realizing this, I find the following solution works for me:
意识到这一点,我发现以下解决方案对我有用:
cp .gitattributes .git/info/attributes
Copying .gitattributes
which git lfs uses to track large files to .git/
directory to avoid being deleted.
将.gitattributes
git lfs 用于跟踪大文件的复制到.git/
目录以避免被删除。
When filter-branch is done don't forget to put back the .gitattributes
if you still want to use git lfs for the new repository:
当 filter-branch 完成后,.gitattributes
如果你仍然想对新存储库使用 git lfs ,请不要忘记放回:
mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'