3

First, I understand the how related to pushing to non-bare git remotes, including the use of the git config option receive.denyCurrentBranch and other work arounds, so I'm NOT looking for answers such as those here:

This is more of a git implementation/representation/philosophical question.

Why can't a git push <remote> to a non-bare remote be the dual or essentially the same as a git fetch <source> from the remote? That way, my local working dir on the remote may be out of date (behind) the new content, and I might even have local changes (commits ahead, or even staged/unstaged/stashed/whatever), but that working dir is completely untouched by the push operation? If it did, then once on the remote, I could merge or rebase or whatevever necessary. In fact, that's exactly what is claimed by this kernel.org git faq entry.

Motiviation for this is really the same as everyone else who asks the how questions: I don't have any way to easily access the "source" of the push from the remote due to {firewall, nat, security} reasons.

Probably I'm missing some fundamental knowledge of how git really tracks things that "if I only understood XXXX", I'd know the answer; enlighten me, please.

Community
  • 1
  • 1
crimson-egret
  • 753
  • 7
  • 18
  • Maybe compare more to `git pull`. You may also find http://stackoverflow.com/q/3329943/631619 useful for more conceptual stuff. It wasn't until I saw index and staging areas that I 'got' it myself. Until then I was just a stupid git. – Michael Durrant Jul 05 '15 at 21:21
  • Thanks for the pointer, Michael. Some useful information in there, and well written, but it's not exactly what I'm asking. I'm trying to understand specifically why the working tree must be updated when pushing to a non-bare remote. At least I think that's the right question. – crimson-egret Jul 10 '15 at 16:34
  • It’d be nice if I could just push to a repository’s `FETCH_HEAD` instead of `HEAD`. This question is that same idea: it’d be nice to be able to push in a way that merely detaches the head. For me, I just want to get the changesets into the store. It’s like git doesn’t support doing that without updating a ref… – binki Jul 11 '22 at 16:11

1 Answers1

0

The problem is that pushing rewrites refs. HEAD is a synonym for the latest checkout, and rewriting that ref silently invalidates the worktree and index -- a commit in that repo will lose the pushed changes, with no indication that that's happened. Refusing the push is the simplest solution. If doing git pull at the destination isn't an option, then push to a throwaway and fix up the refs:

git push origin master:fakemaster
cd $origindir
git checkout -B master fakemaster
git branch -D fakemaster
jthill
  • 55,082
  • 5
  • 77
  • 137
  • Thanks for the response, and while your work around and mine are effectively equivalent, what I'm really trying to understand is **why** the worktree and must be updated when the index is updated. **IF** I understand what `fetch` is doing, it is updating the refs (specifically `refs/heads/master`) without updating the index or the worktree. Therefore, why can't a `git push` to a non-bare remote do the same thing? – crimson-egret Jul 10 '15 at 16:37
  • I can't think of another way to desync HEAD + index + worktree in somebody else's repo offhand -- and fetch doesn't update your main branches by default, it updates your remote-tracking ones (in refs/remots). – jthill Jul 10 '15 at 18:38
  • @eggo, I think the answer to your above comment is actually: **It does.** The refs get updated, the index and the worktree do not. This is *exactly* how it works. The trick is that if you change the currently checked out branch ref, you also affect the HEAD of the non-bare remote (which is pointing at the branch you just changed), and this invalidates whatever is currently in your index and any changes in your work tree on that remote. Of course, you could agree on a custom that you will never make changes on that remote...but then you should just **use a bare repo** in the first place. – Wildcard Apr 14 '16 at 21:54
  • @Wildcard - thanks for that, and clearly my mental model of the inner workings of git are still not up to the task to solve the underlying theoretical confusion. Specifically, the (apparently) fundamental linkage between the work tree and the index. In the end, I have a workable solution to the practical problem; one that looks similar to jthill's answer. The practical problem is that I have (N separate) remote(s) with no outbound access, but will allow inbound (via ssh). – crimson-egret Apr 16 '16 at 20:34
  • @eggo, if you have a box that you need to push to and *also* do work on—just make a bare repo on that box for pushing to, and a separate non-bare repo on the *same* box where you can `git fetch` from the local bare repo. – Wildcard Apr 16 '16 at 21:39