Git use-cases

Outline

  1. General Tips
  2. Pushing a draft
  3. Pushing a certain version
  4. When Gerrit tells me that a change needs to be rebased locally
  5. Re-ordering commits
  6. Restoring lost commits
  7. Pushing multiple changes to gerrit

General Tips

It is useful to have one graphical tool for git so that you can quickly see in the log whether the order of your commits is correct. It also helps not lose track. The integrated git support in IntelliJ IDEA or Eclipse is just fine for that (Smartgit is an alternative which is very nice for interactive add for example). Often it is easiest just to type in one concise command in a shell (but this may be a matter of personal preferences). On GNU/Linux the regular bash is sufficient, on Windows I would recommend using the Git shell. It is bundled with Github Windows, which is the easiest way to get it without manual steps. (see this article for more information).

Pushing a draft

Instead of refs/for/master use refs/drafts/master when uploading your changeset, e.g.

git push origin HEAD:refs/drafts/master

Pushing a certain version

You can specify the commit you want to push in

git push origin <identify-your-commit>:refs/for/master

Typical identifiers are the SHA-1 of the commit (not the Change-ID), HEAD (currently checked out revision) or the name of a branch like master. It is helpful to look at the graphical git log to see what HEAD is pointing to. Note that you will also push all you new commits *upto* this referenced commit.

When Gerrit tells me that a change needs to be rebased locally

If your are developing on the master branch locally, you just have to update your local state and push the change again.

git pull --rebase

which is short-hand for git fetch followed by git rebase. Note that this rebases all local commits on the current branch.

If you want to confirm that the rebase has been successful, you can view the git log and check that the commit to be rebased comes after the latest master commit. After that you can just push the commit.

git push origin <commit-id>:refs/for/master

(or use your favorite git tool). Note that this pushes all local commits up to this one.

Advanced way

If you have a more complicated local branch structure or do not wish to merge the changes from the master into the local development branch yet, then the following steps provide a general guideline to rebase a patchset.

  1. Fetch the current master revision. This updates the local reference to origin/master
    git fetch
  2. Fetch the latest patchset from gerrit and
    git fetch <gerrit-url>

    (can be obtained on the website of the commit in gerrit)

  3. Apply it on top of the updated master version. This will require merging (otherwise gerrit would have done the rebase itself). Please see the section about merging.
    git checkout -b new_branch fetch_head

    and

    git rebase origin/master new_branch

    . Do not forget to call git rebase --continue to complete the merging.

  4. Upload the rebased patchset. Again you might want to look at the git graph to confirm that HEAD is pointing at the rebased commit and that this commit comes after origin/master.
    git push origin HEAD:refs/for/master

Re-ordering commits

git rebase -i If the current branch is no tracking branch it demands a branch identifier, e.g. git rebase -i origin/master The list of commits to be rebased can now be edited. If you remove a commit here it gets lost, so read the instructions in the text file carefully. You can also simply add a commit by inserting p <commit-id> in a new line in the desired position. You can change the order of commits by simply reordering the lines in the file. Please keep in mind that a re-ordering of commits might require cumbersome manual merging. Therefore, you should only make about 1 or 2 changes at once to avoid confusion. It is probably easiest to execute the rebasing multiple times. git branch --set-upstream-to=origin/master browser_page_rewrite

Restoring lost commits

Take a look at the git reflog.

Pushing multiple changes to gerrit

Try to structure commits independent if possible. For example there is no reason for an unrelated fix in a different area of the code to depend on your current development. In this case, create a separate branch at origin/master for the unrelated commit. However, when developing in the same location or on related elements, in most cases the only practical solution is to have a chain of commits. Then there are two approaches to submit updated patchsets to those chain of commits.

  1. Directly rebase depending commits. This can easily be done by using git rebase -i and writing edit before the commit to be changed.
  2. Create a branch for each commit you want to change and use git commit --amend in this branch. Subsequent commits stay unchanged.

The big disadvantage of the first variant is that new patchsets might be created for commits that have not actually changed, just been rebased. Existing +1s in gerrit disappear for those commits. Furthermore, it is difficult to track the changes between individual changeset as the rebase might introduce a lot of noise. The advantage of this method is that after the review, patches can be submitted directly to the master (in most cases) and do not require a rebase. The second variant makes it easy to follow individual patchsets, but may require rebase after the commits have been approved by +2. This rebase, at least in theory, has to be reviewed again. Generally, I would recommend to manage update to a commit in a separate local branch. However, when an update to a patchset contains fundamental changes it makes sense to rebase all dependent commits directly because non-trivial merging operations (as a result of the rebase) should be reviewed as well. This way the depending changes do not have to reviewed again when the rebase has been done. Furthermore, I would recommend to make only small changes in later patchsets and use separate commits for all other stuff. This makes reviewing easier and reduces merge conflicts while rebasing to a minimum.