Git trick #481: Prevent accidentally pushing into git instead of Gerrit

Some while ago I wrote about a little [git hook that automatically sets up your commit author identity][1]  after git clone based on the remote origin address. Recently I learned that in git 2.8 a new pre-push hook was introduced, and I immediately knew it will fix my second biggest pain point: accidentally pushing directly into git instead of Gerrit.

If you often switch between different projects where some use Gerrit for code review and some don’t, it’s very easy to just mistakenly do

git push master

when in fact you wanted to

git push HEAD:refs/for/master

There are some tricks how to make it harder for you to accidentally do this, like creating a “gpush” alias that pushes to refs/for/master and disabling pushing into the ‘origin’ remote by changing the push URL to something invalid. That, however, is not perfect because there are still ways how to by-pass it. And it becomes complicated if you use more than one remote and it’s clumsy if you sometimes do want to push directly into git (for example to submit a large patch series).

With a custom pre-push hook, we can check if the remote that we are pushing into is a Gerrit instance and then check if the remote ref that we are pushing into is a “Gerrit ref” (refs/for/foo) instead of a regular branch and we can have a nice “Are you sure you want to do this?” prompt:

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# (C) 2017 Daniel Vrátil <dvratil@kde.org>
# License: GPL

import os
import sys

def remoteIsGerrit(remoteName, remoteUrl):
    # if the remote is called "gerrit", assume it's Gerrit
    if 'gerrit' in remoteName:
        return True
    # if the remote URL contains the default Gerrit port, assume it's Gerrit
    if ':29418/' in remoteUrl:
        return True

    # TODO: Add custom checks to match your non-standard Gerrit configuration
    return False
def main():
    # name and URL of the remote we are pushing into is passed as arguments
    if not remoteIsGerrit(sys.argv[1], sys.argv[2]):
        # If we are not pushing into gerrit, then simply allow the push
        return
    # The pushed refs are passed in via stdin
    for line in sys.stdin:
        # line = "localRef localRev remoteRef remoteRev"
        remoteRef = line.split(' ')[2]
        # Check if the remoteRef contains the typical Gerrit 'refs/for/foo'.
        if not remoteRef.startswith('refs/for/'):
            print('!!')
            print('!! You are pushing directly into git instead of Gerrit !!')
            print('!! Do you want to continue? [y/N] ', end = '', flush = True)
            if open('/dev/tty', 'rb').readline().decode().strip().lower() == 'y':
                return
            else:
                sys.exit(1)

if __name__ == "__main__":
    main()

Save this a file as “pre-push” and move it into .git/hooks/ folder in your local repository clone. Remember to make the script executable.

Here is how it works: trying to push into “gerrit” remote to branch “5.9” directly gets intercepted by our new hook and if you press ‘n’ the push gets aborted. If I would’ve pressed ‘y’, then the push would proceed.

$ git push gerrit 5.9
Enter passphrase for key '/home/dvratil/.ssh/id_rsa.qt':  
!! 
!! You are pushing directly into git instead of Gerrit !! 
!! Do you want to continue? [y/N] n
error: failed to push some refs to 'ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase.git'</pre>
<p>Now when we try to push to the correct ref (`refs/for/5.9`) the hook accepts the push without any complaints:</p>
<pre>$ git push gerrit HEAD:refs/for/5.9
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 407 bytes, done.
Total 4 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2)
remote: Processing changes: new: 1, refs: 1, done    
remote: 
remote: New Changes:
remote:   https://codereview.qt-project.org/......
remote: 
To ssh://dvratil@codereview.qt-project.org:29418/qt/qtbase
 * [new branch] HEAD -&gt; refs/for/5.9

To have the hook automatically copied into every new repository that you clone, save it as “pre-push” into .git-templates/hooks/ and run the following command:

git config --global init.templatedir ~/.git-templates

Git will automatically copy everything from the ‘templatedir’ into the .git directory after every new git clone, so you don’t need to bother with doing that manually. Unfortunately for all your existing checkouts, you have to copy the hook manually

[1] /2015/12/git-trick-628-automatically-set-commit-author-based-on-repo-url

Git trick #628: automatically set commit author based on repo URL

If you have more than one email identity that you use to commit to different projects you have to remember to change it in .git/config every time you git clone a new repository. I suck at remembering things and it’s been annoying me for a long time that I kept pushing commits with wrong email addresses to wrong repositories.

I can’t believe I am the only one having this problem, but I could not find anything on the interwebs so I just fixed it myself and I’m posting it here so that maybe hopefuly someone else will find it useful too :).

The trick is very simple: we create a post-checkout hook that will check the value of user.email in .git/config and set it to whatever we want based on URL of the “origin” remote.  Why post-checkout? Because there’s no post-clone hook, but git automatically checkouts master after clone so the hook gets executed. It also gets executed every time you run git checkout by hand but the overhead is minimal and we have a guard against overwriting the identity in case it’s already set.

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (C) 2015 Daniel Vrátil &lt;dvratil@kde.org&gt;
# License: GPL
#
# Requires: Python 2 or 3 and compatible GitPython
#
# https://github.com/gitpython-developers/GitPython
import git
import ConfigParser
import os
import sys

repo = git.Repo(os.getcwd())

# Don't do anything if an identity is already configured in this
# repo's .git/config
config = repo.config_reader(config_level = 'repository')
try:
    # The value of user.email is non-empty, stop here
    if config.get_value('user', 'email'):
        sys.exit(0)
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
    # Section or option does not exist, continue
    pass
origin = repo.remote('origin')
if not origin:
    print('** Failed to detect remote origin, identity not updated! **')
    sys.exit(0)
# This is where you adjust the code to fit your needs
if 'kde.org' in origin.url or origin.url.startswith('kde:'):
    email = 'dvratil@kde.org'
elif 'fedoraproject.org' in origin.url:
    email = 'dvratil@fedoraproject.org'
elif 'kdab.com' in origin.url:
    email = 'daniel.vratil@kdab.com'
else:
    print('** Failed to detect identity! **')
    sys.exit(0)
# Write the option to .git/config
config = repo.config_writer()
config.set_value('user', 'email', email)
config.release()
print('** User identity for this repository set to \'%s\' **' % email)

To install it, just copy the script above to ~/.git-templates/hooks/post-checkout, make it executable and run

git config --global init.templatedir ~/.git-templates

All hooks from templatedir are automatically copied into .git/hooks when a new repository is created (git init or git clone) - this way the hook will get automatically deployed to every new repo.

And here’s a proof that it works :-)

[dvratil@Odin ~/devel/KDE]
$ git clone kde:kasync
Cloning into 'kasync'...
remote: Counting objects: 450, done.
remote: Compressing objects: 100% (173/173), done.
remote: Total 450 (delta 285), reused 431 (delta 273)
Receiving objects: 100% (450/450), 116.44 KiB | 0 bytes/s, done.
Resolving deltas: 100% (285/285), done.
Checking connectivity... done.
** User identity for this repository set to 'dvratil@kde.org' **

[dvratil@Odin ~/packaging/fedpkg]
$ git clone ssh://dvratil@pkgs.fedoraproject.org/gammaray
Cloning into 'gammaray'...
remote: Counting objects: 287, done.
remote: Compressing objects: 100% (286/286), done.
remote: Total 287 (delta 113), reused 0 (delta 0)
Receiving objects: 100% (287/287), 57.24 KiB | 0 bytes/s, done.
Resolving deltas: 100% (113/113), done.
Checking connectivity... done.
** User identity for this repository set to 'dvratil@fedoraproject.org' **

Update 1: added utf-8 coding (thanks, Andrea) Update 2: changed shebang to more common /usr/bin/python (/bin/python is rather Fedora-specific), added “Requires” comment to top of the script (thanks, Derek)

How free software makes us better people

I don't write this kind of blogs very often (actually not at all), partially because I don't have much to say, partially because I suck at it (as you'll probably find out yourself if you decide to continue reading). However this evening I had a nice cup of tea with a friend of mine and I'm feeling oddly relaxed now. I remembered an earlier discussion we had and it made me think about my inner motivations. In this text I tried to follow all my thoughts and see if they lead anywhere.

This post is about helping. Helping others and helping myself and why I think it's free software, and the community around it that brings up the good in me and in others. Those who were in Brno on last year Akademy might find this kinda similar to Cornelius' keynote about how KDE makes us better people, and it might as well be, since I really liked the keynote and agreed with everything Cornelius said. But I want to tell my story here, so bare with me...:)

Maybe what I'm writing here is absolutely obvious to everyone, but maybe it will help someone to realize what I realized while writing this post. But most of all it helped me to sort out my own thoughts, and I think that after a long time I won't have troubles falling asleep tonight. Maybe I should start writing this kind of stuff more often... :-)




People help other people. That's how the world works. But why do we help others? Because it's a good thing to do? Because it makes us feel better? I guess I first thought about my motivations to help a couple weeks ago when I attended an HTML and CSS workshop organized by Czechitas - a Czech non-profit organization where girls teach other girls IT and programming. You might have heard about Rail Girls, so Czechitas is something similar and they are organizing workshops on various topics - from web coding and WordPress to graphical design (using open source tools!). Each workshop is also attended by tutors (that's where I come in) who have some experience in the subject and who guide a small group of girls during the workshop, answer their questions and help them with their project. One question I got during that workshop was "Why?" - why are we willing to spent our entire Saturday just by sitting there and watching bunch of people we don't know to struggle with HTML. I also got asked the same question couple days later when I talked about this to my friend and it made me think again - why indeed?




I think I always wanted to help people somehow. It makes me feel useful, it makes me feel good and I learn a thing or two during that, which is also important to me. I guess the first moment I realized this was back in 2009, when I started packaging weekly development snapshots of KDE for ArchLinux. I've been using Arch for over 2 years back then, but I was really just a user, I did not contribute in any way. I did not help. I felt I've been given so much, but I never gave anything in return.




I live in a sort of a bubble. My own world, my own reality. My day job involves working on free software, so I spend most of my time surrounded by free software hackers and other like-minded people. Thinking about it, I probably talk to other devs on IRC more than I do to my flatmates. But I don't mind. I take the community as my second family, I consider some people there to be my very close friends and I really cannot express in words what being part of this family means to me. And what influences us more than our own family?




I see programming as a form of art. It's creating something from pure thoughts and imagination. It's building castles out of LEGO bricks, walking those castles and describing them in a form of a code. I do what I do because I enjoy it, because I don't completely suck at it (some of the time), because I get recognized for what I do, and because I can actually see how what I do helps other people.




Richard Stallman defines "free" in free software as 'free as in free speech, not free beer". We are free, because we can take others' ideas and build on them and we let others to take ours and build on them too. We share. We build powerful and high quality software because we share it with everyone, and we allow anyone to step in and help push it forward. We don't want to see their CV, we don't care what they have achieved in their life. We care about what they can achieve in the future If we let them. For a while I thought we were doing it simply because we want to use their potential to help us with our cause, our product. But now I see how wrong I was. After my first Akademy, my first chance to meet the community in person I realized it. We do it because we want to help those people. We want to help them to get better at what they do. We want to help them become part of the family. And we do so, because that's how we became part of it. Because someone there cared enough. Because someone helped us and because we know it's the right thing to do. We do it because we want to share the happiness we get out of being part of the family.




I guess this is where my thoughts lead. We don't help, because we must, or because we are expected to. We help because we believe in it and because we believe it is the right way to make the world a better place. Ultimately it does not matter if I spend 30 seconds answering someone's question on IRC, or if I spend a few hours helping uncountable many people by fixing a bug or implementing a new feature, or if I spend all day helping three girls to learn HTML. It's not possible to say which is more useful, as we cannot see the full potential of those people. But we can help them. We can guide them and let them discover what they can do. And who knows, maybe the next person we help will achieve great things, and maybe those things will directly affect us, and help us in return. And even if they don't, we will still teach them to help others - and they might be the ones to help someone else to do great things.

How does free software fit into all this? We help by sharing - we share what we know and we let others share that knowledge further, because knowledge is really the foundation of everything else. And we don't care how much time it costs us.

I cannot really say what would I be like if I never got involved in free software. What I can say for sure however is that free software made me a better person. It taught me to share what I know with others and it taught me to help others. And yes, by free software I don't mean any program. I mean the people.

My Top10 Sci-Fi shows

As maybe not mentioned anywhere in this blog, I'm also a big fan of scifi series. I've been to Festival Fantazie, first in summer 2010, then again in autumn. By that time I've already seen some series, but it really encouraged me to see more. I was talking about publishing my top-scifi chart and to-see list, so finally here it comes.

Seen series

I created the list of following shows, so the best (for me) series are on the top. As time goes, I'll be updating this post, moving series from to-see to this list.

1. Babylon 5

I haven't seen the last two seasons yet, but I can already place Babylon 5 on the second place. First place be it! In many aspects it's better then FarScape, but on the other hand, it lacks the proper kind of humor and universe I was used to from FarScape (I've seen FS just before B5). First I was afraid that I won't like all the talking and politics involved, but actually that's the thing which keeps me at the series. And Sheridan, of course :) There's nothing our brave captain couldn't solve. I'm looking forward to see the last two series in hope, that Ivanova will get more space, becuase I think she's absolutely amazing.

Update 2011-04-25: So I've finished B5 last week. I really missed Ivanova in season 5, but the more happy I was when she appeared in the last episode. The final two parts were really moving and really awesome. B5 is now my #1 show. I'll really miss the guys.

2. FarScape

So, to explain this a little. I knew both Ben Browder and Claudia Black from SG-1, but I was really surprised. Crichton is much better written then Mitchell, and Aeryn is absolutely something different then Vala. First season was somehow boring, it really didn't took me in. But with Scorpius entering the show on full-time I just become to love the series. I've seen seasons 3 and 4 within one month (which is actually quite a short time for me!). The Peacekeeper Wars miniseries were very very good and led to a very good final, but for me, personally, the best final ever has BSG. Also, FarScape has absolutely the best Universe I've seen in scifi series.

3. Doctor Who 2005

Hey, Tennant is my Doctor! When I finally became to like The Ninth Doctor, he just changed and David came in. It took me about two episodes to get used to him and I become to love him soon. He's the best, ever will be. Smith is barely adequate follower for Tennant.

The idea of the entire Doctor is simply brilliant, they couldn't have made it better. There are only two big fails in the Doctor: Moffat and Smith. I don't like Karen either, but at least she's pretty :) Talking about companions, Rose is the best one for me. I don't think that Moffat is a bad writer and Smith bad actor, no. They're both very good, I just don't like their new style of Doctor. Well, let's see how it will change in season 6 this year, otherwise I'll have them all exterminated.

Update: season 6 was...hmm...avarage.

4. BattleStar Gallactica

BSG was my first really-scifi (SG-1 does not count). Second season was absolutely the best, I've seen it in one day, I just couldn't stop. The third season, on the other hand, was the worst - just boring. It was not bad, but it just didn't have the action and speed of the previous season. It is a very very good show, and the final is simply the best I've ever seen (yet). Strong, well done and absolutely unexpected. My favourite characters were admiral Adama, Kara and Chief. Unfortunatelly Kara and Cheif changed a lot and at the end their characters were, at least weird.

5. Firefly

Firefly! It will run for years...well it didn't because of the idiots in Fox, but still, it is a great show. It is very original - western scifi, duh! Nathan is a great actor and made watching the series a great fun for me. And I HAVE to mention Morena too. I've seen her in two or three episodes of V (haven't seen more yet) too and she's still so damned hot!! :) It's quite short, you can see it over night (or three nigths, like me) and it is definetely a must-see. And there's one more reason to see FireFly, and that's Jewel Staite and her smile.

6. Torchwood

I say TORCH, you say WOOD! This Doctor Who spin-off is a great for relaxation. It's very lamer but that's what make it so fraking awesome. I was quite surprised actually that a british thinkg can contain so lot of homosexuality, but it's the best they could've done. Harkness, being all-sexual, giving it with everyone and  everything..duh! Torchwood is so great because it's so lame - simply as that. If you don't have nothing else to do or see, you definetely go for this. I'm just little worried about the fourth season, which was shot in US.

Update: season 4 was cool - Gwen with bazooka? Go Torchwood, go!

7. Stargate SG-1

Stargate is a greate phenomenon, but in total, it's a nonsense. How it comes that everyone in the entire universe speaks English :)? It's very long and I really liked only the first five or so series. Oris could've been a good revival for the series, but unfortunatelly it was cut too soon. SG-1 is important for me in one way: it was the first sci-fi series I really begun to watch. And I don't regret it, because it moved me further, to BSG.

8. Stargate Atlantis

New, fresh and good idea, acutally a spin-off from one of the storylines of SG-1. Torri Higginson is a great leader (and actress of course!), and I really missed her in the fourth and fifth season. It's not the best scifi ever, but it's something worth seeing. But only when you've seen all the other series.

9. Startgate Universe (season 1)

Yet another SG spin-off. The only SG-related thing is the gate, but there it ends. It's not bad - they've met aliens and they have secrets (especially Rush). I've seen few episodes from the second season and it seems to be good, I'll know more when I see all. The first season was very unbalanced I think. There were very very bad episodes, followed by two or three weeks long pause and the came two abso-freakin-lutely awesome episodes.

10. Red Dwarf (I really must see it again)

Red Dwarf is not 10th because I wouldn't consider it a good (good? Awesome!) series, but because it's much more sitcom then sci-fi and because it's a long time I've seen it and I really must find some time to see it again. Jokes and quotes are simply legen-wait for it-dary!!

To see

So here comes the the "to-see" list of scifi series:
  • Star Trek
  • Caprica
  • Stargate Universe, season 2
  • Pioneer One (soon as there will be more episodes)
  • Red Dwarf
  • V

The order is random, just as I recalled the shows. What I can say now is, that I will probably give V second chance when I'm finished with Babylon 5, followed by Caprica and SGU S02.

I hope I didn't forget any series. I will try to return to this as soon as something changes. For now, I think it's quite enough :)