What are the consequences of using receive.denyCurrentBranch in Git?
Asked Answered
S

6

57

I have a Git repository. I have cloned the repository and can commit my local changes. When I push my changes to the server it works.

As soon as I create a branch, I checkout the branch, commit my work and then checkout the master branch. I then merge my local changes into the master branch. When I try to push to the server I get the following exception:

Welcome to Git (version 1.7.11-preview20120620)

Run 'git help git' to display the help index.
Run 'git help <command>' to display help for specific commands.

$ git push origin master:master
 Counting objects: 9, done.
 Delta compression using up to 4 threads.
 Compressing objects: 100% (7/7), done.
 Writing objects: 100% (8/8), 13.68 KiB, done.
 Total 8 (delta 2), reused 1 (delta 0)
 Unpacking objects: 100% (8/8), done.
 remote: error: refusing to update checked out branch: refs/heads/master
 remote: error: By default, updating the current branch in a non-bare repository
 remote: error: is denied, because it will make the index and work tree inconsistent
 remote: error: with what you pushed, and will require 'git reset --hard' to match
 remote: error: the work tree to HEAD.
 remote: error:
 remote: error: You can set 'receive.denyCurrentBranch' configuration variable to

 remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into

 remote: error: its current branch; however, this is not recommended unless you
 remote: error: arranged to update its work tree to match what you pushed in some

 remote: error: other way.
 remote: error:
 remote: error: To squelch this message and still keep the default behaviour, set

 remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
 To c:/jGit
 ! [remote rejected] master -> master (branch is currently checked out)
 error: failed to push some refs to 'c:/gitRepository'

One solution is to run the following command:

git config receive.denyCurrentBranch ignore

After this it works, but I would like to know why I need to use this option. Is this the only option? What are the consequences of doing this?

What I would really like to do is create branches, merge them into the master branch and then push my changes to the server.

Swiercz answered 4/9, 2012 at 14:33 Comment(7)
What is the default value for receive.denyCurrentBranch?Nylons
You actually now have a secure way to push to a non-bare repo with Git 2.3.0 (February 2015) and git config receive.denyCurrentBranch=updateInstead:https://mcmap.net/q/11431/-what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repositoryKaciekacy
@VonC: But sadly still not on Windows.Newmown
@Newmown True. As I mention in https://mcmap.net/q/12564/-difference-between-msysgit-and-cygwin-git, they are working on a more robust "Git for Windows" as opposed to the current "msysgit"Kaciekacy
@Kaciekacy is right but without the equation: git config receive.denyCurrentBranch updateInsteadCheiron
@Cheiron Yes, https://mcmap.net/q/11431/-what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repository has the right syntaxKaciekacy
I just did a 'git config receive.denyCurrentBranch updateInstead' on Windows, and it worked fine. So it appears to me that whatever lack of support for this previously existed on Windows has now been fixed. This was with git version "2.19.1.windows.1" according to git --version.Ungrateful
C
30

The server where you are pushing to should use bare repository.

How to convert a normal Git repository to a bare one?

Calva answered 4/9, 2012 at 14:57 Comment(10)
I do understand difference between bare and non-bare. But what do you mean in this case?Swiercz
Just to be clear, I have also set the bare to true. Still no difference. Basically, I have done: git config --bool core.bare true. This has made no difference.Swiercz
Regular git repository has working copy (your source files) and hidden .git folder with git stuff. Bare repository has only git stuff. The error means that you are trying to push into regular repository and its working copy contains the same branch as you are pushing. The server's git repo doesn't need working copy, so use bare repo.Calva
I suspect you have done the git config in your local repository. Please try to understand what does it mean first.Calva
thanks, I have got it working. Yes, I did this on my local. Did this to the server and it worked.Swiercz
Note for the future: this will be easier with Git 2.3 "push changes directly to the repository on your server." github.com/blog/1957-git-2-3-has-been-releasedSaval
@Calva Please help me with my question: #28703641Muskrat
@Calva Still don't get your answer what makes git config receive.denyCurrentBranch ignore? Why do I need it?Sansone
@confile It is well explained in the message git prints out : "because it will make the index and work tree inconsistent with what you pushed". Not sure, what exactly do you ask?Calva
I came here to seek more information on the exact behaviour of said variable, more than git already spits out. This answer does not answer the question, nor does it provide more information than the original error message. All other answers further down are betterLapp
C
32

Why Git won't let you push to non-bare repositories

The original poster says:

One solution is to run the following command:

git config receive.denyCurrentBranch ignore

After this it works, but I would like to know why I need to use this option. Is this the only option? What are the consequences of doing this?

As I point out in my answer to a similar question, since Git version 1.6.2, Git won't let you push to a non-bare repository by default. This is because the git push command only updates the branch and HEAD references on the remote repository. What it doesn't do is also update the working-copy and staging-area in that non-bare remote.

As a consequence, when you use git status in the remote repo, you'll see that the repo's previous state is still present in the working copy (and staged in the index):

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   previous-state.txt

If you look at the error message that you got when you first tried to push to your non-bare remote repo with the receive.denyCurrentBranch setting set to the default refuse value, you'll see that the message tells you basically the same thing:

error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error:
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.

You should really just push to bare Git repositories

As pointed out in some of the other answers, you shouldn't really be pushing to a non-bare repository, for the reasons I pointed out above, and which Git itself is telling you.

So like what this answer states, a simple way to convert an existing non-bare repo to a bare one is to simply reclone it as a bare repo:

git clone --bare old-repo

Or you could try messing around with the core.bare config setting, as detailed in this answer.

Celin answered 30/7, 2014 at 18:17 Comment(3)
You actually now have a secure way to push to a non-bare repo with Git 2.3.0 (February 2015) and git config receive.denyCurrentBranch=updateInstead:https://mcmap.net/q/11431/-what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repositoryKaciekacy
@Kaciekacy typo: git config receive.denyCurrentBranch updateInsteadCheiron
@Cheiron yes, https://mcmap.net/q/11431/-what-is-this-git-warning-message-when-pushing-changes-to-a-remote-repository has the right synaxKaciekacy
C
30

The server where you are pushing to should use bare repository.

How to convert a normal Git repository to a bare one?

Calva answered 4/9, 2012 at 14:57 Comment(10)
I do understand difference between bare and non-bare. But what do you mean in this case?Swiercz
Just to be clear, I have also set the bare to true. Still no difference. Basically, I have done: git config --bool core.bare true. This has made no difference.Swiercz
Regular git repository has working copy (your source files) and hidden .git folder with git stuff. Bare repository has only git stuff. The error means that you are trying to push into regular repository and its working copy contains the same branch as you are pushing. The server's git repo doesn't need working copy, so use bare repo.Calva
I suspect you have done the git config in your local repository. Please try to understand what does it mean first.Calva
thanks, I have got it working. Yes, I did this on my local. Did this to the server and it worked.Swiercz
Note for the future: this will be easier with Git 2.3 "push changes directly to the repository on your server." github.com/blog/1957-git-2-3-has-been-releasedSaval
@Calva Please help me with my question: #28703641Muskrat
@Calva Still don't get your answer what makes git config receive.denyCurrentBranch ignore? Why do I need it?Sansone
@confile It is well explained in the message git prints out : "because it will make the index and work tree inconsistent with what you pushed". Not sure, what exactly do you ask?Calva
I came here to seek more information on the exact behaviour of said variable, more than git already spits out. This answer does not answer the question, nor does it provide more information than the original error message. All other answers further down are betterLapp
C
13

I had the same error and needed the repository to be running as a dev test page online (that is, I guess, to keep a non-bare repo). Hopefully I solved it by initiating the repository with this series of commands (since git 2.3):

git init
git config --global user.email "[email protected]"
git config --global user.name "Your Name"
git commit
git config receive.denyCurrentBranch updateInstead

As seen here: cannot push into git repository

Cheiron answered 17/2, 2017 at 7:6 Comment(0)
S
5

You should have a bare repository on the server, not one with a checked-out working tree. Git is telling you it refuses to overwrite the branch that is currently checked out on the server.

See this answer for information on how to convert your non-bare repository on the server to a bare one.

Sitsang answered 4/9, 2012 at 15:0 Comment(2)
I have tried this, but no difference. Basically, I have done: git config --bool core.bare true. What should I do?Swiercz
You need to do that on the repository on the server. Also, you need to get rid of the checked-out working tree on the server. Did you go through all the steps in the answer I linked to?Sitsang
M
3

Autopsy of the Problem

When a branch is checked out, committing will add a new commit with the current branch's head as its parent and move the branch's head to be that new commit.

So

A ← B
    ↑
[HEAD,branch1]

becomes

A ← B ← C
        ↑
    [HEAD,branch1]

But if someone could push to that branch inbetween, the user would get itself in what git calls detached head mode:

A ← B ← X
    ↑   ↑
[HEAD] [branch1]

Now the user is not in branch1 anymore, without having explicitly asked to check out another branch. Worse, the user is now outside any branch, and any new commit will just be dangling:

     [HEAD]
        ↓
        C
      ↙
A ← B ← X
        ↑
       [branch1]

Hypothetically, if at this point, the user checks out another branch, then this dangling commit becomes fair game for Git's garbage collector.

Mciver answered 3/12, 2014 at 3:47 Comment(3)
What you are describing is not detached head. Detached head is when you are checked out to a SHA directly, and not to a branch.Petromilli
When version pushed to non-bare repo, and if existing workspace has some modification, then repo head will be Detached head from the main branch repository. Merge or hard - rebase need to be applied for unifing the branch.Mciver
I don't believe setting receive.denyCurrentBranch to warn or ignore will put the remote repository into a detached head state (which would be what I want). Pushing to the remote repository instead seems to update the branch reference, which means that a commit in the remote repository would undo changes from the push.Admetus
O
0

I think a non bare repository can be useful when man configures the git update hook to deploy from the repository itself after the push happened. Just do not forget to reset the repository. If you miss that step files wont track the actual state...

Outspeak answered 4/1, 2015 at 16:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.