题
我有个混库在一个文件夹,名为 XXX, 我有第二Git仓库被称为 YYY.
我想进口的 XXX 库入 YYY 库作为一个子目录,名为 ZZZ 并添加所有的 XXX's改变历史 YYY.
文件夹结构之前:
XXX
|- .git
|- (project files)
YYY
|- .git
|- (project files)
文件夹结构之后:
YYY
|- .git <-- This now contains the change history from XXX
|- ZZZ <-- This was originally XXX
|- (project files)
|- (project files)
可以这样做,或者我必须诉诸使用子模块?
解决方案
也许最简单的方法是将拉的 XXX 强>东西到一个分支中的 YYY ,然后将其合并到主:
在的 YYY 强>:
git remote add other /path/to/XXX
git fetch other
git checkout -b ZZZ other/master
mkdir ZZZ
git mv stuff ZZZ/stuff # repeat as necessary for each file/dir
git commit -m "Moved stuff to ZZZ"
git checkout master
git merge ZZZ --allow-unrelated-histories # should add ZZZ/ to master
git commit
git remote rm other
git branch -d ZZZ # to get rid of the extra branch before pushing
git push # if you have a remote, that is
我其实只是一对夫妇我的回购尝试这样做,它的工作原理。不同于约尔格的回答它不会让您继续使用其他回购,但我不认为你指定的反正。
注:由于这是最初写于2009年,混帐又新增下面的答复中提到的子树合并。我可能会使用该方法的今天,当然,这种方法还可以工作。
其他提示
如果您想保留第二仓库的确切提交历史,因此也保留在将来很容易合并上游的变化那么这里的能力是需要的方法。它导致的子树的未修改的历史被导入到您的回购加一个合并提交将合并后的资源库移到子目录。
git remote add XXX_remote <path-or-url-to-XXX-repo>
git fetch XXX_remote
git merge -s ours --no-commit --allow-unrelated-histories XXX_remote/master
git read-tree --prefix=ZZZ/ -u XXX_remote/master
git commit -m "Imported XXX as a subtree."
可以跟踪,像这样改变的上游:
git pull -s subtree XXX_remote master
的Git自身在根做合并之前,这样你就不会需要指定后续的合并前缀数字出来。
的Git版本之前2.9 :你并不需要通过--allow-unrelated-histories
选项git merge
在使用read-tree
并跳过步骤merge -s ours
对方的回答的方法,是有效地不超过复制文件具有CP和提交的结果不同。
原始来源是从 GitHub的 “子树合并” 帮助文章。
git-subtree
是设计用于准确的这种使用情况的脚本合并多个仓库为一体,同时保留完整的历史(和/或子树的分裂的历史,虽然这似乎是无关紧要这个问题)。因为释放1.7.11 该分配成在GIT中树的一部分。
要合并在修订<repo>
作为子目录<rev>
存储库<prefix>
,使用git subtree add
如下:
git subtree add -P <prefix> <repo> <rev>
git的子树实现在一个更加用户友好的子树合并策略方式。
有关你的情况,仓库里面YYY,你可以运行:
git subtree add -P ZZZ /path/to/XXX.git master
有一个众所周知的实例,在这个版本库本身,这是统称在从初社会"最酷的合并永远"(后的主题行Linus Torvalds中使用的电子邮件从初邮件列表介绍了这一合并).在这种情况下, gitk
Git的图形用户界面,这现在是一部分内适当、实际使用的是一个单独的项目。Linus管理,以合并,库进版本库中的一种方式,
- 它出现在版本库,如果它一直是发展部分内,
- 所有的历史记录保持完整和
- 它仍然可以独立发展在其古老的储存库,变化仅仅是
git pull
ed。
电子邮件包含所需的步骤再现,但它不是微弱的心脏:第一,莱纳斯 写了 Git,所以他可能知道更多关于这比你或我,和第二,这几乎是5年前,并让有所改善 相当大 自那以后,因此,也许现在是要容易得多。
特别是,我想现在会用一个gitk子模块,在特定情况。
简单的方法,这样做是对偏格式修补程序。
假设我们有2git仓库 foo 和 酒吧.
foo 包含:
- foo.txt
- .git
酒吧 包含:
- bar.txt
- .git
和我们想要结束了 foo 含有 酒吧 历史和这些文件:
- foo.txt
- .git
- foobar/bar.txt
因此,要做到:
1. create a temporary directory eg PATH_YOU_WANT/patch-bar
2. go in bar directory
3. git format-patch --root HEAD --no-stat -o PATH_YOU_WANT/patch-bar --src-prefix=a/foobar/ --dst-prefix=b/foobar/
4. go in foo directory
5. git am PATH_YOU_WANT/patch-bar/*
如果我们想要重写的所有信息提交的从酒吧我们可以做的,例如在Linux上
git filter-branch --msg-filter 'sed "1s/^/\[bar\] /"' COMMIT_SHA1_OF_THE_PARENT_OF_THE_FIRST_BAR_COMMIT..HEAD
这将添加"[bar]"在开始每个提交的信息。
根据本文一个上>,用子树是什么工作对我来说,只适用历史转移。万一有人张贴在这里需要的步骤(请务必用适用于您的值替换占位符):
在源存储库分割的子文件夹到一个新的分支
git subtree split --prefix=<source-path-to-merge> -b subtree-split-result
在分割结果的分支目的地回购合并
git remote add merge-source-repo <path-to-your-source-repository>
git fetch merge-source-repo
git merge -s ours --no-commit merge-source-repo/subtree-split-result
git read-tree --prefix=<destination-path-to-merge-into> -u merge-source-repo/subtree-split-result
验证更改和提交
git status
git commit
不要忘记
通过删除subtree-split-result
分支清理
git branch -D subtree-split-result
删除远程你加入来从源回购数据
git remote rm merge-source-repo
此功能将克隆远程回购到本地回购目录,合并所有的提交将被保存后,git log
将显示原始提交和正确路径:
function git-add-repo
{
repo="$1"
dir="$(echo "$2" | sed 's/\/$//')"
path="$(pwd)"
tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"
git clone "$repo" "$tmp"
cd "$tmp"
git filter-branch --index-filter '
git ls-files -s |
sed "s,\t,&'"$dir"'/," |
GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD
cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"
}
使用方法:
cd current/package
git-add-repo https://github.com/example/example dir/to/save
如果稍作修改,你甚至可以将合并回购的文件/显示目录到不同的路径,例如:
repo="https://github.com/example/example"
path="$(pwd)"
tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"
git clone "$repo" "$tmp"
cd "$tmp"
GIT_ADD_STORED=""
function git-mv-store
{
from="$(echo "$1" | sed 's/\./\\./')"
to="$(echo "$2" | sed 's/\./\\./')"
GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}
# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'
git filter-branch --index-filter '
git ls-files -s |
sed "'"$GIT_ADD_STORED"'" |
GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD
GIT_ADD_STORED=""
cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"
<强>通告强>结果
通过路径替换sed
,所以一定要确保它在正确的路径移动合并后,点击
所述--allow-unrelated-histories
参数仅因为GIT中存在> = 2.9。
添加另一种答案,因为我认为这是一个有点简单。 repo_dest的拉做成repo_to_import然后一推--set上游URL:repo_dest主完成
此方法很适合我导入几个较小回购成一个更大的一个。
如何导入:repo1_to_import到repo_dest
# checkout your repo1_to_import if you don't have it already
git clone url:repo1_to_import repo1_to_import
cd repo1_to_import
# now. pull all of repo_dest
git pull url:repo_dest
ls
git status # shows Your branch is ahead of 'origin/master' by xx commits.
# now push to repo_dest
git push --set-upstream url:repo_dest master
# repeat for other repositories you want to import
重命名或者你在导入之前移动文件和目录到所需的位置在原来的回购。例如
cd repo1_to_import
mkdir topDir
git add topDir
git mv this that and the other topDir/
git commit -m"move things into topDir in preparation for exporting into new repo"
# now do the pull and push to import
在下面的链接中所描述的方法的启发这个答案。我喜欢它,因为它显得比较简单。但要小心!有怪物! https://help.github.com/articles/importing-an-external -git-库 git push --mirror url:repo_dest
推动当地的回购历史和状态的远程(网址:repo_dest)。但它删除远程的悠久历史和状态。随之而来的乐趣! :-E
我只想在我的情况下,进口从其他仓库(XXX)的一些文件。该树对我来说太复杂,其他的解决方案没有奏效。这是我做过什么:
ALL_COMMITS=$(git log --reverse --pretty=format:%H -- ZZZ | tr '\n' ' ')
这给你所有能影响我想导入(ZZZ)以相反的顺序文件的提交的空格分隔的列表(您可能需要--follow添加到捕获重命名为好)。然后我进入目标库(YYY),加入其它储存库(XXX),为远程,并从一个它读取与最后:
git cherry-pick $ALL_COMMITS
这增加了所有提交到您的分支,你会因此都与他们的历史文件,并可以做任何你想要与他们,如果他们一直在这个资源库。
我在我一直在寻找-s theirs
但当然,这种策略不存在的情况。我的历史是我当时分叉在GitHub上的一个项目,现在由于某种原因,我的本地master
无法与upstream/master
合并虽然我没有作出任何本地更改到这个分支。 (真不知道那里发生了什么? - 我猜上游做了幕后的一些肮脏的推动,也许)
我最终什么事做了
# as per https://help.github.com/articles/syncing-a-fork/
git fetch upstream
git checkout master
git merge upstream/master
....
# Lots of conflicts, ended up just abandonging this approach
git reset --hard # Ditch failed merge
git checkout upstream/master
# Now in detached state
git branch -d master # !
git checkout -b master # create new master from upstream/master
所以现在我master
再次与upstream/master
同步(你可以重复上面的你也想同样同步任何其他分支)。
看看 基本的例子 在 这篇文章 并考虑这样的映射在仓库:
A
<->YYY
,B
<->XXX
之后所有的活动中描述这一章(合并后),删除分支 B-master
:
$ git branch -d B-master
然后,推动改变。
这对我的作品。
我可以建议另一个解决方案(替代 混帐子)对于你的问题 吉尔(git链接)工具
它允许来描述和管理复杂的git仓库的依赖关系。
此外,它提供了解决 git递子系统的依赖问题.
考虑有以下项目的相关性:样品git仓库依赖关系图
然后可以定义 .gitlinks
文件的储存库有关的说明:
# Projects
CppBenchmark CppBenchmark https://github.com/chronoxor/CppBenchmark.git master
CppCommon CppCommon https://github.com/chronoxor/CppCommon.git master
CppLogging CppLogging https://github.com/chronoxor/CppLogging.git master
# Modules
Catch2 modules/Catch2 https://github.com/catchorg/Catch2.git master
cpp-optparse modules/cpp-optparse https://github.com/weisslj/cpp-optparse.git master
fmt modules/fmt https://github.com/fmtlib/fmt.git master
HdrHistogram modules/HdrHistogram https://github.com/HdrHistogram/HdrHistogram_c.git master
zlib modules/zlib https://github.com/madler/zlib.git master
# Scripts
build scripts/build https://github.com/chronoxor/CppBuildScripts.git master
cmake scripts/cmake https://github.com/chronoxor/CppCMakeScripts.git master
每个线描述git链在下面的格式:
- 唯一的名称的储存库
- 相对路径库(从开始的道路。gitlinks文件)
- Git库将用于在git克隆的命令 数据库分支来结帐
- 空行或行开始#不析(处理作为评论)。
最后,你必须更新根样品储存库:
# Clone and link all git links dependencies from .gitlinks file
gil clone
gil link
# The same result with a single command
gil update
作为结果只克隆所需的所有项目,并将它们彼此在一种适当的方式。
如果你想要做的所有变化在一些储存库,与所有的改变儿童的链接仓库您可以做它与一个单一的命令:
gil commit -a -m "Some big update"
拉、推命令的工作在一个类似的方式:
gil pull
gil push
吉尔(git链接)工具支持以下命令:
usage: gil command arguments
Supported commands:
help - show this help
context - command will show the current git link context of the current directory
clone - clone all repositories that are missed in the current context
link - link all repositories that are missed in the current context
update - clone and link in a single operation
pull - pull all repositories in the current directory
push - push all repositories in the current directory
commit - commit all repositories in the current directory
更多关于 git递子系统的依赖问题.
我不知道一个简单的方式做到这一点。你可以这样做:
- 偏滤分添加一个ZZZ超目录上XXX库
- 推动新的分支到YYY库
- 合并的推支YYY的主干。
我可以编辑用的详细信息,如果这听起来有吸引力。
我想你可以使用 'git的MV' 和 '混帐拉' 做到这一点。
我是一个公平的git小白 - 所以要小心你的主存储库 - 但我只是尝试这样在临时目录和它似乎工作
。首先 - 重命名XXX的结构,使其符合您想让它时,它的YYY内:
cd XXX
mkdir tmp
git mv ZZZ tmp/ZZZ
git mv tmp ZZZ
现在XXX看起来像这样:
XXX
|- ZZZ
|- ZZZ
现在使用 'git的拉' 跨获取的变化:
cd ../YYY
git pull ../XXX
现在YYY看起来像这样:
YYY
|- ZZZ
|- ZZZ
|- (other folders that already were in YYY)