It looks like there is a race condition between fetch and push in a bare repository in the following setup. There is a bare git repository on a local file system. Some process pushes to this repository via jgit. There is a cron task which pushes this repository to the backup remote repo over ssh. We observe the following in the reflog: 6932a831843f4dbe3b394acde9adc9a8269b6cf1 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 XXX 1505903078 +0200 push: forced-update 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 44a221b0271b9abc885dd6e54f691d5248c4171f XXX 1505905206 +0200 push: forced-update 44a221b0271b9abc885dd6e54f691d5248c4171f 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 YYY 1505905217 +0200 update by push Where XXX is the process pushing via jgit and YYY is the cron task. It looks like the cron task started a push when the ref was pointing to 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 and push finished when the ref was already updated to 44a221b0271b9abc885dd6e54f691d5248c4171f. The push unconditionally updated the local tracking branch back to the commit 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 and we lost the commit 44a221b0271b9abc885dd6e54f691d5248c4171f since the next push from the local process created a new commit with 57b77b8c2a04029e7f5af4d3b7e36a3ba0c7cac9 as a parent. Shouldn't the update_ref at transport.c:308 specify the expected old hash, like this: update_ref("update by push", rs.dst, ref->new_oid.hash, ref->old_oid.hash, 0, 0); at least for bare repositories?