我有两个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
现在,当我查看提交历史记录时,一切看起来都不错,但我存储库中的唯一文件现在是来自otherRepo的文件。
有什么想法吗?
干杯, Merlyn
答案 0 :(得分:11)
我认为git存储库是无关的?因为它们是单独项目的不同存储库,您希望将它们合并在一起以形成组合存储库?如果是这样,那么以下参考资料可能有所帮助:
答案 1 :(得分:4)
这篇权威性文章论述了开头段落中的简单案例 - 并将更可能的案例作为其主要主题:How to use the subtree merge strategy
保留两个存储库的提交历史记录。
这是我的版本 - 基于上面引用的文章...
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
答案 2 :(得分:2)
在最简单的情况下,你想要在合并后想要来自两个存储库的所有文件,你应该能够简单地使用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
答案 3 :(得分:2)
我知道这已经很晚了,但是对于仍然在寻找方法的人来说,我已经在StackOverFlow上收集了很多信息,并设法将一个脚本放在一起,为我解决了问题。
该脚本实际上甚至处理功能分支和标记 - 在新项目中重命名它们,以便您知道它们来自何处。
我知道这已经很晚了,但是对于仍然在寻找方法的人来说,我已经在StackOverFlow上收集了很多信息,并设法将一个脚本放在一起,为我解决了问题。
该脚本实际上甚至处理功能分支和标记 - 在新项目中重命名它们,以便您知道它们来自何处。
#!/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
## eitch@eitchnet.ch
##
## 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: $0 <new_project> <my_repo_urls.lst>"
exit 1
fi
# Script functions
function failed() {
echo -e "ERROR: Merging of projects failed:"
echo -e "$1"
exit 1
}
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 '$1' of ${sub_project}" ; then
failed "Failed to commit merge of branch '$1' of ${sub_project} into ${current_branch}"
fi
fi
}
## Script variables
PROJECT_NAME="${1}"
PROJECT_PATH="${ROOT_DIR}/${PROJECT_NAME}"
REPO_FILE="${2}"
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
# Make sure the required directories don't exist
if [ -e "${PROJECT_PATH}" ] ; then
echo -e "ERROR: Project ${PROJECT_NAME} already exists!"
exit 1
fi
# 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
您也可以从http://paste.ubuntu.com/11732805/
获取首先使用每个存储库的URL创建一个文件,例如:
git@github.com:eitchnet/ch.eitchnet.parent.git
git@github.com:eitchnet/ch.eitchnet.utils.git
git@github.com:eitchnet/ch.eitchnet.privilege.git
然后调用脚本,给出项目名称和脚本路径:
./mergeGitRepositories.sh eitchnet_test eitchnet.lst
脚本本身有很多注释,可以解释它的作用。
编辑用更优越的脚本替换脚本。
答案 4 :(得分:-1)
这些都显得非常困难和困惑......为什么不只是:
# 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
答案 5 :(得分:-1)
git checkout master
git merge otherRepoBranch
最后被遗忘了。
这对于将rebase应用于master分支是必需的。