countAheadBehind returns the number of non-merge commits on `local` not in `remote` (ahead) and on `remote` not in `local` (behind), in a single git invocation.
(path, subpath, local, remote string)
| 230 | // countAheadBehind returns the number of non-merge commits on `local` not in `remote` (ahead) |
| 231 | // and on `remote` not in `local` (behind), in a single git invocation. |
| 232 | func countAheadBehind(path, subpath, local, remote string) (int32, int32, error) { |
| 233 | args := []string{"-C", path, "rev-list", "--left-right", "--count", "--no-merges", fmt.Sprintf("%s...%s", local, remote)} |
| 234 | if subpath != "" { |
| 235 | args = append(args, "--", subpath) |
| 236 | } |
| 237 | cmd := exec.Command("git", args...) |
| 238 | data, err := cmd.CombinedOutput() |
| 239 | if err != nil { |
| 240 | return 0, 0, fmt.Errorf("failed to count commits: %s(%w)", data, err) |
| 241 | } |
| 242 | parts := strings.Fields(strings.TrimSpace(string(data))) |
| 243 | if len(parts) != 2 { |
| 244 | return 0, 0, fmt.Errorf("unexpected rev-list output: %q", string(data)) |
| 245 | } |
| 246 | ahead, err := strconv.ParseInt(parts[0], 10, 32) |
| 247 | if err != nil { |
| 248 | return 0, 0, fmt.Errorf("failed to parse ahead count: %w", err) |
| 249 | } |
| 250 | behind, err := strconv.ParseInt(parts[1], 10, 32) |
| 251 | if err != nil { |
| 252 | return 0, 0, fmt.Errorf("failed to parse behind count: %w", err) |
| 253 | } |
| 254 | return int32(ahead), int32(behind), nil |
| 255 | } |