Why is git push gerrit HEAD:refs/for/master used instead of git push origin master
Asked Answered
H

2

170

I've just started using gerrit and I want to know why we need to do git push gerrit HEAD:refs/for/master instead of doing git push origin master

If I do git push origin master I get the error saying ! [remote rejected] master -> master (prohibited by Gerrit)

Heterophyllous answered 5/5, 2012 at 11:5 Comment(1)
although there are some answers, but it is like "lie to the client", and "magical". So this is what I don't like about the current state of software engineering: nobody at work really knows what's happening, and the push actually gives a fatal: internal server error but together with a print out of remote: SUCCESS which seem conflicting messages, and sometimes the tests kicked off by Gerrit works, sometimes doesn't, without anything changed at all. The feeling that nobody knows what's happening is not goodPals
L
288

The documentation for Gerrit, in particular the "Push changes" section, explains that you push to the "magical refs/for/'branch' ref using any Git client tool".

The following image is taken from the Intro to Gerrit. When you push to Gerrit, you do git push gerrit HEAD:refs/for/<BRANCH>. This pushes your changes to the staging area (in the diagram, "Pending Changes"). Gerrit doesn't actually have a branch called <BRANCH>; it lies to the git client.

Internally, Gerrit has its own implementation for the Git and SSH stacks. This allows it to provide the "magical" refs/for/<BRANCH> refs.

When a push request is received to create a ref in one of these namespaces Gerrit performs its own logic to update the database, and then lies to the client about the result of the operation. A successful result causes the client to believe that Gerrit has created the ref, but in reality Gerrit hasn’t created the ref at all. [Link - Gerrit, "Gritty Details"].

The Gerrit workflow

After a successful patch (i.e, the patch has been pushed to Gerrit, [putting it into the "Pending Changes" staging area], reviewed, and the review has passed), Gerrit pushes the change from the "Pending Changes" into the "Authoritative Repository", calculating which branch to push it into based on the magic it did when you pushed to refs/for/<BRANCH>. This way, successfully reviewed patches can be pulled directly from the correct branches of the Authoritative Repository.

Lashaun answered 5/5, 2012 at 12:5 Comment(11)
Out of curiosity, what really happens if you do something like "git push origin" only? I tried it and cannot see the change anywhere, thus the question. But it does exist in my local log, naturally.Osteomyelitis
@Pintolaranja I did the same accidentially. You're right, Gerrit "handles" such situation, but it does not create any change. So actually, it does not handle it at all. Which really pisses me off, as this is really stupid. Why to allow user to commit something, that Gerrit is unable to properly handle?Shu
Are the "Fetch" arrows in this diagram pointing in the right direction?Atonic
@gregb Yes. The arrows indicate the source and destination of the command, not any subsequent data flow as a result of it. e.g. Developer 1 issues a fetch to the Authoritative Repository, not the other way aroundBacktrack
@Shu It allows that because Gerrit allows you to configure some accounts to bypass reviews. By pushing to the default branch you're effectively saying "I want to merge this change without a review." If you're not allowed to do that, the push fails.Electroballistics
Is there a way to pull a change back from the "pending changes" section? I am in a situation where I have committed a change to the pending changes section, but then accidentally reset my local branch containing that change. Now, I need to do a commit --amend to that change because Gerrit won't accept another plain commit due to unique constraints and its essentially setup to only allow amendments to the originalPolite
Nervermind, I think I see the command on the Gerrit UI under the patch set.Polite
Any idea why my push to refs/for/masters1 works while my push to refs/for/s4op-1610sp0 does not? Both remote branches exist on Gerrit. Is it because of the minus - in the branch name?Norenenorfleet
I am missing one point here. Assuming you have an existing repo and you want to add it to gerrit for review, I believe that adding it manually to the list of gerrit repos won't do the magic of creating these staging branches right? Do I need to add the repo through the ssh command interface? I did it manually and the funny thing is that when I push to gerrit HEAD:refs/for/branch_name I don't get any errors, I don't see a review request pending in the web interface.Uracil
Also, and probably worse, I can't even see that branch in the gerrit repo, although I could see the usual success log: To ssh://my_url:/path_to_repo/my_repo.git 6700002..47c40df HEAD -> refs/for/branch_nameUracil
In fact, if the git/gerrit interoperation had been built properly you wouldn't have to do such foolishness and would simply do "git push origin" (better yet, just "git push") Then git/gerrit would be configured in such a way that it would automatically place your changes in a staging area for code review. Forcing you to push to a different location than the one you intend to change is just dumb, adds confusion, and that leads to mistakes.Amorita
T
70

In order to avoid having to fully specify the git push command you could alternatively modify your git config file:

[remote "gerrit"]
    url = https://your.gerrit.repo:44444/repo
    fetch = +refs/heads/master:refs/remotes/origin/master
    push = refs/heads/master:refs/for/master

Now you can simply:

git fetch gerrit
git push gerrit

This is according to Gerrit

Trichoid answered 12/4, 2015 at 3:10 Comment(5)
+1 from me! It's way nicer just having this hard-coded for my remote.origin.push instead of having to type / paste it every time!Dode
@SeanMurphy You can make it more general by replacing instances of 'master' with '*' so that something like 'git push gerrit TopicBranch' will also work.Radiometer
Also, if gerrit is your only remote you don't have to specify it at all. I simply do git fetch and git push with the config @DavidDoria mentioned above.Shakitashako
push = refs/heads/*:refs/for/* is for all branchesElboa
You really need to use the upstream branch, not your current branch. I usually have a dozen or so changes going on in parallel, so using a single branch just doesn't work.Athwart

© 2022 - 2024 — McMap. All rights reserved.