Outline
- General Tips
- Pushing a draft
- Pushing a certain version
- When Gerrit tells me that a change needs to be rebased locally
- Re-ordering commits
- Restoring lost commits
- 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.
- Fetch the current master revision. This updates the local reference to
origin/master
git fetch
- Fetch the latest patchset from gerrit and
git fetch <gerrit-url>
(can be obtained on the website of the commit in gerrit)
- 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.
- 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.
- Directly rebase depending commits. This can easily be done by using
git rebase -i
and writing edit
before the commit to be changed.
- 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 +1
s 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.