| package git |
| |
| import ( |
| "fmt" |
| "io" |
| "os/exec" |
| "strings" |
| ) |
| |
| // IsClean checks if the repo in the current directory is clean. |
| // |
| // Untracked files are okay, but modified, added, or deleted files are not. |
| func IsClean() (bool, error) { |
| cmd := exec.Command("git", "status", "--porcelain") |
| out, err := cmd.Output() |
| if err != nil { |
| return false, fmt.Errorf("git status failed: %v", err) |
| } |
| |
| lines := strings.Split(string(out), "\n") |
| for _, line := range lines { |
| if line == "" { |
| continue |
| } |
| |
| // Ignore untracked files. |
| if !strings.HasPrefix(line, "??") { |
| return false, nil |
| } |
| } |
| |
| return true, nil |
| } |
| |
| // ApplyPatches applies a list of patches to the current repo with `git am <paths>`. |
| // |
| // The combined output of the command is written to the given writer. |
| func ApplyPatches(paths []string, writer io.Writer) error { |
| cmd := exec.Command("git", append([]string{"am"}, paths...)...) |
| cmd.Stdout = writer |
| cmd.Stderr = writer |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("`git am` command failed: %v", err) |
| } |
| return nil |
| } |
| |
| // Add adds a list of files to the current repo with `git add <files>`. |
| // |
| // The combined output of the command is written to the given writer. |
| func Add(files []string, writer io.Writer) error { |
| cmd := exec.Command("git", append([]string{"add"}, files...)...) |
| cmd.Stdout = writer |
| cmd.Stderr = writer |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("`git add` command failed: %v", err) |
| } |
| return nil |
| } |
| |
| // Commit commits changes to the current repo with `git commit <message>`. |
| // |
| // The combined output of the command is written to the given writer. |
| func Commit(message string, writer io.Writer) error { |
| cmd := exec.Command("git", "commit", "-m", message) |
| cmd.Stdout = writer |
| cmd.Stderr = writer |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("`git commit` command failed: %v", err) |
| } |
| return nil |
| } |
| |
| // SwitchToNewBranch creates a branch in the current repo and switches to |
| // it using `git switch -c <branch>`. |
| // |
| // The combined output of the command is written to the given writer. |
| func SwitchToNewBranch(branch string, writer io.Writer) error { |
| cmd := exec.Command("git", "switch", "-c", branch) |
| cmd.Stdout = writer |
| cmd.Stderr = writer |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("command %s failed: %v", cmd, err) |
| } |
| return nil |
| } |
| |
| // FindCommitByPattern searches the git log for the provided pattern and |
| // returns the first commit hash it finds. |
| func FindCommitByPattern(pattern string) (string, error) { |
| cmd := exec.Command("git", "log", "-n1", "--format=%H", "--grep", pattern) |
| out, err := cmd.CombinedOutput() |
| if err != nil { |
| return "", fmt.Errorf("command %s failed: %v", cmd, err) |
| } |
| |
| return strings.TrimSpace(string(out)), nil |
| } |
| |
| // FormatPatch formats a revision range as patches and writes them to the |
| // provided output directory. |
| // |
| // The combined output of the command is written to the given writer. |
| func FormatPatch(revisionRange, outDir string, writer io.Writer) error { |
| cmd := exec.Command("git", "format-patch", revisionRange, "-o", outDir) |
| cmd.Stdout = writer |
| cmd.Stderr = writer |
| if err := cmd.Run(); err != nil { |
| return fmt.Errorf("command %s failed: %v", cmd, err) |
| } |
| return nil |
| } |