in internal/git/localrepo/commit.go [123:240]
func (repo *Repo) WriteCommit(ctx context.Context, cfg WriteCommitConfig) (git.ObjectID, error) {
if err := validateWriteCommitConfig(cfg); err != nil {
return "", err
}
if cfg.AuthorDate.IsZero() {
cfg.AuthorDate = time.Now()
}
if cfg.CommitterDate.IsZero() {
cfg.CommitterDate = time.Now()
}
// Use 'commit-tree' instead of 'commit' because we are in a bare
// repository. What we do here is the same as "commit -m message
// --allow-empty".
commitArgs := []string{string(cfg.TreeID)}
repoPath, err := repo.Path(ctx)
if err != nil {
return "", fmt.Errorf("getting repo path: %w", err)
}
var env []string
if cfg.AlternateObjectDir != "" {
if !filepath.IsAbs(cfg.AlternateObjectDir) {
return "", errors.New("alternate object directory must be an absolute path")
}
if err := os.MkdirAll(cfg.AlternateObjectDir, mode.Directory); err != nil {
return "", err
}
env = append(env,
fmt.Sprintf("GIT_OBJECT_DIRECTORY=%s", cfg.AlternateObjectDir),
fmt.Sprintf("GIT_ALTERNATE_OBJECT_DIRECTORIES=%s", filepath.Join(repoPath, "objects")),
)
}
env = append(env,
fmt.Sprintf("GIT_AUTHOR_DATE=%s", git.FormatTime(cfg.AuthorDate)),
fmt.Sprintf("GIT_AUTHOR_NAME=%s", cfg.AuthorName),
fmt.Sprintf("GIT_AUTHOR_EMAIL=%s", cfg.AuthorEmail),
fmt.Sprintf("GIT_COMMITTER_DATE=%s", git.FormatTime(cfg.CommitterDate)),
)
if featureflag.GPGSigning.IsEnabled(ctx) && cfg.Sign && cfg.GitConfig.CommitterName != "" && cfg.GitConfig.CommitterEmail != "" {
env = append(env,
fmt.Sprintf("GIT_COMMITTER_NAME=%s", cfg.GitConfig.CommitterName),
fmt.Sprintf("GIT_COMMITTER_EMAIL=%s", cfg.GitConfig.CommitterEmail),
)
} else {
env = append(env,
fmt.Sprintf("GIT_COMMITTER_NAME=%s", cfg.CommitterName),
fmt.Sprintf("GIT_COMMITTER_EMAIL=%s", cfg.CommitterEmail),
)
}
var flags []gitcmd.Option
for _, parent := range cfg.Parents {
flags = append(flags, gitcmd.ValueFlag{Name: "-p", Value: parent.String()})
}
flags = append(flags, gitcmd.ValueFlag{Name: "-F", Value: "-"})
var stdout, stderr bytes.Buffer
opts := []gitcmd.CmdOpt{
gitcmd.WithStdout(&stdout),
gitcmd.WithStderr(&stderr),
gitcmd.WithStdin(strings.NewReader(cfg.Message)),
gitcmd.WithEnv(env...),
}
if featureflag.GPGSigning.IsEnabled(ctx) && cfg.Sign && cfg.GitConfig.SigningKey != "" {
flags = append(flags, gitcmd.Flag{Name: "--gpg-sign=" + cfg.GitConfig.SigningKey})
opts = append(opts, gitcmd.WithGitalyGPG())
}
if err := repo.ExecAndWait(ctx,
gitcmd.Command{
Name: "commit-tree",
Flags: flags,
Args: commitArgs,
},
opts...,
); err != nil {
if strings.Contains(stderr.String(), "name consists only of disallowed characters") {
return "", ErrDisallowedCharacters
}
return "", fmt.Errorf("commit-tree: %w: %s %s", err, stderr.String(), stdout.String())
}
objectHash, err := repo.ObjectHash(ctx)
if err != nil {
return "", fmt.Errorf("detecting object hash: %w", err)
}
oid, err := objectHash.FromHex(text.ChompBytes(stdout.Bytes()))
if err != nil {
return "", fmt.Errorf("hex to object hash: %w", err)
}
if cfg.Reference != "" {
if err := repo.UpdateRef(
ctx,
git.ReferenceName(cfg.Reference),
oid,
"",
); err != nil {
return "", fmt.Errorf("updating ref: %w", err)
}
}
return oid, nil
}