func (a *application) runPrePush(repo scm.Repo) (err error) { previous := scm.Head // Will be "" if the current checkout was detached. previousRef := repo.Ref(scm.Head) curr := previous stashed := false defer func() { if curr != previous { p := previousRef if p == "" { p = string(previous) } if err2 := repo.Checkout(p); err == nil { err = err2 } } if stashed { if err2 := repo.Restore(); err == nil { err = err2 } } }() bio := bufio.NewReader(os.Stdin) line := "" triedToStash := false for { if line, err = bio.ReadString('\n'); err != nil { break } matches := rePrePush.FindStringSubmatch(line[:len(line)-1]) if len(matches) != 5 { return fmt.Errorf("unexpected stdin for pre-push: %q", line) } from := scm.Commit(matches[4]) to := scm.Commit(matches[2]) if to == gitNilCommit { // It's being deleted. continue } if to != curr { // Stash, checkout, run tests. if !triedToStash { // Only try to stash once. triedToStash = true if stashed, err = repo.Stash(); err != nil { return } } curr = to if err = repo.Checkout(string(to)); err != nil { return } } if from == gitNilCommit { from = scm.Initial } change, err := repo.Between(to, from, a.config.IgnorePatterns) if err != nil { return err } if err = a.runChecks(change, []checks.Mode{checks.PrePush}, &sync.WaitGroup{}); err != nil { return err } } if err == io.EOF { err = nil } return }