176

When I run git remote -v in one of my Git repositories that has a remote(s) configured, I see that each remote has both fetch and push specs:

$ git remote -v
<remote-name> ssh://host/path/to/repo (fetch)
<remote-name> ssh://host/path/to/repo (push)

For remotes that point to peer developers there's no need to push, and Git will refuse to push to a non-bare repository anyway. Is there any way to configure these remotes as "fetch-only" with no push address or capabilities?

mtbkrdave
  • 2,900
  • 3
  • 23
  • 24
  • 4
    @sehe, nope, you cannot. With no push URL specified, pushes will use the fetch URL. – yoyo May 16 '14 at 17:26

5 Answers5

247

I don't think you can remove the push URL, you can only override it to be something other than the pull URL. So I think the closest you'll get is something like this:

$ git remote set-url --push origin no-pushing
$ git push
fatal: 'no-pushing' does not appear to be a git repository
fatal: The remote end hung up unexpectedly

You are setting the push URL to no-pushing, which, as long as you don't have a folder of the same name in your working directory, git will not be able to locate. You are essentially forcing git to use a location that does not exist.

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Daniel Brockman
  • 18,826
  • 3
  • 29
  • 40
  • 21
    Yup, you would think "git remote set-url --delete --push .*" would do the trick, but if you delete the push url then it defaults back to the fetch url. – yoyo May 16 '14 at 17:25
  • 9
    I personally prefer use of something like '**DISALLOWED**', more visible. But that's just a matter of taste. – Pierre-Olivier Vares Oct 30 '14 at 17:25
  • 1
    @Pierre-OlivierVares What about **'DONTPUSH'**?! :) – Ali Shakiba Jul 10 '15 at 01:32
  • FYI, after doing this your git config file should look like this: (Note the new **pushurl** option) [remote "origin"] fetch = +refs/heads/*:refs/remotes/origin/* url = ssh://host/path/to/repo pushurl = ssh://host/no-pushing/repo – jaywilliams Jul 15 '16 at 14:13
  • 3
    Similarly to @Pierre-OlivierVares, I went with `git remote set-url --push origin -- --read-only--` -- note the extra `--` to allow a name with leading dashes. This felt more readable to me. – lindes Dec 17 '16 at 01:03
  • 2
    I found that with Git 2.24.0 I had to use DO.NOT.PUSH to avoid "Error: repository no-pushing/REPO doesn't exist". – Steven Shaw Feb 05 '20 at 03:53
  • @yoyo Is that still the case in 2020 (as of version 2.28.0)? I can't find any documentation either way. – Chiramisu Aug 28 '20 at 21:12
  • @Chiramisu sorry, not sure - try it and see? – yoyo Aug 29 '20 at 23:35
  • This seems more like a workaround. It is a required feature which is missing, to be able to enable/disable pushing to/fetching from a specific repository (though the second one seems useless at first look you might be the only one working on a personal fork so it saves some time when you want to merge latest changes). – Alireza Mohamadi Dec 09 '21 at 08:25
25

Apart from changing the push URL to something invalid (e.g., git remote set-url --push origin DISABLED), one can also use the pre-push hook.

One quick way to stop git push is to symlink /usr/bin/false to be the hook:

$ ln -s /usr/bin/false .git/hooks/pre-push
$ git push
error: failed to push some refs to '...'

Using a hook allows for more fine-grained control of pushes if desirable. See .git/hooks/pre-push.sample for an example of how to prevent pushing work-in-progress commits.

To prevent pushing to a specific branch or to limit pushing to a single branch, this in an example hook:

$ cat .git/hooks/pre-push
#!/usr/bin/sh

# An example hook script to limit pushing to a single remote.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If this script exits with a non-zero status nothing will be pushed.

remote="$1"
url="$2"

[[ "$remote" == "origin" ]]

A test repo with multiple remotes:

$ git remote -v
origin  ../gitorigin (fetch)
origin  ../gitorigin (push)
upstream        ../gitupstream (fetch)
upstream        ../gitupstream (push)

Pushing to origin is allowed:

$ git push origin
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 222 bytes | 222.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ../gitorigin
 * [new branch]      master -> master

Pushing to any other remote is not allowed:

$ git push upstream
error: failed to push some refs to '../gitupstream'

Note that the pre-push hook script can be modified to, among other things, print a message to stderr saying the push has been disabled.

Michael
  • 8,362
  • 6
  • 61
  • 88
Rodolfo Carvalho
  • 1,737
  • 1
  • 20
  • 18
6

The general statement "Git will refuse to push to a non-bare repository" is not true. Git will only refuse to push to a non-bare remote repository if you are attempting to push changes that are on the same branch as the remote repository's checked-out working directory.

This answer gives a simple explanation: https://stackoverflow.com/a/2933656/1866402

(I am adding this as an answer because I don't have enough reputation to add comments yet)

Community
  • 1
  • 1
pkeller
  • 691
  • 6
  • 7
  • a bare repository has no checked-out working directory, by definition. You can push to a particular branch on it though., – Ed Randall Mar 17 '15 at 12:33
3

If you already have a remote set up and just want to prevent yourself from doing something like accidentally pushing directly to master or release/production, you can prevent this using git config.

# prevent pushing to branch: master
$ git config branch.master.pushRemote no_push

# prevent pushing to branch: release/production
$ git config branch.release/production.pushRemote no_push

For the record, no_push is not a special name. It's just the name of any nonexistent branch. So you could use $ git config branch.master.pushRemote create_a_pr_and_do_not_push_directly_to_master and it would work just fine.

More info: git-config pushRemote

PaulMest
  • 12,925
  • 7
  • 53
  • 50
0

If you have control over the repository, you can achieve this by making use of permissions. The user who is fetching repository shouldn't have write permissions on master repository.

Abhilash
  • 339
  • 2
  • 7