The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

git-gerrit - Git extension to implement a Gerrit workflow

VERSION

version 0.010

SYNOPSIS

    git gerrit new         [--update] TOPIC [BRANCH]
    git gerrit push        [--keep] [--force] [--[no]rebase] [--draft]
                           [--topic TOPIC] [--reviewer USER] [--cc USER]

    git gerrit query       [--limit LIMIT] [--verbose] [[NAME=]QUERY]*
    git gerrit my          [--limit LIMIT] [--verbose] [changes|drafts|watched|starred]
    git gerrit show        [CHANGE]

    git gerrit checkout    [CHANGE]
    git gerrit upstream    [--keep]
    git gerrit cherry-pick [OPTIONS]* CHANGE

    git gerrit reviewer    [--add USERS] [--confirm] [--delete USERS] [CHANGE]
    git gerrit review      [--message TEXT] [--keep] [[LABEL]=VOTE]* [CHANGE]
    git gerrit abandon     [--message TEXT] [--keep] [CHANGE]
    git gerrit restore     [--message TEXT] [CHANGE]
    git gerrit revert      [--message TEXT] [CHANGE]
    git gerrit submit      [--no-wait-for-merge] [--keep] [CHANGE]

    git gerrit config
    git gerrit version

DESCRIPTION

Git-gerrit is a Git extension to manage changes using Gerrit Code Review.

Git-gerrit offers a rich set of sub-commands to make it easy to create, query, amend, review, and submit changes to Gerrit, making it possible to interact with it through the command-line, avoiding its web interface most of the time and improving your efficiency. The goal is to make Gerrit's review process feel like a natural extension of Git.

Git-gerrit provides three main features:

  • An easy and safe way to push changes to Gerrit through the git gerrit push sub-command, avoiding the need to type remote names and long refspecs.

  • A standard way to map Gerrit changes into local branches, referred to as "change-branches", making it easier to manage several changes simultaneously and to perform the fetch-amend-push review cycle.

  • Several sub-commands to query and inspect Gerrit changes and also to review and submit them.

Git-gerrit is implemented on top of Gerrit's REST API, which was consolidated in its version 2.6. As this API matures, expect git-gerrit to incorporate new functionality.

There are a few alternatives to git-gerrit described below.

INSTALLATION

Make sure you have at least Perl 5.10 installed. Check this with:

    perl -v

Then, you should install the App::GitGerrit distribution from CPAN. The best way to do it is to use a CPAN package installer, such as cpanm, like this:

    cpanm App::GitGerrit

If you don't have cpanm already, read the INSTALLATION section of the App::cpanminus module.

The cpanm should take care of other Perl dependencies for you. The git-gerrit script should be installed in a directory already in your PATH. To read its documentation you can type

    perldoc git-gerrit

CONFIGURATION

You must tell git-gerrit how to interact with your Gerrit server by defining a few configuration variables in Git's git-gerrit configuration section. All these variables are required. If they aren't set, git-gerrit will provide a helpful message telling you how to set them up.

  • git-gerrit.baseurl

    The base URL of your Gerrit server. This usually can be configured globally, if you have a Gerrit server hosting several of your repositories. It's a good idea to insert your username into this URL to avoid being asked for it interactively.

  • git-gerrit.project

    The project name associated with your repository.

  • git-gerrit.remote

    The Git remote name you use to push commits to and fetch commits from your Gerrit server.

AUTHENTICATION

If you have Git 1.8.0 or later, git-gerrit uses Git's credential management system via its git-credential command to obtain credentials for connecting to Gerrit. You can take advantage of this by configuring Git's credential.helper variable to use a persistent credential storage and avoid being asked for the authentication credentials repeatedly. Please, read gitcredentials manpage to know how to configure this system. But here are a few tips anyway:

  • On Ubuntu Linux (tested on 13.04)

    Use the git-credential-gnome-keyring program which provides a very nice integration with your desktop environment. You have to compile the helper first:

        sudo apt-get install libgnome-keyring-dev
        sudo make -C /usr/share/doc/git/contrib/credential/gnome-keyring
        git config --global credential.helper /usr/share/doc/git/contrib/credential/gnome-keyring/git-credential-gnome-keyring
  • On other Unix-like systems

    The git-credential-cache command which comes with Git is as a balanced compromise between convenience and security:

        git config --global credential.helper cache --timeout 86400
  • On Windows systems

    The best choice seems to be the third-party application git-credential-winstore, which you have to install first.

        git config --global credential.helper winstore

If you're using a pre-1.8 Git that doesn't support the git-credential command, there are a few fall-backs.

First, git-gerrit tries to get credentials from the git-gerrit.baseurl configuration variable. The URL should be in a format like https://username:password@host/path. Security conscious people should avoid putting credentials there, but if you do git-gerrit will be satisfied.

Then, git-gerrit tries to load Perl's Net::Netrc module, if available, to get credentials from a netrc(5) file.

As a last resort, git-gerrit tries to load Perl's Term::Prompt module to prompt you for the credentials.

If none of this works, git-gerrit dies screaming.

GLOSSARY

There are a few concepts that should be clear in order to the sub-commands documentation below to make sense.

change

Each commit pushed to one of Gerrit's virtual branches (refs/for or refs/drafts) creates a change for review.

Change-Id

A Change-Id is a 40-hexadecimal characters long SHA-1 hash prefixed with an I. It uniquely identifies a change and is normally generated by the commit-msg hook and inserted in the commit message footer.

{change-id}

A {change-id}, is a more general identifier used by Gerrit's REST API to uniquely identify a change . It can be expressed in one of three forms:

  • As an ID of the change in the format "<project>~<branch>~<Change-Id>", where, for the branch, the refs/heads/ prefix can be omitted (e.g., myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940).

  • As a Change-Id if it uniquely identifies one change (e.g., I8473b95934b5732ac55d26311a706c9c2bde9940).

  • As a legacy numeric change ID (e.g., 4247).

You may pass any form of change-id to git-gerrit's sub-commands when they require a CHANGE argument. Most commonly, you'll be using the legacy numeric ID, just because it's more convenient.

upstream branch

You normally should avoid creating changes directly on a local tracking branch. Instead, you should create a local topic branch deriving from the tracking branch to work on each change. We refer to the tracking branch from which your topic branch derived as the topic's upstream branch.

change-branch

A change-branch is a local branch with a special name that git-gerrit creates and maps to a Gerrit change.

When the sub-command git gerrit new TOPIC BRANCH starts a new change it creates a topic branch named change/BRANCH/TOPIC, which we call a change-branch. We refer to BRANCH as the change-branch's upstream, because it is the branch from which the change-branch derives and to which it will be ultimately merged back again.

When git gerrit checkout CHANGE fetches an existing change it creates a change-branch named change/BRANCH/ID, where BRANCH is the name of the branch associated with the change, and ID is its legacy numeric change ID.

So, you should reserve the change/ top-level branch name for the change-branches managed by git-gerrit.

SUB-COMMANDS

Each git-gerrit sub-command has its own set of options, described in its own section below.

The --debug option is accepted by all sub-commands:

--debug

This option makes git-gerrit print to STDERR every system command (usually a Git command) invoked and every Gerrit REST call made during the execution of its sub-commands. System commands are prefixed with CMD: and Gerrit REST calls with GERRIT:.

Options names may be abbreviated to uniqueness, case does not matter, and a single dash is sufficient, even for long option names.

git gerrit new [--update] TOPIC [BRANCH]

The new sub-command starts a new change on top of the current branch or BRANCH, if specified. It creates a new change-branch off of BRANCH called change/BRANCH/TOPIC and checks it out for you to start making changes to your working area.

The TOPIC name must contain at least one non-digit character so that it's clear that this is a new change-branch, not yet pushed to Gerrit. Also, the TOPIC name cannot contain slashes so that it's not confused with the branch name. It's usually best to use only letters and hyphens.

--update

This option makes git-gerrit update BRANCH before creating the change-branch by fetching from Gerrit and fast-forward-merging it with its remote branch. This way you guarantee to start a change on top of the newest state of your project, which is usually the right thing to do.

You will be warned if your working area is dirty, as this is sometimes a mistake.

git gerrit push [--keep] [--force] [--[no]rebase] [--draft] [--topic=TOPIC] [--reviewer USERS] [--cc USERS]

The push sub-command should be invoked to push a change-branch to Gerrit's refs/for/ branch associated with its upstream branch. It should be invoked when you have the change-branch checked out in your working area.

When a new change-branch is pushed it creates a Gerrit change associated with the TOPIC in its name, as created by git gerrit new above.

After a successful push, git-gerrit checks out the upstream branch and deletes the original change-branch. The goal is to maintain a clean namespace, containing only the change-branches that are being worked on. When you push one to Gerrit, you don't need to keep it any longer locally. If you need to amend it later, you'll be able to get to it with the git gerrit checkout sub-command.

--keep

This option tells git-gerrit not to checkout the upstream and not to delete the change-branch, keeping your working area intact.

--force

By default, git-gerrit refuses to push a change-branch if it contains more than one commit dangling from its upstream. It's best to avoid multiple commit pushes, because if you have to amend them later, having multiple commits may require rebasing dependent commits, which is a more complex operation and clutters the review history of the change.

This option makes git-gerrit perform multiple commit pushes without complaining.

--[no]rebase

Before a brand new change-branch (one ending in a TOPIC name) is pushed, its upstream branch is updated and it is rebased on top of its upstream. This is to make sure you're pushing a change based on the newest project state. If, by any reason, you don't want to have it rebased, use the --norebase option.

A change-branch that has been checked out (one ending in an ID) isn't rebased by default, because this would clutter the change review history in Gerrit. If you want it rebased nonetheless, use the --rebase option.

--draft

This option makes git-gerrit push the change-branch to refs/drafts/UPSTREAM instead of to refs/for/UPSTREAM, creating a draft change in Gerrit.

--topic TOPIC

This option specifies another name for the topic that will be associated with the change. By default, the topic name is the last component of the current change-branch name, as specified by the git gerrit new sub-command.

--reviewer USERS

This option let's you invite a list of users to review your change.

USERS is a colon-separated list of usernames. You may also pass this option more than once, to invite more than a set of users.

--cc USERS

This option let's you notify a list of users about your change.

USERS is a colon-separated list of usernames. You may also pass this option more than once, to invite more than a set of users.

git gerrit query [--limit LIMIT] [--verbose] [[NAME=]QUERY]*

The query sub-command let's you list Gerrit changes meeting specific criteria. The matching changes are shown in tabular format, one change per line, listing their legacy ID, status, Code-Review vote, time of last update, project name, branch name, owner name, and subject line.

You may pass a list of queries. Each QUERY's results is presented separated from the other by a empty line and a header containing the query's name and expression inside brackets. For example:

    $ git gerrit query 'Starred changes=is:starred' is:draft

    [Starred changes=is:starred]
    ID    STATUS CR UPDATED    PROJECT    BRANCH OWNER          SUBJECT
    1186  MERGED +2 2013-09-18 helloworld master Gustavo Chaves [SB-1] Test amend 3

    [QUERY=is:draft]
    ID    STATUS CR UPDATED    PROJECT    BRANCH OWNER          SUBJECT
    1187  NEW       2013-09-08 helloworld master Gustavo Chaves [SB-2] Make foo

Note that unnamed queries are prefixed by QUERY= instead of by their names.

Each QUERY can be specified by a Gerrit search expression.

--limit LIMIT

This option put a limit on the number of changes that are shown for each QUERY.

--verbose

This option makes the change topic be shown inside parenthesis to the right of the change branch name. This requires a separate REST call for each change, making the result appear more slowly.

git gerrit my [--limit LIMIT] [--verbose] [changes|drafts|watched|starred]

The my sub-command provides a set of pre-defined queries for the query sub-command. It's based on Gerrit's standard queries shown in its web interface under the My tab.

The changes argument is used by default if you don't specify any.

The options taken by the my sub-command are passed to the query sub-command.

git gerrit show [CHANGE]

The show sub-command describes a CHANGE in detail, showing much like what Gerrit shows in a change page of its web interface. For example:

    $ git gerrit show 1186
     Change-Num: 1186
      Change-Id: I0bb976fe1890657d7a1c3ba403e0b58ac2b63cd7
        Subject: [SB-1] Test amend 3
          Owner: Gustavo Chaves
        Project: helloworld
         Branch: master
        Created: 2013-09-18 16:22:21.000000000
        Updated: 2013-09-18 19:45:56.000000000
         Status: MERGED

If a CHANGE is not passed the branch associated with the current change-branch is described. If you're not in a change-branch, you'll get an error.

git gerrit checkout|co [CHANGE]

The checkout sub-command fetches a CHANGE from Gerrit, creates a change-branch pointing to it and checks it out, leaving your working area in the CHANGE state.

A Gerrit change may contain a series of patch-sets. The checkout fetches the current (latest) one. If there is already a change-branch for the change, it will be updated to the change's current patch-set.

If you omit the CHANGE argument and you are in a change-branch, it will be updated with its current patch-set.

The shorter name co can also be used instead of checkout.

git gerrit upstream|up [--keep] [--delete]

The upstream sub-command should be invoked when you're in a change-branch. It checks out the upstream branch and deletes the change-branch if it's associated with an already pushed change, i.e., if its name ends in a legacy numeric id, not in a topic name.

The shorter name up can also be used instead of upstream.

--keep

This option prevents the change-branch deletion after the upstream checkout.

--delete

This options forces the change-branch deletion when it's a new change. However, the <--keep> option has precedence, meaning that if both options are present the change-branch isn't deleted.

git gerrit cherry-pick [OPTIONS]* CHANGE

The cherry-pick sub-command fetches CHANGE from Gerrit and applies it to the current branch using the git cherry-pick command. The CHANGE id is required and every OPTION (but --debug) is passed as-is to the git cherry-pick command. You should read git-cherry-pick manpage to know what options are available. Some of the most usefull ones are these: -e, -x, and -n.

The shorter name cp can also be used instead of cherry-pick.

git gerrit reviewer [--add USERS] [--confirm] [--delete USERS] [CHANGE]

The reviewer sub-command allows you to manage the list of reviewers for a CHANGE. You can omit the CHANGE argument if you're in a change-branch. In this case, you'll be managing the associated change reviewers.

--add USERS

This option let's you invite new users to review the change. You can pass a comma-separated list of users and even use more than one --add option.

You can use Gerrit groupnames in addition to usernames, if you want to invite a group of users to review.

--confirm

Gerrit may reject the addition of groups with too many users because it recons you may be doing it by mistake. In this case, you'll receive an error message something like this:

    "The group My Group has 15 members. Do you want to add them all as reviewers?"

If you really want to invite them all, try again with using the --confirm option.

--delete USERS

This option let's you remove reviewers from the change. You can pass a comma-separated list of users and even use more than one --delete option.

You can use Gerrit groupnames in addition to usernames, if you want to remove a group of reviewers.

After adding and removing reviewers, git gerrit reviewers shows the remaining list of reviewers of the CHANGE.

git gerrit review [--message TEXT] [--keep] [[LABEL]=VOTE]* [CHANGE]

The review sub-command allows you to review (duh!) a CHANGE by casting votes and adding messages to it.

You can omit the CHANGE argument if you are in a change-branch, in which case you'll be reviewing the associated change. In this case, after a successful review, the change-branch will be deleted and its upstream checked out.

You can cast multiple votes using LABEL=VOTE arguments, where LABEL names a Gerrit label and VOTE is a negative, zero, or positive number. If you omit the LABEL name (but not the equal sign!) you'll be voting in the standard Code-Review label.

The Git editor (see the definition of GIT_EDITOR with the git help var command) is invoked for you to compose a message to be added to the review.

--message TEXT

This option adds a message to the review avoiding the Git editor invocation.

--keep

This option avoids the change-branch deletion after a successful review.

git gerrit submit [--no-wait-for-merge] [--keep] [CHANGE]

The submit sub-command submits an approved CHANGE, making Gerrit merge it into its remote upstream branch.

You can omit the CHANGE argument if you are in a change-branch, in which case you'll be submitting the associated change. In this case, after a successful submission, the change-branch will be deleted and its upstream checked out.

--no-wait-for-merge

By default git-gerrit will wait for the merge of the change into its branch to complete in Gerrit. This option tells it not to wait and finish as soon as it receives Gerrit's submit acknowledge.

--keep

This option avoids the change-branch deletion after a successful submission.

git gerrit abandon [--message TEXT] [--keep] [CHANGE]

The abandon sub-command abandons an unmerged CHANGE.

You can omit the CHANGE argument if you are in a change-branch, in which case you'll be abandoning the associated change. In this case, after a successful abandonment, the change-branch will be deleted and its upstream checked out.

The Git editor (see the definition of GIT_EDITOR with the git help var command) is invoked for you to compose a message to be added to the action.

--message TEXT

This option adds a message to the review avoiding the Git editor invocation.

--keep

This option avoids the change-branch deletion after a successful abandonment.

git gerrit restore [--message TEXT] [CHANGE]

The restore sub-command restores an abandoned CHANGE.

You can omit the CHANGE argument if you are in a change-branch, in which case you'll be restoring the associated change.

The Git editor (see the definition of GIT_EDITOR with the git help var command) is invoked for you to compose a message to be added to the action.

--message TEXT

This option adds a message to the review avoiding the Git editor invocation.

git gerrit revert [--message TEXT] [CHANGE]

The revert sub-command reverts an already merged CHANGE. Gerrit does so by creating, in the server, a new change with an inverted patch on top of the CHANGE remote upstream branch.

You can omit the CHANGE argument if you are in a change-branch, in which case you'll be reverting the associated change.

The Git editor (see the definition of GIT_EDITOR with the git help var command) is invoked for you to compose a message to be added to the action.

--message TEXT

This option adds a message to the review avoiding the Git editor invocation.

git gerrit config

The config sub-command lists Git's configuration variables in the git-gerrit section. It's just a shortcut to

    git config --get-regexp "^git-gerrit\."

git gerrit version

The version sub-command shows the versions of git-gerrit, Git, and Gerrit that you're using.

COMMIT-MSG HOOK

Gerrit provides a commit-msg hook for Git that should be installed in your repositories. Its purpose is to insert a Change-Id footer in the commit messages so that Gerrit can discern independent commits from merely amended ones.

Git-gerrit takes care of installing this hook for you. When you invoke its new or push sub-commands, it checks to see if your repository already has a commit-msg hook installed. If not, it automatically downloads Gerrit's standard hook and installs it for you.

GERRIT WORKFLOW

Here are the main use-cases of git-gerrit to manage your changes.

Creating a new change for review

Suppose you want to create a new change on master:

    git gerrit new topic master
    # edit
    git commit
    git gerrit push

First you create a new change-branch for your new change. If you're already in master you don't need to mention it on the first line. Then you make your change editing your working area and committing. When you're done, simply tell git-gerrit to push your change and get back to master.

In order to do the same thing using only standard Git commands you'd do something like this:

    git checkout master
    git pull --ff-only
    git checkout -b change/master/topic
    # edit
    git commit
    git push origin HEAD:refs/for/master
    git checkout master
    git branch -D change/master/topic

Reviewing a change

    git gerrit my changes
    git gerrit checkout 1234
    git show
    git gerrit review =-1

First, if you don't know the {change-id} of the change you want to review, you ask my changes to get a list of the changes still unreviewed. Then you checkout one change and study it. Finally, you record your review and gets back to the change's upstream branch.

Without git-gerrit you'd have to perform the review using Gerrit's web interface.

Amending a change

    git gerrit checkout 1234
    # edit
    git commit --amend
    git gerrit push

To amend a change you first check it out to a local change-branch. Then you can amend it and, finally, push it as another patch-set to Gerrit, checking out upstream again.

Without git-gerrit you would have to go first to Gerrit's web interface, find the change, and copy its fetch/checkout command line. Then you could paste it in your terminal and perform the amending like this:

    git fetch https://gustavo@gerrit.example.net/project refs/changes/90/1190/2 && git checkout FETCH_HEAD
    # edit
    git commit --amend
    git push origin HEAD:refs/for/master
    git checkout master

SEE ALSO

There are some alternatives to git-gerrit, other Git extensions to make it easier to interact with Gerrit. The three mentioned below are the most well known. All of them use Gerrit's mature and simple SSH API while git-gerrit's distinguishes from them in that it uses Gerrit's newer and more comprehensive REST API.

  • git-review

    Being the original inspiration for git-gerrit, git-review is a mature tool that's used by some very well known projects, such as OpenStack, MediaWiki, and LibreOffice.

  • git-change

    Simpler than git-review, git-change is better documented and has the best name of all. From it, git-gerrit took the change-branch concept.

  • querrit

    A very simple tool to query Gerrit and make it easier to push changes.

If you're interested in Gerrit automation per se, you can take a look at the Gerrit::REST Perl module, which is used by git-gerrit to interact with Gerrit via it's REST API.

AUTHOR

Gustavo L. de M. Chaves <gnustavo@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by CPqD <www.cpqd.com.br>.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.