git log
时,可以看到旧存储库的提交历史记录,但是如果我执行git log <file>
,它仅显示该文件的一个提交 - 子树合并。根据上面答案的评论,我不是唯一遇到这个问题的人,但我没有找到任何公开的解决方案。有没有办法合并存储库并保留各个文件的历史记录?
git log
时,可以看到旧存储库的提交历史记录,但是如果我执行git log <file>
,它仅显示该文件的一个提交 - 子树合并。根据上面答案的评论,我不是唯一遇到这个问题的人,但我没有找到任何公开的解决方案。# Assume the current directory is where we want the new repository to be created
# Create the new repository
git init
# Before we do a merge, we have to have an initial commit, so we'll make a dummy commit
git commit --allow-empty -m "Initial dummy commit"
# Add a remote for and fetch the old repo
# (the '--fetch' (or '-f') option will make git immediately fetch commits to the local repo after adding the remote)
git remote add --fetch old_a <OldA repo URL>
# Merge the files from old_a/master into new/master
git merge old_a/master --allow-unrelated-histories
# Move the old_a repo files and folders into a subdirectory so they don't collide with the other repo coming later
mkdir old_a
dir -exclude old_a | foreach { git mv $_.Name old_a }
# Commit the move
git commit -m "Move old_a files into subdir"
# Do the same thing for old_b
git remote add -f old_b <OldB repo URL>
git merge old_b/master --allow-unrelated-histories
mkdir old_b
dir –exclude old_a,old_b | foreach { git mv $_.Name old_b }
git commit -m "Move old_b files into subdir"
# Bring over a feature branch from one of the old repos
git checkout -b feature-in-progress
git merge -s recursive -Xsubtree=old_a old_a/feature-in-progress
git mv
的解决方案效果不是很好。当你后来在一个移动的文件上使用 git log
时,你只能看到移动的提交记录,之前所有的历史记录都丢失了。这是因为 git mv
实际上是 git rm; git add
的组合,只是一步完成。 - mholm815git log --follow
来获取所有的历史记录,或者所有的GUI工具都会自动为你完成这个操作。使用子树合并的方法时,据我所知,无法获取单个文件的历史记录,因此这种方法更好。 - Eric Leels
命令中使用的是数字1
(代表数字一),而在xargs
命令中使用的是大写字母'I'。 - Dominique Vial以下是不需要重写任何历史记录的方式,因此所有提交ID仍然有效。最终结果是第二个repo的文件将保存在一个子目录中。
将第二个repo作为远程库添加:
cd firstgitrepo/
git remote add secondrepo username@servername:andsoon
确保你已经下载了secondrepo的所有提交记录:
git fetch secondrepo
从第二个仓库的分支创建本地分支:
git branch branchfromsecondrepo secondrepo/master
将其所有文件移动到子目录中:
git checkout branchfromsecondrepo
mkdir subdir/
git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} subdir/
git commit -m "Moved files to subdir/"
将第二个分支合并到第一个repo的主分支(master branch)中:
git checkout master
git merge --allow-unrelated-histories branchfromsecondrepo
您的代码库将有多个初始提交,但这不应该成为问题。
git remote show secondrepo
在远程仓库上查看分支)。 - Flimm--allow-unrelated-histories
选项。请参阅此回答帖子的历史记录。 - Flimma
合并到 b
中(我假设它们是相邻的):cd b
git remote add a ../a
git fetch a
git merge --allow-unrelated-histories a/master
git remote remove a
如果您想将a
放入子目录中,请在上述命令之前执行以下操作:
cd a
git filter-repo --to-subdirectory-filter a
cd ..
为此,您需要安装git-filter-repo
(不建议使用filter-branch)。
合并两个大型存储库的示例,并将其中一个放入子目录中:https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731
更多信息在这里。
a/b/c
这个文件。你可以在合并之前重新命名文件,或将其合并到子目录中,或解决冲突。 - x-yurigit filter-repo
将重写历史记录。如果您不想这样做,可以使用 git mv
。 - Guildenstern在Github上创建一个新的代码库。
下载新建的代码库并添加旧的远程代码库。
git clone https://github.com/alexbr9007/Test.git
cd Test
git remote add OldRepo https://github.com/alexbr9007/Django-React.git
git remote -v
从旧仓库中获取所有文件,以创建一个新分支。
git fetch OldRepo
git branch -a
在主分支中,执行合并操作以将旧仓库与新创建的仓库合并。
git merge remotes/OldRepo/master --allow-unrelated-histories
创建一个新文件夹,用于存储从OldRepo添加的所有新内容,并将其文件移动到此新文件夹中。
最后,您可以上传来自合并存储库的文件,并安全地从GitHub中删除OldRepo。
希望这对于任何处理合并远程存储库的人都有用。
git remote rm OldRepo
删除旧仓库的远程链接。 - Célia Doolaeghegit rebase --root --preserve-merges --onto
将两个历史记录的早期联系在一起。
如果您有重叠的路径,请使用修复它们。
git filter-branch --index-filter
当你使用日志时,请确保你“更难找到副本”,使用以下方法:
git log -CC
我将 @Flimm 的解决方案转化为一个 git 别名
,并将其添加到我的~/.gitconfig
文件中:
[alias]
mergeRepo = "!mergeRepo() { \
[ $# -ne 3 ] && echo \"Three parameters required, <remote URI> <new branch> <new dir>\" && exit 1; \
git remote add newRepo $1; \
git fetch newRepo; \
git branch \"$2\" newRepo/master; \
git checkout \"$2\"; \
mkdir -vp \"${GIT_PREFIX}$3\"; \
git ls-tree -z --name-only HEAD | xargs -0 -I {} git mv {} \"${GIT_PREFIX}$3\"/; \
git commit -m \"Moved files to '${GIT_PREFIX}$3'\"; \
git checkout master; git merge --allow-unrelated-histories --no-edit -s recursive -X no-renames \"$2\"; \
git branch -D \"$2\"; git remote remove newRepo; \
}; \
mergeRepo"
$GIT_PREFIX
的值是什么? - neowulf33这个函数会将远程仓库克隆到本地仓库目录:
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
注意。此脚本可以重写提交记录,但会保留所有作者和日期信息,这意味着新的提交记录将具有另一个哈希值,如果您尝试将更改推送到远程服务器,只能通过强制键才能成功,并且它将在服务器上重写提交记录。因此,请在启动之前备份。
受益!
git filter-branch --index-filter
正常工作。通常情况下,我会收到一个错误消息,提示 .new
索引文件不存在。这让你想起了什么吗? - Patrick Beardgit-add-repo.sh
的单独文件,并在文件末尾添加此行代码 git-add-repo "$@"
。之后,你可以在zsh中使用它,例如 cd current/git/package
和 bash path/to/git-add-repo.sh https://github.com/example/example dir/to/save
。 - Andrey Izmanmv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
有时会失败,因此您需要添加一个if test
。 - Patrick Beard我需要一些与其他答案不同的东西,而且不需要安装任何新工具,并且更详细地了解这里发生了什么,所以这是我的答案:
假设您拥有以下本地文件结构。这里的两个仓库可能只在本地存储,也可能在远程URL上。无论哪种方式,指令都是相同的,只要它们也在本地存储,也就是说,如果它们是远程仓库,您已经将它们在本地克隆。
repo1
和repo2
是独立的、单独的,在本地存储或克隆的git仓库。
repo1/
.git/
.gitignore
(other files and folders)
repo2/
.git/
.gitignore
(other files and folders)
new_repo
里,repo1
和repo2
只是文件夹(不是仓库或子仓库/子模块)。repo1/ # will be deleted when done
...
repo2/ # will be deleted when done
...
new_repo/
.git/
.gitignore
repo1/
(other files and folders)
repo2/
(other files and folders)
除了上述参考资料外,还可以参考:
git clone git@github.com:user/parent-repo.git
git clone git@github.com:user/child-repo.git
cd child-repo/
my/new/subdir
(出现3次),这是您想要放置子仓库的目录结构。git filter-branch --prune-empty --tree-filter ' if [ ! -e my/new/subdir ]; then mkdir -p my/new/subdir git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files my/new/subdir fi'
cd ../parent-repo/
git remote add child-remote ../child-repo/
git fetch child-remote
git merge --allow-unrelated-histories child-remote/master
如果现在检查父仓库的 git 日志,应该已经合并了子仓库提交。您还可以看到标记,指示提交来源。
以下文章帮助我将一个仓库嵌入到另一个仓库中,通过合并两个 git 历史记录来获得一个单一的 git 历史记录。
希望这可以帮到你。 编码愉快!git filter-branch --prune-empty --tree-filter ' if [ ! -e my/new/subdir ]; then mkdir -p my/new/subdir; git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files my/new/subdir; fi'
。 - Yuri L我根据x-yuri的答案创建了一个基于filter-repo的一些脚本的存储库。使用我的脚本,您可以轻松地将所有分支和标签移动到新存储库中,如果指定不同的子目录,则不会出现合并冲突。