Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git push -> code review only current change (remote.origin.push overrides push.default)

Tags:

git

config

gerrit

My team is using gerrit code review, essentially this means the default push behaviour bypasses the standard workflow so instead we need to use git push origin HEAD:refs/for/feature to correctly push our code to get reviewed.

The default push behaviour looks like this:

user$ git push --dry-run
To https://gerrit.company.url/project
   83fa2a5..aca3a22  feature -> feature

This would bypass the review process which is undesired.

When I set the push ref-spec (reference here) to be refs/heads/*:refs/for/* this takes a step in the right direction:

user $ git config remote.origin.push refs/heads/*:refs/for/*
user$ git push --dry-run
To https://gerrit.company.url/project
 * [new branch]      master -> refs/for/master
 * [new branch]      old_stuff -> refs/for/old_stuff
 * [new branch]      feature -> refs/for/feature

Now it is trying to push feature to refs/for/feature which is what I want but it's also trying to push all my branches to origin. Gerrit rejects more than one request so I get an output like this:

user$ git push
....
To https://gerrit.company.url/project
 ! [remote rejected] master -> refs/for/master (no new changes)
 ! [remote rejected] old_stuff -> refs/for/old_stuff (duplicate request)
 ! [remote rejected] feature -> refs/for/feature (duplicate request)

but I found that if I name the current branch it does what I'm expecting:

user $ git push origin feature --dry-run
To https://gerrit.company.url/project
 * [new branch]      feature -> refs/for/feature

This is great and I will be able to use this but I'd like to narrow it more. I figured if I set push.default to current it will mean that git push will only push the current branch in this way, but to my disappointment:

user$ git config push.default current
user$ git push origin --dry-run
To https://gerrit.company.url/project
 * [new branch]      master -> refs/for/master
 * [new branch]      old_stuff -> refs/for/old_stuff
 * [new branch]      feature -> refs/for/feature

This seems to be ignoring the push.default setting, From the git config documentation:

push.default

Defines the action git push should take if no refspec is explicitly given

So the remote.origin.push config gets interpreted as an explicit ref spec? Even when setting the default push behaviour to nothing it still tries to push all branches:

user$ git config push.default nothing
user$ git push
fatal: You didn't specify any refspecs to push, and push.default is "nothing".
user$ git config remote.origin.push refs/heads/*:refs/for/*
user$ git push origin --dry-run
To https://gerrit.company.url/project
 * [new branch]      master -> refs/for/master
 * [new branch]      old_stuff -> refs/for/old_stuff
 * [new branch]      feature -> refs/for/feature

What am I missing here? How do I get git push to only push the current branch like feature -> refs/for/feature?

like image 706
Tadhg McDonald-Jensen Avatar asked Oct 18 '18 16:10

Tadhg McDonald-Jensen


People also ask

Does git push default to Origin?

By default, Git chooses origin for the remote and your current branch as the branch to push. If your current branch is main , the command git push will supply the two default parameters—effectively running git push origin main .

Does git push overwrite?

push may overwrite refs other than the current branch (including local refs that are strictly behind their remote counterpart). To force a push to only one branch, use a + in front of the refspec to push (e.g git push origin +master to force a push to the master branch).

What is the difference between git push and git push origin?

Simply, we can say that git push command updates the remote repository with local commits. And origin represents a remote name where the user wants to push the changes.


1 Answers

I don't believe what you want to do can be done with just git currently.

I've been able to narrow it down one level further by defining remote server aliases in my config file like below, one for each branch I might want to push, but this is obviously tedious and obnoxious, and I still have to type something like git push masterrev.

    [remote "origin"]
        url = ssh://gerritserver/product
        fetch = +refs/heads/*:refs/remotes/origin/*
    [remote "masterrev"]
        url = ssh://gerritserver/product
        fetch = +refs/heads/*:refs/remotes/origin/*
        push = HEAD:refs/for/master

The only equivalent I know to provide your original goal is with 3rd party tools like the git-review tool that the OpenStack developers put together for their own use. It might be worth it if your team is planning to use gerrit, since it provides other functionality like easy access to cherry-picking or checkout of reviews.

As an aside, I believe the push.default setting of "current" means just to assume that the local branch name(s) should be pushed through the remote.*.push modification even if they aren't already known to exist on the server. It does not limit which branches are pushed to just the "current" one, but rather to use the "current" name(s).

like image 180
JustinB Avatar answered Nov 15 '22 05:11

JustinB