1

I'm working on a shell script I wrote to automatically sync a local branch with its upstream branch. It does this by:

  • first checking that there are no uncommitted changes locally, then
  • fetching any missing commits from the upstream,
  • doing a merge (or rebase), and finally
  • pushing the result back upstream.

The problem is that if the upstream is non-bare, there is a good chance that the push will fail with the infamous ! [remote rejected] master -> master (branch is currently checked out) error, due to the default value of receive.denyCurrentBranch. Therefore I would like to programmatically predict in advance whether the push will fail in this manner, so that I can push using a different refspec (e.g. $branch:refs/remotes/$src/$branch). This would at least guarantee that the remote contains the latest commits, even if they are not in the remote's working tree.

This could be done as follows:

  • connect to the remote server
  • jump through some hoops to calculate the absolute path of the repo on the remote, and chdir to it
  • execute git config core.bare
  • if it returns true then we know we won't get the [remote rejected] error on push
  • if it returns false, execute another command to determine which branch is currently checked out on the remote, to see if it matches the one being pushed

But this makes the assumption that ssh (or some other remote mechanism) is available for execution of arbitrary commands on the remote end, and it requires calculating the absolute path to the repo on the remote too, so it's not a clean, generally applicable solution.

Another option is just to attempt the push, spot when it fails in this manner, and retry with the modified refspec. But that's a bit ugly too. Is there a cleaner solution?

Community
  • 1
  • 1
Adam Spiers
  • 17,397
  • 5
  • 46
  • 65
  • Couldn't you just always push with the alternate refspec (`$branch:refs/remotes/$src/$branch`)? – Wesley Wiser Oct 22 '12 at 15:55
  • Well yes, I already mentioned that in the original question :) But I want to update the remote's local branch too when possible. After a bit more thought, I think I'm going to switch from the above approach of "push to whichever branch isn't checked out on the remote" to "always push to `refs/remotes/$src/$branch` *and* also attempt to push to `$branch` but don't worry if it fails due to `$branch` already being checked out". Maybe that's what you meant? But that requires checking for other errors, and also calculating `$src`. I'd still like to know a good answer to the original question :) – Adam Spiers Oct 22 '12 at 16:11

0 Answers0