| @@ -189,7 +189,13 @@ func CommitFileChange(dir, branch, path string, content []byte, name, email, mes |
| 189 | 189 | branchRef := "refs/heads/" + branch |
| 190 | 190 | parent, err := ResolveRef(dir, branchRef) |
| 191 | 191 | if err != nil { |
| 192 | | return "", fmt.Errorf("branch %s: %w", branch, err) |
| 192 | // An unborn branch is a root commit only in a repository with no |
| 193 | // refs at all. Anywhere else an unresolvable branch is a typo, and |
| 194 | // starting an orphan branch for it would be worse than refusing. |
| 195 | if !isEmptyRepo(dir) { |
| 196 | return "", fmt.Errorf("branch %s: %w", branch, err) |
| 197 | } |
| 198 | parent = "" |
| 193 | 199 | } |
| 194 | 200 | |
| 195 | 201 | // Hash the new blob. |
| @@ -211,7 +217,11 @@ func CommitFileChange(dir, branch, path string, content []byte, name, email, mes |
| 211 | 217 | defer os.Remove(idx.Name()) |
| 212 | 218 | env := append(os.Environ(), "GIT_INDEX_FILE="+idx.Name()) |
| 213 | 219 | |
| 214 | | rt := exec.Command(toolpath.Look("git"), "-C", dir, "read-tree", parent+"^{tree}") |
| 220 | tree0 := parent + "^{tree}" |
| 221 | if parent == "" { |
| 222 | tree0 = "--empty" |
| 223 | } |
| 224 | rt := exec.Command(toolpath.Look("git"), "-C", dir, "read-tree", tree0) |
| 215 | 225 | rt.Env = env |
| 216 | 226 | if out, err := rt.CombinedOutput(); err != nil { |
| 217 | 227 | return "", fmt.Errorf("read-tree: %v\n%s", err, out) |
| @@ -229,7 +239,11 @@ func CommitFileChange(dir, branch, path string, content []byte, name, email, mes |
| 229 | 239 | } |
| 230 | 240 | tree := strings.TrimSpace(string(out)) |
| 231 | 241 | |
| 232 | | sha, err := CommitTree(dir, tree, []string{parent}, name, email, message) |
| 242 | var parents []string |
| 243 | if parent != "" { |
| 244 | parents = []string{parent} |
| 245 | } |
| 246 | sha, err := CommitTree(dir, tree, parents, name, email, message) |
| 233 | 247 | if err != nil { |
| 234 | 248 | return "", err |
| 235 | 249 | } |
| @@ -239,6 +253,13 @@ func CommitFileChange(dir, branch, path string, content []byte, name, email, mes |
| 239 | 253 | return sha, nil |
| 240 | 254 | } |
| 241 | 255 | |
| 256 | // isEmptyRepo reports whether dir has no refs at all — a repository |
| 257 | // created but never pushed to. |
| 258 | func isEmptyRepo(dir string) bool { |
| 259 | out, err := exec.Command(toolpath.Look("git"), "-C", dir, "rev-list", "-n1", "--all").Output() |
| 260 | return err == nil && strings.TrimSpace(string(out)) == "" |
| 261 | } |
| 262 | |
| 242 | 263 | // CommitParents returns the parent SHAs of a commit. |
| 243 | 264 | func CommitParents(dir, sha string) ([]string, error) { |
| 244 | 265 | out, err := exec.Command(toolpath.Look("git"), "-C", dir, "rev-list", "--parents", "-n1", "--end-of-options", sha).Output() |