Git: Set up a fetch-only remote?
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?
Solution 1:
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.
Solution 2:
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.
Solution 3:
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)