81

Is there a way to set up a git repository, so that git pull defaults to one remote and git push defaults to another? I know I can set both by changing the value of the remote variable in branch section of .git/config, but how to do it for each direction separately?

Andrew Vit
  • 18,961
  • 6
  • 77
  • 84
svick
  • 236,525
  • 50
  • 385
  • 514

7 Answers7

106

Since Git version 1.7.0, you can set this with:

git remote set-url --push origin https://your.push.com/blah/
suriv
  • 757
  • 8
  • 13
user392887
  • 1,399
  • 3
  • 9
  • 5
  • 1
    3 years later than the question, but this should be the new accepted answer! – Kevlar Sep 25 '13 at 20:47
  • 1
    @Kevlar Why? Accepting is used to mark not always "the best" answers, but the one that worked out for OP (read FAQ for more information). At a time of asking question above answer wouldn't work (wouldn't even existed), as git was way earlier than 1.8. Accepted answer however did worked out for OP. What reason to you find for changing OP's decision after three years? – trejder Dec 06 '13 at 10:26
  • 13
    @trejder Stack Overflow is also a place to serve useful answers to future visitors, who find a question via a search engine or whatever. It's valuable to have the currently-best answer appear first. I'm not saying that OP *must* change the accepted answer, but that it would be perfectly reasonable (and in my opinion a net positive) to do so. – amalloy Aug 20 '15 at 00:30
  • 2
    @trejder this also doesn't answer the question that was asked. – shadowtalker May 25 '16 at 16:00
  • How about the pull side of things using HTTPS? Using `pull` results in `error: unknown option 'pull'` – jww Jan 14 '18 at 20:22
  • 1
    1. fetch is what is relevant here, pull is simply fetch+merge 2. You have to do it the other way around apparently – xeruf May 17 '18 at 08:37
  • I just tried this with ssh as the default (pull) url and https as the push url and it did not work, giving me strange errors about urls. – plugwash Dec 05 '19 at 00:22
  • Sorry that was my own stupid fault, I had accidentally doubled up the colon in the URL. – plugwash Dec 06 '19 at 12:16
36

Since Git 1.8.3, you can use the remote.pushDefault option to do exactly what you want (i.e. having different default remotes for pull and push). You can set the option just like any other; for example, to set it to the pushTarget remote, use

git config remote.pushDefault pushTarget

This option will have the following effect:

  • git pull will pull from the remote specified by the remote option in the relevant branch section in .git/config, while
  • git push will push to the remote specified by remote.pushDefault.

Note that you need to specify the name of a remote, not an URL. This makes this solution more flexible than the solution involving remote.<name>.pushurl, because (for example) you will still have tracking branches for both remotes. Whether you need or want this flexibility is up to you.

The release notes say this option was added specifically to support triangular workflows.

MvanGeest
  • 9,536
  • 4
  • 41
  • 41
  • Strange: I thought you are pushing to upstream only, and you don't know how many downstream repo are pulling from you: see http://stackoverflow.com/a/2749166/6309 – VonC Jul 02 '15 at 19:12
  • @VonC Ah, yes, I see why it's confusing. I usually call the remote I want to *pull* from by default `upstream` because... well... it's upstream of my repository during those pulls. But the option is `pushDefault`, not `pullDefault`, so I used `downstream` as the name in the example. It's probably a better idea to call it `defaultPushTarget` ;) – MvanGeest Jul 02 '15 at 19:28
  • @MvanGeest I agree. But I confirm you generally push to "upstream". There one (or very few and known) upstreams. But there can be many (and unknown) downstreams. Such is the DVCS (as in "distributed") universe. – VonC Jul 02 '15 at 19:34
29

For Git 1.6.4 and later, set remote.<name>.pushurl with git config.

One might use this to pull using the read-only https: protocol and push using an ssh-based protocol.


Say origin's url (remote.origin.url) is https://git.example.com/some/repo.git. It is read-only, but you have write access through the ssh-based ‘URL’ git@git.example.com:some/repo.git. Run the following command to effect pushing over the ssh-based protocol:

git config remote.origin.pushurl git@git.example.com:some/repo.git
Demi
  • 3,535
  • 5
  • 29
  • 45
Chris Johnsen
  • 214,407
  • 26
  • 209
  • 186
  • 6
    How to have push going to a say 'development' branch and pull coming from say 'production' branch in same remote+bare Git repository? – Ninad Jul 23 '15 at 12:36
7

Thanks to MvanGeest for linking to the git 1.8.3 release notes. Those release notes say:

  • A triangular "pull from one place, push to another place" workflow is supported better by new remote.pushdefault (overrides the "origin" thing) and branch.*.pushremote (overrides the branch.*.remote) configuration variables.

I use such a triangular workflow all the time for open-source contributions. For example: I have my own GitHub fork of llvm/llvm-project, and I want to keep my own main branch up-to-date with the upstream's main. So I frequently git pull upstream main; it would be convenient if I could just type git pull instead. But, I don't want any chance that I might fat-finger git push<return> instead of git push origin main<return> and accidentally push to the upstream project's repo before I intended to! So, before today, my .git/config looked like this:

[remote "origin"]
        url = git@github.com:Quuxplusone/llvm-project
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "upstream"]
        url = git@github.com:llvm/llvm-project
        fetch = +refs/heads/*:refs/remotes/upstream/*
[branch "main"]
        merge = refs/heads/main
        remote = origin

Based on the release note quoted above, I've just changed my local repo's .git/config to this:

[remote "origin"]
        url = git@github.com:Quuxplusone/llvm-project
        fetch = +refs/heads/*:refs/remotes/origin/*
[remote "upstream"]
        url = git@github.com:llvm/llvm-project
        fetch = +refs/heads/*:refs/remotes/upstream/*
[branch "main"]
        merge = refs/heads/main
        remote = upstream
        pushremote = origin

Now I can do a simple git checkout main ; git pull to pull from upstream/main, and a simple git checkout main ; git push to push to origin/main. This is the "triangular workflow" I want.

Quuxplusone
  • 23,928
  • 8
  • 94
  • 159
  • Thanks a lot! This works for me! For those who are new to this like me and wondering where/how to update .git/config, here it is: git config --edit – Zoe L Aug 22 '23 at 14:51
  • @ZoeL: I suppose `git config --edit` works, but FWIW, I just do `nano .git/config`. :) The `config` file for a given checkout/repo is always stored in a file named `$ROOT_OF_MY_CHECKOUT/.git/config`. – Quuxplusone Aug 28 '23 at 01:34
5

From what I can gather from the git config man page, the upstream repo is:

  • by default origin
  • set by branch.remote
  • always for both git pull/fetch and git pull

For a given branch, I don't see any way to have two separate remote by default.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • This seems to be true in practice for git v1.8.3.2, after trying both the `git config remote...` and git remote set-url...` answers, for a single branch or for an entire copy of a repo. – Chris Keele Aug 29 '13 at 03:13
  • to reset the default remote back to `origin` for the current branch and push/pull to/from the matching branch name: `git push --set-upstream origin ` – hobs Sep 12 '14 at 21:24
3

user392887's answer is mostly correct, but:

  1. You should prefer to use SSH. According to GitHub, "We strongly recommend using an SSH connection when interacting with GitHub. SSH keys are a way to identify trusted computers, without involving passwords."

  2. Anyone using RHEL/CentOS 6 will be using git 1.7.1 by default, which supports set-url.

So, the preferred solution for git 1.7.1. and later is:

git remote set-url --push origin git@github.com:username/somerepo.git
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
potto
  • 47
  • 4
2

In case you also came here looking for a per-branch solution, here it is from the manual:

branch.<name>.pushRemote

When on branch , it overrides branch..remote for pushing. It also overrides remote.pushDefault for pushing from branch . When you pull from one place (e.g. your upstream) and push to another place (e.g. your own publishing repository), you would want to set remote.pushDefault to specify the remote to push to for all branches, and use this option to override it for a specific branch.

xeruf
  • 2,602
  • 1
  • 25
  • 48
  • So at the command line that would be `git config branch.my_branch.pushRemote my_push_remote` – Jasha Sep 17 '21 at 20:14