直接改 remote 地址可保留全部历史,因 commit 基于内容哈希且未重写历史;但需确保目标仓库为空、分支名匹配、无初始文件,并注意权限与认证差异。

直接改 remote 地址就能保留全部历史
能。Git 的提交对象(commit)是基于内容哈希生成的,只要不重写历史(比如没用 git filter-repo 或 rebase -i),换 remote 地址只是“换快递单”,包裹里的所有 commit、分支指针、标签都原封不动。
- 适用场景:源仓库和目标仓库都可访问(SSH/HTTPS),且目标仓库是空的
- 操作极简:
git remote set-url origin <新地址>,再git push -u origin master(或main) - 注意分支名必须匹配——如果原仓库主分支叫
main,但你推git push origin master,会新建一个空master分支,历史全丢 - 目标仓库不能有初始文件(如
README.md),否则git push会报non-fast-forward拒绝推送
镜像克隆(git clone --mirror)才是完整迁移的底线方案
普通 git clone 只拉默认分支,--mirror 才真正“复制整个 Git 数据库”:所有分支(含 refs/remotes/origin/*)、所有标签、所有引用日志(reflog)一并拿下,且不带工作区,杜绝本地修改干扰。
- 执行顺序固定:
git clone --mirror <旧地址>→cd xxx.git→git remote set-url origin <新地址>→git push --mirror -
--mirror推送等价于git push --all && git push --tags加上远程分支同步,但更彻底——连refs/pull/*(GitHub PR 引用)这类非标准引用也会传过去 - 常见错误:克隆后忘记进
xxx.git目录,直接在父目录下git push --mirror,会报错fatal: 'origin' does not appear to be a git repository
推送失败时先查保护分支和权限,别急着加 --force
看到 ! [remote rejected] master -> master (pre-receive hook declined) 不代表命令错了,大概率是目标仓库的分支保护策略在拦你。
- GitLab/GitHub 默认把
master或main设为受保护分支,Developer角色无法直接推送 - 解决路径优先级:进新仓库 Settings → Branches → 找到对应分支 → 勾选
Allow force pushes或Developers can push(GitLab);GitHub 则需调整Branch protection rules - 临时绕过?可以切个新分支推:
git checkout -b migrate-$(date +%Y%m%d)→git push -u origin HEAD,但历史虽在,主干衔接就断了 - 真要用
--force?只限git push --mirror --force,且确保目标仓库无人正在协作——它会强制覆盖远端所有引用,不是只刷一个分支
跨平台迁移(如 Gitee → GitHub)要防 URL 协议和认证方式差异
SSH 地址在不同平台权限模型不同:Gitee 的 SSH key 可能对不上 GitHub 的 deploy key,HTTPS 地址又可能触发双重验证(2FA)导致密码失效。
- 推荐统一用 HTTPS + Personal Access Token(PAT):GitHub PAT 权限勾选
repo,Gitee 用私有令牌(Private Token),避免输密码卡住 - 检查 URL 格式:
https://gitee.com/user/repo.git和https://github.com/user/repo.git结尾都有.git,漏掉会报repository not found - 如果旧仓库用了子模块(submodule),
--mirror不会自动同步子模块配置,得额外git submodule sync再推,否则新仓库里.gitmodules仍指向旧地址
git branch -a 和新仓库的 Settings → Branches 页面,比重推三次都管用。


















