我想在我的工作git存储库中合并一个远程git存储库作为它的子目录.我希望生成的存储库包含两个存储库的合并历史记录,并且合并存储库的每个文件都保留其在远程存储库中的历史记录.我尝试使用如何使用子树合并策略中提到的子树策略,但是在遵循该过程之后,尽管生成的存储库确实包含两个存储库的合并历史记录,但来自远程存储库的单个文件尚未保留其历史记录(任何一个'git log'只显示一条消息"Merged branch ...").
此外,我不想使用子模块,因为我不希望两个组合的git存储库再次分开.
是否可以将远程git存储库合并为另一个存储库作为子目录,来自远程存储库的单个文件保留其历史记录?
非常感谢您的帮助.
编辑:我目前正在尝试使用git filter-branch重写合并的存储库历史记录的解决方案.它似乎确实有效,但我需要再测试一下.我将回来报告我的发现.
编辑2:希望我让自己更清楚我给出了与git的子树策略一起使用的确切命令,这导致远程存储库文件的历史明显丢失.设A是我正在使用的git repo和B git repo我想将它作为它的子目录合并到A中.它做了以下事情:
git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."
Run Code Online (Sandbox Code Playgroud)
在这些命令进入目录subdir/Iwant/to/put/B/in后,我看到B的所有文件,但是git log在其中任何一个文件中只显示提交消息"将子目录合并为子目录/ Iwant/to/put/B /中".它们在B中的文件历史记录丢失了.
什么似乎工作(因为我在混帐初学者我可能是错的)如下:
git remote add -f B <url-of-B>
git checkout -b B_branch B/master # make a local branch following B's master
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
git checkout master
git merge B_branch
Run Code Online (Sandbox Code Playgroud)
上面的filter-branch命令取自git help filter-branch,我只更改了subdir路径.
kyn*_*nan 55
git-subtree是一个脚本,专门用于将多个存储库合并为一个同时保留历史记录(和/或拆分子树历史,尽管这似乎与此问题无关)的用例.它自1.7.11发布以来作为git树的一部分进行分发.
要将<repo>版本的存储库合并<rev>为子目录<prefix>,请使用git subtree add以下命令:
git subtree add -P <prefix> <repo> <rev>
Run Code Online (Sandbox Code Playgroud)
git-subtree 以更加用户友好的方式实现子树合并策略.
Set*_*son 31
在对正在发生的事情进行更全面的解释之后,我想我理解它,无论如何在底层我有一个解决方法.具体来说,我相信正在发生的事情是重命名检测被子树与--prefix合并所愚弄.这是我的测试用例:
mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
git read-tree --prefix=bdir -u B/master
git commit -m "subtree merge B into bdir"
cd bdir
echo BBB>>B
git commit -a -m BBB
Run Code Online (Sandbox Code Playgroud)
我们使用几个提交来创建git目录a和b.我们进行子树合并,然后在新子树中进行最终提交.
运行gitk(以z/a表示)显示历史确实出现,我们可以看到它.运行git log显示历史记录确实出现.但是,查看特定文件有一个问题: git log bdir/B
好吧,我们可以玩一招.我们可以使用--follow查看特定文件的预重命名历史记录. git log --follow -- B.这很好,但不是很好,因为它无法将合并前的历史与合并后的链接相关联.
我尝试使用-M和-C,但我无法让它跟随一个特定的文件.
因此,我觉得解决方案是告诉git将在子树合并中发生重命名.不幸的是git-read-tree对于子树合并非常挑剔,所以我们必须通过一个临时目录,但在我们提交之前就可以消失了.之后,我们可以看到完整的历史.
首先,创建一个"A"存储库并进行一些提交:
mkdir -p z/a z/b
cd z/a
git init
echo A>A
git add A
git commit -m A
echo AA>>A
git commit -a -m AA
Run Code Online (Sandbox Code Playgroud)
其次,创建一个"B"存储库并进行一些提交:
cd ../b
git init
echo B>B
git add B
git commit -m B
echo BB>>B
git commit -a -m BB
Run Code Online (Sandbox Code Playgroud)
使这项工作的诀窍是:强制Git通过创建一个子目录并将内容移入其中来识别重命名.
mkdir bdir
git mv B bdir
git commit -a -m bdir-rename
Run Code Online (Sandbox Code Playgroud)
返回存储库"A"并获取并合并"B"的内容:
cd ../a
git remote add -f B ../b
git merge -s ours --no-commit B/master
# According to Alex Brown and pjvandehaar, newer versions of git need --allow-unrelated-histories
# git merge -s ours --allow-unrelated-histories --no-commit B/master
git read-tree --prefix= -u B/master
git commit -m "subtree merge B into bdir"
Run Code Online (Sandbox Code Playgroud)
为了表明他们现在合并:
cd bdir
echo BBB>>B
git commit -a -m BBB
Run Code Online (Sandbox Code Playgroud)
要证明完整的历史记录保留在连接链中:
git log --follow B
Run Code Online (Sandbox Code Playgroud)
我们在这样做之后得到了历史,但问题是,如果你实际上保留旧的"b"回购并且偶尔从它合并(说它实际上是第三方单独维护的回购)你就遇到了麻烦,因为那个第三方将不会重命名.您必须尝试将新更改合并到您的b版本中并重命名,我担心这不会顺利进行.但如果b消失,你就赢了.
我想
git log -- file不使用--follow。步骤1:在源存储库中重写历史记录,以使其看起来所有文件始终都存在于子目录下。
为重写的历史记录创建一个临时分支。
git checkout -b tmp_subdir
Run Code Online (Sandbox Code Playgroud)
然后git filter-branch按照“ 如何重写历史记录”中的说明使用,以便除我已移动的文件以外的所有文件都在子目录中?:
git filter-branch --prune-empty --tree-filter '
if [ ! -e foo/bar ]; then
mkdir -p foo/bar
git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files foo/bar
fi'
Run Code Online (Sandbox Code Playgroud)
步骤2:切换到目标存储库。在源存储库中将源存储库添加为远程存储库并获取其内容。
git remote add sourcerepo .../path/to/sourcerepo
git fetch sourcerepo
Run Code Online (Sandbox Code Playgroud)
步骤3:merge --onto用于将重写的源存储库的提交添加到目标存储库的顶部。
git rebase --preserve-merges --onto master --root sourcerepo/tmp_subdir
Run Code Online (Sandbox Code Playgroud)
您可以检查日志,以确保它确实为您提供了所需的东西。
git log --stat
Run Code Online (Sandbox Code Playgroud)
步骤4:重新设置基准后,您将处于“分离头”状态。您可以将主控快进到新的位置。
git checkout -b tmp_merged
git checkout master
git merge tmp_merged
git branch -d tmp_merged
Run Code Online (Sandbox Code Playgroud)
步骤5:最后进行清理:删除临时遥控器。
git remote rm sourcerepo
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
23424 次 |
| 最近记录: |