我有一个以特定方式浏览其他Web应用程序的Web应用程序。它在一个demos
文件夹中包含一些Web演示,并且其中一个演示现在应该具有自己的存储库。我想为此演示应用程序创建一个单独的存储库,并使其成为分包 主存储库中的子模块,而不会丢失其提交历史记录。
是否可以保留存储库文件夹中文件的提交历史记录,并从中创建存储库并将其用作子模块?
我有一个以特定方式浏览其他Web应用程序的Web应用程序。它在一个demos
文件夹中包含一些Web演示,并且其中一个演示现在应该具有自己的存储库。我想为此演示应用程序创建一个单独的存储库,并使其成为分包 主存储库中的子模块,而不会丢失其提交历史记录。
是否可以保留存储库文件夹中文件的提交历史记录,并从中创建存储库并将其用作子模块?
Answers:
有关使用npm的git子模块的快速替代方法,请参见此答案末尾的注释(最后一段);)
在以下答案中,您将知道如何从存储库中提取文件夹并从中创建git存储库,然后将其作为子模块而不是文件夹包含在内。
受Gerg Bayer的文章启发,将文件从一个Git存储库移动到另一个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 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
<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
创建一个子模块从<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 urls作为dependencies。
如果以这种方式执行此操作,则要用作需求的存储库必须是npm模块,因此它必须包含一个package.json
文件,否则会出现此错误:Error: ENOENT, open 'tmp.tgz-unpack/package.json'
。
您可能会发现使用npm和使用git urls管理依赖项更加容易:
npm init
在两个存储库中 运行npm install --save git://github.com/user/project.git#commit-ish
在要安装依赖项的地方运行cd someLib
在第二步之前做吗?您说“当前文件夹将是新的存储库”,但实际上不是。新的存储库(子模块)位于该文件夹内。
@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
GabLeRoux的解决方案效果很好,除非您使用git lfs
并且在要分离的目录下有大文件。在这种情况下,在第3步之后,所有大文件都将保留为指针文件,而不是实际文件。我猜可能是由于.gitattributes
文件在过滤器分支过程中被删除了。
意识到这一点,我发现以下解决方案适用于我:
cp .gitattributes .git/info/attributes
将.gitattributes
哪个git lfs用于跟踪大文件的文件复制到.git/
目录中以避免被删除。
过滤分支完成后,.gitattributes
如果您仍然想对新存储库使用git lfs,请不要忘记放回:
mv .git/info/attributes .gitattributes
git add .gitattributes
git commit -m 'added back .gitattributes'