git-codereview: add branchpoint command, for scripts

The most important use of this is

	git rebase -i $(git codereview branchpoint)

in multichange clients.

Change-Id: I6bdbc02db2e2823e837159efec20ad5c9046bcd5
Reviewed-on: https://go-review.googlesource.com/2783
Reviewed-by: Andrew Gerrand <adg@golang.org>
diff --git a/git-codereview/branch.go b/git-codereview/branch.go
index 1aa5427..cdec9c3 100644
--- a/git-codereview/branch.go
+++ b/git-codereview/branch.go
@@ -316,3 +316,8 @@
 	}
 	return work[0]
 }
+
+func branchpoint(args []string) {
+	expectZeroArgs(args, "sync")
+	fmt.Fprintf(stdout(), "%s\n", CurrentBranch().Branchpoint())
+}
diff --git a/git-codereview/branch_test.go b/git-codereview/branch_test.go
index f206d9e..fdfb044 100644
--- a/git-codereview/branch_test.go
+++ b/git-codereview/branch_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"reflect"
+	"strings"
 	"testing"
 )
 
@@ -109,3 +110,21 @@
 	b := CurrentBranch()
 	b.Submitted("I123456789")
 }
+
+func TestBranchpoint(t *testing.T) {
+	gt := newGitTest(t)
+	defer gt.done()
+
+	// Get hash corresponding to checkout (known to server).
+	hash := strings.TrimSpace(trun(t, gt.client, "git", "rev-parse", "HEAD"))
+
+	// Any work we do after this point should find hash as branchpoint.
+	for i := 0; i < 4; i++ {
+		testMain(t, "branchpoint")
+		t.Logf("numCommits=%d", i)
+		testPrintedStdout(t, hash)
+		testNoStderr(t)
+
+		gt.work(t)
+	}
+}
diff --git a/git-codereview/doc.go b/git-codereview/doc.go
index 566b82a..03eae19 100644
--- a/git-codereview/doc.go
+++ b/git-codereview/doc.go
@@ -43,6 +43,15 @@
 
 Descriptions of each command follow.
 
+Branchpoint
+
+	git codereview branchpoint
+
+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)".
+
 Change
 
 The change command creates and moves between Git branches and maintains the
diff --git a/git-codereview/review.go b/git-codereview/review.go
index 98fa241..5f4b890 100644
--- a/git-codereview/review.go
+++ b/git-codereview/review.go
@@ -124,6 +124,8 @@
 	installHook()
 
 	switch command {
+	case "branchpoint":
+		branchpoint(args)
 	case "change":
 		change(args)
 	case "gofmt":
diff --git a/git-codereview/util_test.go b/git-codereview/util_test.go
index e38c364..a5f1418 100644
--- a/git-codereview/util_test.go
+++ b/git-codereview/util_test.go
@@ -24,6 +24,7 @@
 	tmpdir string // temporary directory holding repos
 	server string // server repo root
 	client string // client repo root
+	nwork  int    // number of calls to work method
 }
 
 // resetReadOnlyFlagAll resets windows read-only flag
@@ -60,13 +61,16 @@
 }
 
 func (gt *gitTest) work(t *testing.T) {
-	trun(t, gt.client, "git", "checkout", "-b", "work")
-	trun(t, gt.client, "git", "branch", "--set-upstream-to", "origin/master")
+	if gt.nwork == 0 {
+		trun(t, gt.client, "git", "checkout", "-b", "work")
+		trun(t, gt.client, "git", "branch", "--set-upstream-to", "origin/master")
+	}
 
 	// make local change on client
-	write(t, gt.client+"/file", "new content")
+	gt.nwork++
+	write(t, gt.client+"/file", fmt.Sprintf("new content %d", gt.nwork))
 	trun(t, gt.client, "git", "add", "file")
-	trun(t, gt.client, "git", "commit", "-m", "msg\n\nChange-Id: I123456789\n")
+	trun(t, gt.client, "git", "commit", "-m", fmt.Sprintf("msg\n\nChange-Id: I%d23456789\n", gt.nwork))
 }
 
 func newGitTest(t *testing.T) *gitTest {