git-codereview: add rebase-work command

Shorthand for git rebase -i $(git codereview branchpoint).
Suggested alias: rw = codereview rebase-work.

Change-Id: I4c489064fc6fced8b18cf528b77ae36b9a1c7f06
Reviewed-on: https://go-review.googlesource.com/3622
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/git-codereview/branch.go b/git-codereview/branch.go
index 48ba8bb..38933b0 100644
--- a/git-codereview/branch.go
+++ b/git-codereview/branch.go
@@ -351,3 +351,15 @@
 	expectZeroArgs(args, "sync")
 	fmt.Fprintf(stdout(), "%s\n", CurrentBranch().Branchpoint())
 }
+
+func rebasework(args []string) {
+	expectZeroArgs(args, "rebase-work")
+	b := CurrentBranch()
+	if HasStagedChanges() || HasUnstagedChanges() {
+		dief("cannot rebase with uncommitted work")
+	}
+	if len(b.Pending()) == 0 {
+		dief("no pending work")
+	}
+	run("git", "rebase", "-i", b.Branchpoint())
+}
diff --git a/git-codereview/branch_test.go b/git-codereview/branch_test.go
index 9a3ab5c..c01680f 100644
--- a/git-codereview/branch_test.go
+++ b/git-codereview/branch_test.go
@@ -129,6 +129,32 @@
 	}
 }
 
+func TestRebaseWork(t *testing.T) {
+	gt := newGitTest(t)
+	defer gt.done()
+
+	// Get hash corresponding to checkout (known to server).
+	// Any work we do after this point should find hash as branchpoint.
+	hash := strings.TrimSpace(trun(t, gt.client, "git", "rev-parse", "HEAD"))
+
+	testMainDied(t, "rebase-work", "-n")
+	testPrintedStderr(t, "no pending work")
+
+	write(t, gt.client+"/file", "uncommitted")
+	testMainDied(t, "rebase-work", "-n")
+	testPrintedStderr(t, "cannot rebase with uncommitted work")
+
+	gt.work(t)
+
+	for i := 0; i < 4; i++ {
+		testMain(t, "rebase-work", "-n")
+		t.Logf("numCommits=%d", i)
+		testPrintedStderr(t, "git rebase -i "+hash)
+
+		gt.work(t)
+	}
+}
+
 func TestBranchpointMerge(t *testing.T) {
 	gt := newGitTest(t)
 	defer gt.done()
diff --git a/git-codereview/doc.go b/git-codereview/doc.go
index 03eae19..58553a9 100644
--- a/git-codereview/doc.go
+++ b/git-codereview/doc.go
@@ -32,6 +32,7 @@
 		gofmt = codereview gofmt
 		mail = codereview mail
 		pending = codereview pending
+		rebase-work = codereview rebase-work
 		submit = codereview submit
 		sync = codereview sync
 
@@ -50,7 +51,8 @@
 The branchpoint command prints the commit hash of the most recent change
 on the current branch that is shared with the Gerrit server. This is the point
 where local work branched from the published tree. The command is intended
-mainly for use in scripts. For example, "git rebase -i $(git codereview branchpoint)".
+mainly for use in scripts. For example, "git diff $(git codereview branchpoint)"
+or "git log $(git codereview branchpoint)..HEAD".
 
 Change
 
@@ -156,6 +158,14 @@
 By default, it fetches recent commits and code review information from the
 Gerrit server.
 
+Rebase-work
+
+The rebase-work command runs git rebase in interactive mode over pending changes.
+It is shorthand for "git rebase -i $(git codereview branchpoint)".
+It differs from plain "git rebase -i" in that the latter will try to incorporate
+new commits from the origin branch during the rebase, and git rebase-work
+does not.
+
 Submit
 
 The submit command pushes the pending change to the Gerrit server and tells
diff --git a/git-codereview/review.go b/git-codereview/review.go
index 964ba1e..144f911 100644
--- a/git-codereview/review.go
+++ b/git-codereview/review.go
@@ -140,6 +140,8 @@
 		mail(args)
 	case "pending":
 		pending(args)
+	case "rebase-work":
+		rebasework(args)
 	case "submit":
 		submit(args)
 	case "sync":