本地Git仓库迁移:复制全分支、留5条提交历史、重命名分支并关联远程
解决Git仓库分支复制、浅历史保留及远程关联问题
问题描述
我需要将本地Git仓库A复制到仓库B,要求:
- 复制所有分支,但每个分支仅保留最新5条commit历史
- 将
master分支重命名为main - 所有分支重新关联远程仓库以推送到GitHub
但编写的bash脚本执行后出现分支丢失远程关联、无法推送的问题,GitHub Desktop报错:
Unable to push commits to this branch because there are commits not on the remote that are not present on your local branch. Fetch these new commits before pushing in order to reconcile them with your local commits.
原脚本内容:
#!/bin/bash set -e repo_name=TestRepo dir=/Users/username/development/$repo_name repo_src_url=git@github.com:my_username/$repo_name.git repo_target_url=git@github.com:my_username/$repo_name.git git clone --no-single-branch --depth 5 $repo_src_url $dir \ && cd $dir \ && git branch -m master main \ && git commit --amend --author "John Smith <john@johnsmith.com>" -m "Initial Commit" \ && git branch --unset-upstream \ && git remote set-url origin $repo_target_url
原脚本问题分析
- 浅克隆历史不匹配:
--depth 5创建的浅克隆仅保留本地分支最新5条commit,与远程仓库(即使是新仓库)的历史逻辑脱节,触发推送冲突。 - 分支上游处理不全:
git branch --unset-upstream仅取消当前分支的上游关联,其他本地分支仍绑定原仓库远程分支,未批量设置新远程的上游。 - Commit修改加剧冲突:
git commit --amend修改了main分支的根commit,导致本地与远程历史完全不一致,进一步引发推送报错。 - 远程URL配置错误:原脚本中源仓库与目标仓库URL相同,若目标仓库非空会直接触发历史冲突。
修正后的脚本
#!/bin/bash set -e # 配置参数 repo_name=TestRepo dir=/Users/username/development/$repo_name repo_src_url=git@github.com:my_username/source-repo.git # 原仓库A的URL repo_target_url=git@github.com:my_username/target-repo.git # 目标仓库B的URL keep_commits=5 # 克隆原仓库所有分支,每个分支保留指定数量的commit git clone --no-single-branch --depth $keep_commits $repo_src_url $dir cd $dir # 将master分支重命名为main(仅当分支存在时执行) if git show-ref --verify --quiet refs/heads/master; then git branch -m master main fi # 替换远程仓库URL为目标仓库 git remote set-url origin $repo_target_url # 遍历所有本地分支,重新设置上游并强制推送(目标仓库需为全新空仓库) git for-each-ref --format='%(refname:short)' refs/heads/ | while read branch; do # 仅对main分支修改commit作者(不需要可删除此段) if [ "$branch" = "main" ]; then git checkout $branch git commit --amend --author "John Smith <john@johnsmith.com>" --no-edit fi # 设置上游并强制推送,适配浅克隆的截断历史 git push -u origin $branch --force done
关键改进说明
- 批量处理所有分支:通过
git for-each-ref遍历所有本地分支,确保每个分支都重新绑定目标远程仓库。 - 明确强制推送:因为本地是截断的浅历史,与全新目标仓库的无历史状态匹配,强制推送可避免冲突。
- 可选的Commit修改:仅对main分支执行作者修改,不需要可直接删除对应代码块。
- 参数化配置:将保留commit数量、仓库URL等设为变量,便于后续调整。
注意事项
- 确保目标仓库是全新创建的空仓库,否则强制推送会覆盖原有历史,造成数据丢失。
- 浅克隆的分支无法追溯更早的commit,若后续需要完整历史,需执行
git fetch --unshallow(但此操作会拉取完整历史,不符合需求)。 - 若不需要修改commit作者,直接删除脚本中
git commit --amend相关代码即可。
内容的提问来源于stack exchange,提问作者stwhite
相关产品推荐
相关产品推荐

