将 git 存储库及其所有历史记录导入现有的 git 存储库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5995826/
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
Import a git repository with all its history into an existing git repository
提问by Curious Attempt Bunny
I have two git repositories and I want to merge them together without losing their commit histories. I've tried this:
我有两个 git 存储库,我想将它们合并在一起而不会丢失它们的提交历史记录。我试过这个:
cd firstRepo
git remote add other path/to/otherRepo
git fetch other
git checkout -b otherRepoBranch other/master
echo "`git rev-list otherRepoBranch | tail -n 1` `git rev-list master | head -n 1`" >> .git/info/grafts
git rebase otherRepoBranch master
Now when I look at the commit history everything looks good, but the only files I have in my repository are now the ones from otherRepo.
现在,当我查看提交历史时,一切看起来都不错,但是我的存储库中唯一的文件现在是来自 otherRepo 的文件。
Any ideas?
有任何想法吗?
回答by Phil Street
I take it the git repositories are unrelated? As in they're distinct repositories for separate projects that you want to be merged together to form a combined repository? If so, then it's possible the following references may help:
我认为 git 存储库是无关的?因为它们是不同项目的不同存储库,您希望将它们合并在一起以形成组合存储库?如果是这样,那么以下参考资料可能会有所帮助:
Combining multiple git repositories.
回答by nobar
This definitive article addresses the simple case in the opening paragraph -- and addresses the more likely case as its primary topic: How to use the subtree merge strategy
这篇权威性文章解决了开头段落中的简单案例——并将更有可能的案例作为其主要主题:如何使用子树合并策略
The commit history of both repositories is preserved.
保留两个存储库的提交历史记录。
Here's my version -- based on the above referenced article...
这是我的版本——基于上面引用的文章......
git remote add temp staging_path/(reponame)
git fetch temp
git fetch --tags temp ## optional -- may pull in additional history
for remote in $(git branch -r | grep temp/ ) ; do git branch --no-track imported_$(basename $remote) $remote ; done ## create local branches prefixed with 'imported_'
git remote rm temp ## optional -- assumes you no longer plan to use the source repo
git merge -s ours --no-commit imported_master ## mysterious "merge strategy"
git read-tree -u --prefix=(reponame)/ imported_master ## move to sub-folder
git commit
回答by Jesse Hallett
In the simplest case where you want all of the files from both repositories after the merge you should be able to simply use git merge:
在最简单的情况下,您需要合并后两个存储库中的所有文件,您应该能够简单地使用 git merge:
cd firstRepo
git remote add other path/to/otherRepo
git fetch other
git checkout -b merged
git merge --allow-unrelated-histories other/master
回答by eitch
I know this is rather late, but for anyone still looking for a way to do this, i have gathered a lot of information here on StackOverFlow etc., and have manage to put a script together which solves the problem for me.
我知道这已经很晚了,但是对于仍在寻找方法来做到这一点的任何人来说,我在这里收集了很多关于 StackOverFlow 等的信息,并设法将脚本放在一起,为我解决了问题。
The script actually even handles feature branches and tags - renaming them in the new project so you know where they came from.
该脚本实际上甚至处理功能分支和标签 - 在新项目中重命名它们,以便您知道它们来自哪里。
I know this is rather late, but for anyone still looking for a way to do this, i have gathered a lot of information here on StackOverFlow etc., and have manage to put a script together which solves the problem for me.
我知道这已经很晚了,但是对于仍在寻找方法来做到这一点的任何人来说,我在这里收集了很多关于 StackOverFlow 等的信息,并设法将脚本放在一起,为我解决了问题。
The script actually even handles feature branches and tags - renaming them in the new project so you know where they came from.
该脚本实际上甚至处理功能分支和标签 - 在新项目中重命名它们,以便您知道它们来自哪里。
#!/bin/bash
#
################################################################################
## Script to merge multiple git repositories into a new repository
## - The new repository will contain a folder for every merged repository
## - The script adds remotes for every project and then merges in every branch
##? and tag. These are renamed to have the origin project name as a prefix
##
## Usage: mergeGitRepositories.sh <new_project> <my_repo_urls.lst>
## - where <new_project> is the name of the new project to create
## - and <my_repo_urls.lst> is a file contaning the URLs to the respositories
## which are to be merged on separate lines.
##
## Author: Robert von Burg
## [email protected]
##
## Version: 0.2.0
## Created: 2015-06-17
##
################################################################################
#
# disallow using undefined variables
shopt -s -o nounset
# Script variables
declare SCRIPT_NAME="${0##*/}"
declare SCRIPT_DIR="$(cd ${0%/*} ; pwd)"
declare ROOT_DIR="$PWD"
# Detect proper usage
if [ "$#" -ne "2" ] ; then
echo -e "ERROR: Usage: [email protected]:eitchnet/ch.eitchnet.parent.git
[email protected]:eitchnet/ch.eitchnet.utils.git
[email protected]:eitchnet/ch.eitchnet.privilege.git
<new_project> <my_repo_urls.lst>"
exit 1
fi >&2
# Script functions
function failed() {
echo -e "ERROR: Merging of projects failed:"
echo -e ""
exit 1
} >&2
function commit_merge() {
current_branch="$(git symbolic-ref HEAD 2>/dev/null)"
CHANGES=$(git status | grep "working directory clean")
MERGING=$(git status | grep "merging")
if [[ "$CHANGES" != "" ]] && [[ "$MERGING" == "" ]] ; then
echo -e "INFO: No commit required."
else
echo -e "INFO: Committing ${sub_project}..."
if ! git commit --quiet -m "[Project] Merged branch '' of ${sub_project}" ; then
failed "Failed to commit merge of branch '' of ${sub_project} into ${current_branch}"
fi
fi
}
## Script variables
PROJECT_NAME=""
PROJECT_PATH="${ROOT_DIR}/${PROJECT_NAME}"
REPO_FILE=""
REPO_URL_FILE="${ROOT_DIR}/${REPO_FILE}"
# Make sure the REPO_URL_FILE exists
if [ ! -e "${REPO_URL_FILE}" ] ; then
echo -e "ERROR: Repo file ${REPO_URL_FILE} does not exist!"
exit 1
fi >&2
# Make sure the required directories don't exist
if [ -e "${PROJECT_PATH}" ] ; then
echo -e "ERROR: Project ${PROJECT_NAME} already exists!"
exit 1
fi >&2
# create the new project
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..."
echo -e "===================================================="
cd ${ROOT_DIR}
mkdir ${PROJECT_NAME}
cd ${PROJECT_NAME}
git init
echo "Initial Commit" > initial_commit
# Since this is a new repository we need to have at least one commit
# thus were we create temporary file, but we delete it again.
# Deleting it guarantees we don't have conflicts later when merging
git add initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
git rm --quiet initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
echo
# Merge all projects into th branches of this project
echo -e "INFO: Merging projects into new repository..."
echo -e "===================================================="
for url in $(cat ${REPO_URL_FILE}) ; do
# extract the name of this project
export sub_project=${url##*/}
sub_project=${sub_project%*.git}
echo -e "INFO: Project ${sub_project}"
echo -e "----------------------------------------------------"
# Fetch the project
echo -e "INFO: Fetching ${sub_project}..."
git remote add "${sub_project}" "${url}"
if ! git fetch --no-tags --quiet ${sub_project} 2>/dev/null ; then
failed "Failed to fetch project ${sub_project}"
fi
# add remote branches
echo -e "INFO: Creating local branches for ${sub_project}..."
while read branch ; do
branch_ref=$(echo $branch | tr " " "\t" | cut -f 1)
branch_name=$(echo $branch | tr " " "\t" | cut -f 2 | cut -d / -f 3-)
echo -e "INFO: Creating branch ${branch_name}..."
# create and checkout new merge branch off of master
git checkout --quiet -b "${sub_project}/${branch_name}" master
git reset --hard --quiet
git clean -d --force --quiet
# Merge the project
echo -e "INFO: Merging ${sub_project}..."
if ! git merge --quiet --no-commit "remotes/${sub_project}/${branch_name}" 2>/dev/null ; then
failed "Failed to merge branch 'remotes/${sub_project}/${branch_name}' from ${sub_project}"
fi
# And now see if we need to commit (maybe there was a merge)
commit_merge "${sub_project}/${branch_name}"
# relocate projects files into own directory
if [ "$(ls)" == "${sub_project}" ] ; then
echo -e "WARN: Not moving files in branch ${branch_name} of ${sub_project} as already only one root level."
else
echo -e "INFO: Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..."
mkdir ${sub_project}
for f in $(ls -a) ; do
if [[ "$f" == "${sub_project}" ]] ||
[[ "$f" == "." ]] ||
[[ "$f" == ".." ]] ; then
continue
fi
git mv -k "$f" "${sub_project}/"
done
# commit the moving
if ! git commit --quiet -m "[Project] Move ${sub_project} files into sub directory" ; then
failed "Failed to commit moving of ${sub_project} files into sub directory"
fi
fi
echo
done < <(git ls-remote --heads ${sub_project})
#?checkout master of sub probject
if ! git checkout "${sub_project}/master" 2>/dev/null ; then
failed "sub_project ${sub_project} is missing master branch!"
fi
# copy remote tags
echo -e "INFO: Copying tags for ${sub_project}..."
while read tag ; do
tag_ref=$(echo $tag | tr " " "\t" | cut -f 1)
tag_name=$(echo $tag | tr " " "\t" | cut -f 2 | cut -d / -f 3)
# hack for broken tag names where they are like 1.2.0^{} instead of just 1.2.0
tag_name="${tag_name%%^*}"
tag_new_name="${sub_project}/${tag_name}"
echo -e "INFO: Copying tag ${tag_name} to ${tag_new_name} for ref ${tag_ref}..."
if ! git tag "${tag_new_name}" "${tag_ref}" 2>/dev/null ; then
echo -e "WARN: Could not copy tag ${tag_name} to ${tag_new_name} for ref ${tag_ref}"
fi
done < <(git ls-remote --tags ${sub_project})
# Remove the remote to the old project
echo -e "INFO: Removing remote ${sub_project}..."
git remote rm ${sub_project}
echo
done
# Now merge all project master branches into new master
git checkout --quiet master
echo -e "INFO: Merging projects master branches into new repository..."
echo -e "===================================================="
for url in $(cat ${REPO_URL_FILE}) ; do
# extract the name of this project
export sub_project=${url##*/}
sub_project=${sub_project%*.git}
echo -e "INFO: Merging ${sub_project}..."
if ! git merge --quiet --no-commit "${sub_project}/master" 2>/dev/null ; then
failed "Failed to merge branch ${sub_project}/master into master"
fi
# And now see if we need to commit (maybe there was a merge)
commit_merge "${sub_project}/master"
echo
done
# Done
cd ${ROOT_DIR}
echo -e "INFO: Done."
echo
exit 0
You can also get it from http://paste.ubuntu.com/11732805/
您也可以从http://paste.ubuntu.com/11732805/获取它
First create a file with the URL to each repository, e.g.:
首先使用每个存储库的 URL 创建一个文件,例如:
./mergeGitRepositories.sh eitchnet_test eitchnet.lst
Then call the script giving a name of the project and the path to the script:
然后调用给出项目名称和脚本路径的脚本:
git checkout master
git merge otherRepoBranch
The script itself has a lot of comments which should explain what it does.
脚本本身有很多注释,可以解释它的作用。
Edited to replace the script with a more superior one.
编辑以用更高级的脚本替换脚本。
回答by Tobias Renz
# Make a bare clone of the external repo to a local directory without a working directory
git clone --bare https://githost.org/extuser/repo.git
# now push all history and repo to new repo
cd repo.git
git push --mirror https://github.com/ghuser/repo.git # Push mirror to new GitHub repo
cd ..
rm -rf repo.git # Remove temporary local repo
were forgotten in the end.
最后被遗忘了。
This is necessary to apply the rebase on the master branch.
这是在 master 分支上应用 rebase 所必需的。
回答by MichaelICE
These all seemed very hard and confusing... why not just:
这些似乎都非常困难和令人困惑......为什么不只是:
##代码##