Git and code review
I recently discovered git, a version control system. After learning and trying it out for a few weeks, I am impressed by its efficiency, flexibility, and capability.
For a project I am working on at VMware, it uses subversion as a centralized code repository for multiple developers. Git has good support of subversion through the git-svn command. However, git does not have a built-in support for doing side-by-side code reviews. This document describes my code development process with git and my attempt to customize git to support side-by-side code reviews.
Prepare the repository
First, I use git-svn to clone a copy of the source code from the subversion server.
git svn clone svn+ssh://server.name/svn/valgrind-vassert
Once this is done, a local git repository of the valgrind-vassert project is cloned from the subversion server. This is also my working directory for modifying and testing the code. If I need more than one working directories, I can just make more local clones using git (not git svn).
git clone valgrind-vassert work_dir_2
Note that only the first local directory (cloned by git svn) can talk to the remote subversion server. This is what I want. If I have multiple changes I am working on, I can easily "git push" my changes from the local clones to the svn clone and then commit it to the subversion server. I may have to use branches. But it is very easy to use branches with git. (Check out this book! [pdf])
View the commit history
The local repository has full history of the project. I can get the commit history from either git log or git svn log command, even when I am offline.
$ git log -1 commit 5c9382278d8517a158d0507ede9c7b5d23cb10ac Author: mqiuDate: Tue Aug 19 12:56:06 2008 +0000 ... git-svn-id: svn+ssh://localhost/svn/valgrind-vassert@22 aec7b058-a04d-4682-b3b4-202a7a29d950 $ git svn log -1 ------------------------------------------------------------------------ r22 | mqiu | 2008-08-19 05:56:06 -0700 (Tue, 19 Aug 2008) | 3 lines ... ------------------------------------------------------------------------
To get a condensed view of the history, I put the following alias in my .bashrc file.
alias gl="git log --pretty=oneline"
Make code changes and commit locally
Now, I can edit the source code and start testing. After a while, I may have forgotten what file I have changed. I ask git with git diff command. git diff shows detailed changes by default. I put the following alias in my .gitconfig and .bashrc to change the output to show a list of files that I have modified. (I also specified my name and email in .gitconfig.)
# in .gitconfig
[alias]
changes=diff --name-status -r
[user]
name = Your Name
email = email@address
# in .bashrc
function gd {
# describe a change
if [ -z "$1" ]; then
git changes
elif [ "$1" = "--cached" ]; then
git changes --cached
else
git changes "$1^" "$1"
fi
}
Now, I simply type gd and it shows a list of files I have changed.
$ gd M bashrc M vimrc
Git allows me to put some changes in a staging area, called the index. By using "git add .", it puts all changes to the staging area from my modified copy. If I want to select only part of the changes (includes partial changes from a single file!), I can use git add -i command to invoke the interactive mode.
Once I am happy with the code changes I have in the staging area, I can commit the change locally into git using git commit. Don't worry, this does not publish the change to the subversion yet. This local commit allows me to write a decent commit message to describe what my change is about in detail. I use a commit message template file, which reminds to put title, details, testing and reviewer information. This commit message can be changed later, after my change is reviewed by other developers.
# in .gitconfig
[commit]
template = /path/to/.git.commit.template
# in .git.commit.template
put your commit message title
put your commit message details
testing done:
reviewers:
Send out a code review
To support side by side code review, I wrote a couple of scripts for generating and viewing side by side diff files using vimdiff. The first script is git_diff_to_review.py. This script generates a directory in /tmp from the information obtained from "git diff". To use it, put this "make review" function (gr) in my .bashrc file. Then, invoke gr with the commit ID to make a review tarball.
# in .bashrc
function gr {
if [ -z "$1" ]; then
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff`
elif [ "$1" = "--cached" ]; then
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff --cached`
else
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff "$1^" "$1"`
fi
if [ -d "$reviewDir" ]; then
theDir=`dirname $reviewDir`
theBase=`basename $reviewDir`
pushd "$theDir" >/dev/null
tar zcf "$theBase.tgz" "$theBase"
popd >/dev/null
echo "$reviewDir.tgz"
rm -rf $reviewDir
else
echo "something wrong with $reviewDir"
fi
}
$ gr 92a72512369ec7398af0e9437172ec31a9562879
/tmp/20080820_08339.tgz
The second script is diff_view.py, which is then used to view the generated review tarball using vimdiff. One can use the number in [] to view specific file in the changeset.
$ diff_view.py /tmp/20080820_08339.tgz bashrc [0] vimrc [1] Next/Previous/exit(N/p/x/)?
As a shorthand, I use the following bash function to view both committed and uncommitted changes in development. This enables me to quickly review my own changes within vimdiff. If I pass an extra "-l" option to diff_view.py it will find the local copy of the modified file and enable me to change the local copy in vimdiff as-I-go.
function gdd {
if [ -z "$1" ]; then
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff`
elif [ "$1" = "--cached" ]; then
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff --cached`
else
reviewDir=`GIT_EXTERNAL_DIFF=git_diff_to_review.py git diff "$1^" "$1"`
fi
diff_view.py $reviewDir
rm -rf $reviewDir
}
With this two scripts, I can generate a code review directory and make a tarball and send it, along with my local commit message, to the other developers working on the same project. Usually, if my peer developers have shared file space with me, I can just send them the path to the review tarball.
After the code is reviewed
After the I get my feedback on the code review. I can change the code to address the concerns and suggestions made by other developers. But wait, didn't I already commit my old change locally? No problem! Git allow me to change my last commit since I have not published the commit to the subversion server yet. The secret command is "git commit --amend". I can use the opportunity to update my commit message too.
Commit to and update from SVN
Once my code is reviewed, I can "push" the local commit to the subversion server by using git svn dcommit. To get updates from the subversion server, I use git svn rebase.
alias p5s="git svn dcommit" alias psr="git svn rebase"
Comments:
On Wed, Jun 17, 2009 at 6:58 PM Pablo From Argentina wrote:
thought about the possibility of using git patches sent by mail to be analyzed by reviewing the code? did you know some open software tool for code reviewing ? Thanks
On Wed, Jun 17, 2009 at 7:10 PM Min wrote:
What I do is to send the resulting *.tgz file generated from "gr" to friends for reviewing. It is not like "git am" command, which works on mailboxes directly, I think.