Clone and commit¶
The core round trip: acquire a repository, change files, record the change, publish it.
Throughout, ctx is a context.Context you supply. Every network-touching
call takes one so a hung remote can be cancelled. See
context and cancellation.
Clone into a directory¶
r, err := repo.NewRepo(repo.Settings{
Forge: repo.ForgeGitLab,
Token: repo.StaticToken(os.Getenv("GITLAB_TOKEN")),
FS: afero.NewOsFs(),
})
if err != nil {
return err
}
gitRepo, worktree, err := r.Clone(ctx, url, "/tmp/work", repo.WithShallowClone(1))
Clone targets an explicit path. OpenLocal opens a path that may or may not already be
a repository, and OpenInMemory clones into RAM. See work in memory.
All three bind the repository and worktree to r, so later calls need no handle.
They also return the raw *git.Repository and *git.Worktree for setup-time
convenience. Use them during setup only; do not hand them to other goroutines
(why).
Start a fresh repository¶
OpenLocal init-if-absent, which means it cannot tell "opened an existing repository"
from "initialised a new one". When that distinction matters (scaffolding that must never
git init inside someone's existing checkout) use the init-only pair:
found, err := repo.DiscoverRepository(target) // read-only upward probe
if err != nil {
return err
}
if !found {
_, _, err = r.InitLocal(target, "main") // ErrAlreadyRepository if it is one
}
DiscoverRepository walks upward using git's own discovery semantics, so a
subdirectory of a repository reports true. InitLocal defaults to branch main when
you pass "".
Change files¶
Write through the worktree filesystem. Files written there are the worktree, with no sync step:
fs, err := r.WorkFS()
if err != nil {
return err
}
if err := afero.WriteFile(fs, "README.md", body, 0o644); err != nil {
return err
}
See read and write the worktree for the live-view-versus-copy distinction.
Stage and commit¶
AddAll honours .gitignore; Add(\".\") does not
AddAll wraps go-git's AddWithOptions{All: true}, which applies the repository's
ignore patterns, so build artefacts stay out of the commit. A plain Add(".") would
stage them. The .gitignore file itself is staged.
Commit accepts nil options; pass *git.CommitOptions to set the author, amend, or
sign. It returns the commit hash.
nil options need a git identity in the environment
With nil, go-git fills the author from git configuration: user.name and
user.email across the system, global and repository scopes. Where none is set, as
in most containers and CI runners, the commit fails with author field is required.
This module supplies no identity of its own. Set one explicitly rather than relying
on ambient configuration:
Branch and push¶
if err := r.CreateBranch(ctx, "feature/x"); err != nil {
return err
}
if err := r.Push(ctx, nil); err != nil {
return err
}
CreateBranch creates the branch and checks it out. For a branch that already exists
it instead checks it out and then pulls, so on a repository with no remote the second
call with the same name fails with remote not found where the first succeeded. The pull
is skipped for in-memory repositories. To move to an existing branch without any of that,
use Checkout.
Push(nil) uses the credentials resolved at construction. Pass *git.PushOptions to
override; when opts.Auth or opts.Progress is nil the configured value is filled in for
you, so you can set other fields without re-supplying credentials or losing the server's
output.
Set Settings.Progress before you push
Push is where the server talks back. Pre-receive hook rejection reasons and the
"To create a merge request, visit …" URL arrive on that sideband channel and
nowhere else. With Progress nil, a hook-rejected push gives you an error with the
explanation stripped out. See
diagnostics.
To move between existing refs, use Checkout(plumbing.NewBranchReferenceName("main")) or
CheckoutCommit(hash).
Order matters, and mis-ordering is an error not a panic¶
Every method has a defined unopened state. Call one before Clone/Open*/InitLocal
and you get a sentinel back:
Worktree operations return ErrNoWorktree; repository operations return
ErrNoRepository. InitLocal on an existing repository returns ErrAlreadyRepository.
The full method-by-method table is in the
errors reference.
Related¶
- Authenticate to a forge
- Read and write the worktree
- Work in memory
- Errors reference: what each failure message means
- What this module does not do: merge, log, tags, status and the rest, and how to reach them