I can't push to my git repository. git clone
and git pull
works fine, but git push
doesn't work.
I checked other answers like here tried several ways like git push origin master --force
. But the error remains same.
Here's screenshot.
Other details:
$ git show-ref refs/remotes/origin/master
8a205a0741f85fa309031a45f3613bf95a99148f refs/remotes/origin/master
$ git rev-parse --symbolic-full-name master
refs/heads/master
$ git rev-parse master
35ae39a241cd6bbfe7a9092f72b08279159e0056
$ git show-ref master
35ae39a241cd6bbfe7a9092f72b08279159e0056 refs/heads/master
8a205a0741f85fa309031a45f3613bf95a99148f refs/remotes/origin/master
Please help me to get rid of this error.
$ git ls-remote
From https://xxx.git
8a205a0741f85fa309031a45f3613bf95a99148f HEAD
8a205a0741f85fa309031a45f3613bf95a99148f refs/heads/master
58feda6564bd52b9cce53da9862343aefd704202 refs/heads/new-0505
f24cd00e2f587689cdb92671769817c271bf0759 refs/heads/telestop
2a1afdf637a9108471eeddc755d49b74ef51e567 refs/meta/gitblit/reflog
8a205a0741f85fa309031a45f3613bf95a99148f refs/remotes/origin/master
There are several possible reasons for this sort of failure. As per comment this turned out to be a lingering master.lock
file on the server. Removing it manually sufficed.
Because there can be more than one reason for failure, it's not all that useful to provide just this one specific answer. We can, however, outline the general process here, and what can go wrong.
Remember that branch and tag names are specific forms of refs or references. Each one simply holds one hash ID. Tag names generally hold the hash ID of either a tag object—which makes an annotated tag—or of a commit object, and once created, never change. Branch names, however, identify one commit in a chain of commits, and that one commit is taken as the last commit that is part of that branch. (There may be subsequent commits, but they are not contained within that branch. Note that the commit identified by the branch name can be contained within other branches, though.) The upshot of this is that these values change regularly, as the branches grow. So the <name, value> pairing must be updated.
These name-value pairs probably should be kept in some kind of transactional database, but aren't. Git currently (as of all releases up through today's 2.26.2 version, and probably for quite a while to come) stores all these references in one or both of two places: either a single flat file named packed-refs
, or individual files stored in a file system, e.g., refs/heads/master
. To look up a name, Git first checks to see if the individual file exists. If so, the file will have the correct value. If not, Git checks to see if the name exists in the packed-refs
file and if so, uses the value there. If both searches fail, the name does not exist.
To make sure that any update is atomic—that no other Git command can update a name while one Git command is updating it—Git uses a careful sequence of creating .lock
files. For instance, to update refs/heads/master
, Git first creates refs/heads/master.lock
.1 The host OS must (and does) provide a "create file, but fail if it already exists" operation for this.
Things can go wrong here. Suppose, for instance, that the directory (or folder if you prefer that term) refs/heads/
denies create-new-file permissions to the user-ID that is handling a git push
process. In this case, creating master.lock
will fail with a "permission denied" kind of error.
In your particular case the master.lock
file already existed. Normally, such files are created, written, and then removed-or-renamed. In the event of a power failure, system crash, or other abrupt termination of a Git program, the system isn't left in a good state, though. In particular the .lock
file continues to exist.
For power failures or system crashes, one can go in and remove the lingering .lock
files during system startup. In practice this isn't common enough on most servers to bother with—people can just go fix their Git server manually, like you did. Git programs generally should not be abruptly killed by the OS either, but some systems use "out of memory killers" (OOM-killers) which can cause this sort of problem sometimes.
1Having created the appropriate .lock
file, Git will go on to write the new value into the lock file, then use an atomic rename operation to change the master.lock
file into a file named master
, removing any previous file. That both release the lock and stores the new value, all in a way such that any other Git command that needs the value, will see the new one.
Git uses this same technique for creating an index.lock
when updating its index file, but since the index entries are never transferred from one Git to another, any failures here are always purely local, not during git push
. This technique has another feature, which is that a "transaction" can be "rolled back" by simply deleting the lock file, rather than renaming the lock file to the main name.
Remember the term ACID when working with databases: Atomicity, Consistency, Isolation, Durability. The .lock
file technique provides atomicity, and if the OS makes the right guarantees, consistency and durability. The isolation property is entirely missing though: we cannot update one database field on its own. That's why Git uses separate files for each reference (except, that is, when it doesn't, via the packed-refs
file, which is therefore in effect read-only: only one Git program, git pack-refs
, ever updates it, using its own more complicated locking).
The lack of isolation can be painful when working with an extremely large index, too. For this reason, Git can use a "split index" mode, in which some entries (those that have not been changed recently) are in a second file, and only the "actively changing" entries are in the main .git/index
file.
(Using a real database would solve all of these problems along with multiple others, but real databases are complex.)