返回 2026-04-30
⚙️ 工程

Git远程仓库支持多个URL的配置方法Multiple URLs in Git Remote

susam.net·2026-04-29

文章介绍了Git远程仓库支持多个URL的技术实现方式。传统上Git远程只包含单个URL,但现在可以通过特定配置实现多个URL同时指向不同代码托管平台(如Codeberg)。这种配置允许开发者在不同平台间灵活切换,同时保持本地仓库的统一管理。

作者 Susam Pal,2026年4月29日

通常一个 Git 远程仓库只包含一个 URL。例如,当我们克隆一个仓库时,会自动创建一个名为 origin 的远程,并将其 URL 设置为上游仓库的位置。例如:

$ git remote -v
origin  https://codeberg.org/spxy/spica.git (fetch)
origin  https://codeberg.org/spxy/spica.git (push)
$ sed '/remote/,$!d' .git/config
[remote "origin"]
        url = https://codeberg.org/spxy/spica.git
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
        remote = origin
        merge = refs/heads/main

一个可能不太为人所知的细节是,我们可以为一个远程设置多个 URL。例如:

$ git remote set-url origin --add https://github.com/spxy/spica.git
$ git remote -v
origin  https://codeberg.org/spxy/spica.git (fetch)
origin  https://codeberg.org/spxy/spica.git (push)
origin  https://github.com/spxy/spica.git (push)
$ sed '/remote/,$!d' .git/config
[remote "origin"]
        url = https://codeberg.org/spxy/spica.git
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = https://github.com/spxy/spica.git
[branch "main"]
        remote = origin
        merge = refs/heads/main

从上述输出可以看出,当同一个远程配置了多个 URL 时,第一个 URL 会成为 fetch(获取)URL,而所有 URL 都会成为 push(推送)URL。例如:

$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 327 bytes | 109.00 KiB/s, done.
From https://codeberg.org/spxy/spica
   d473dde..31db503  main       -> origin/main
Updating d473dde..31db503
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)
$ git log --oneline
31db503 (HEAD -> main, origin/main, origin/HEAD) Explain that Spica is a binary star system
d473dde Create README.md

上述输出确认了 fetch 操作是从第一个远程 URL 执行的。尽管输出显示 origin 包含了提交 31db503,但 origin 的所有远程位置可能尚未接收到该提交。由于我们没有配置 pushurl,默认情况下推送会发送到所有远程 URL。例如:

$ echo 'It is about 250 light years away from the Sun.' >> README.md
$ git add README.md
$ git commit -m 'Mention distance from the Sun'
[main 816998d] Mention distance from the Sun
 1 file changed, 1 insertion(+)
$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 10 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 325 bytes | 325.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
To https://codeberg.org/spxy/spica.git
   31db503..816998d  main -> main
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 10 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (9/9), 791 bytes | 791.00 KiB/s, done.
Total 9 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/spxy/spica.git
 * [new branch]      main -> main
$ git log --oneline
816998d (HEAD -> main, origin/main, origin/HEAD) Mention distance from the Sun
31db503 Explain that Spica is a binary star system
d473dde Create README.md

可以按如下方式设置 pushurl:

$ git remote set-url --push origin https://github.com/spxy/spica.git
$ git remote -v
origin  https://codeberg.org/spxy/spica.git (fetch)
origin  https://github.com/spxy/spica.git (push)
$ sed '/remote/,$!d' .git/config
[remote "origin"]
        url = https://codeberg.org/spxy/spica.git
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = https://github.com/spxy/spica.git
        pushurl = https://github.com/spxy/spica.git
[branch "main"]
        remote = origin
        merge = refs/heads/main

当设置了一个或多个 pushurl 时,推送只会发送到这些指定的位置。而获取(fetch)仍会继续像之前一样从第一个 URL 进行。

$ echo 'Its two stars orbit each other roughly every four days.' >> README.md
$ git add README.md
$ git commit -m 'Mention the four-day orbital period'
[main 2e9f4e8] Mention the four-day orbital period
 1 file changed, 1 insertion(+)
$ git push
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 10 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 342 bytes | 342.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
To https://github.com/spxy/spica.git
   816998d..2e9f4e8  main -> main
$ git log --oneline
2e9f4e8 (HEAD -> main, origin/main, origin/HEAD) Mention the four-day orbital period
816998d Mention distance from the Sun
31db503 Explain that Spica is a binary star system
d473dde Create README.md

注意在这种情况下,新的提交仅被推送到第二个远程 URL。如果我们执行 pull 操作,Git 将从第一个远程 URL 获取更改,并将 origin/main 分支回退到该位置的最新提交。例如:

$ git pull
From https://codeberg.org/spxy/spica
 + 2e9f4e8...816998d main       -> origin/main  (forced update)
Already up to date.
$ git log --oneline
2e9f4e8 (HEAD -> main) Mention the four-day orbital period
816998d (origin/main, origin/HEAD) Mention distance from the Sun
31db503 Explain that Spica is a binary star system
d473dde Create README.md

因此,配置单独的 pushurl 需要谨慎。它仅在少数特定场景下有用,例如从一个我们想当作只读的主仓库获取内容,同时向镜像仓库推送更改的情况。

pushurl 与普通远程 URL 的区别在 Git 2.54.0 的 man git-fetch 和 man git-push 手册中也有说明:

<pushurl> 仅用于推送操作。它是可选的,默认为 <URL>。推送到远程会影响所有定义的 pushurls,或者在没有定义 pushurls 时影响所有定义的 urls。然而,获取操作只有在定义了多个 urls 时才会仅从第一个定义的 url 获取。

需要完整排版与评论请前往来源站点阅读。