The eclipse EGit plugin provides a push wizard to push changes into a Git repository. At the end of the wizard there is a confirmation dialog with the checkbox "Push only if remote refs don't change in the mean time", as described on the EGit documentation page "http://wiki.eclipse.org/EGit/User_Guide#Push_Confirmation".
According to the Git book, chapter 2.5 (https://book.git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes), Git will reject a push to the remote repository if another person has pushed some changes in the mean time (since the last synchronization/fetch).
So my question is: What is the use for the described check box if the push would be rejected anyway in case the remote repository has changed since the last fetch?
To open the dialog with the described option you need to perform the following steps:
I don't use EGit so I have to guess a little bit, but from what's on the page of theirs that you linked, it seems that their push dialogue is using several Git features behind the scenes.
According to the Git book, chapter 2.5 (https://book.git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes), Git will reject a push to the remote repository if another person has pushed some changes in the mean time (since the last synchronization/fetch).
This is not wrong, but is also not the entire picture.
When you run:
git push <remote> <refspec>
your Git calls up another Git over the Internet-phone and your Git and their Git—the "foreign" Git, as the githooks documentation calls it—have a conversation. Your Git sends the foreign Git your new-to-them commits, and then sends requests or commands of the form:
Please, if you like, set your
master
to point to commit1234567
or:
I command you: set your
master
to1234567
now!
There are three parts to this conversation: one to establish what your Git and the foreign Git are going to talk about at all; one to transfer the commits (and any other appropriate Git objects); and a final one to direct the foreign Git about what reference-updates to make, i.e., whether your branch updates are polite requests ("do this if you like it") or commands ("take this now dammit"). (We should also note that it's not just branch names; this same stuff applies to tags, and any other reference. They all work fairly similarly though.)
But there are also two Gits in this conversation: yours, and the foreign Git. That's all well and good, but there are more than two Gits in the world. What if a third Git is conversing with the foreign Git? It's possible that your Git and another Git are both talking to the foreign Git at the same time.
The Pro Git book is concerned with the big problem here, which is that the foreign Git might acquire new commits on its branches some time before you send a polite "please set" request. In that case, when you send the polite "please set" request, the foreign Git says: "no, if I do that, I will forget commits that I have that you don't." In that case, as the book says, they reject the push and you can fetch their new commits, integrate all their new-to-you commits with yours, and retry.
But this is where the more forceful, command-like option comes in: you may insist that they forget these commits. They can still refuse, but if they do not refuse, you can get them to forget some commits. This step is somewhat dangerous: Even if you fetch their commits first (to see what you're asking them to forget), there could be a third Git actively conversing with the foreign Git, so that by the time you verify that those are the commits you want them to forget, their branch name to commit hash mappings may have changed.
Hence there's yet another option in modern versions of Git, to atomically set references if and only if they match what you think they match. That is, you have your Git send a command: "set master
to 1234567
!" leavened with "... but only if it's currently fedcba9
!" This gives you a chance to fetch from the foreign Git, make up your mind about what to do, and then send them commands that are conditional on the foreign Git not having changed those branches (or other references) yet, to make sure you are not interfering with a third Git.
Git calls these atomic compare-and-swap updates --force-with-lease
.
EGit seems to want to be especially helpful to you (on your end of this conversation), to figure out what will happen in the future, in each half of this conversation that has not even started yet! Here you are looking at your GUI with its clicky boxes and buttons, and your Git has not even called up the foreign Git over the Internet-phone yet to start the transfer, and your EGit GUI is trying to guess what will happen in the future, even though there might be other Gits out there talking to the foreign Git right now.
So your EGit GUI pulls a little trick: it has an early conversation with the foreign Git. It calls up that Git right now, and asks it: "hey, what commits do your branches name?" If your EGit has those commits, your EGit can figure out what commits you will send them. If your EGit does not have those commits, your EGit can get them, and then figure out what commits you will send them.1 So now your EGit has a really good idea of what it will send them and what it will see in their branch name (and other references) to hash ID mappings.
So, your EGit GUI can show you these things. But then when you click the final "go" button, your EGit will call up their Git again and actually start the two-part conversation—and maybe some third Git got there first, and the conversation won't go the way your EGit GUI thinks it will. That's where these extra confirmation clicky boxes come in.
It's not entirely clear whether EGit is using the "conditional command" option. A receiving foreign Git does not entirely lock out "third Git" updates during the possibly-lengthy conversation that sends commit and other objects across the Internet-phone-wires. They do get an initial set of name-to-ID mappings and can abort the conversation immediately if that does not match what they expect; then they must have the middle part of the conversation that actually sends objects; and then they have the final, update-the-foreign-Git's references part of the conversation. Do the clicky boxes work only on the first part, or do they affect any final commands-vs-polite-requests too? That is not clear to me.
But, that is the answer to this:
So my question is: What is the use for the described check box if the push would be rejected anyway in case the remote repository has changed since the last fetch?
It might use the conditional (force push only if things have not changed) feature, or it might be "abort the conversation if things don't even start as planned", or it might even do both. The images at the documentation you linked have a separate clicky box for "force push", so presumably the EGit GUI will not send its final requests as commands unless that box is also checked. Whether checking the second confirmation box turns these into atomic-swap commands, I don't know; but if it doesn't, the initial check is not sufficient, because "third Gits" may update the foreign Git references during the object-transfer part of the conversation.
Hence I would say: this either offers you a feel-good thing that does not really have any effect; or, it turns on --force-with-lease
.
1I don't know if EGit actually does this—runs a git fetch
invisibly—but if it doesn't it cannot correctly calculate the set of commits that will be sent in the future.