Context and cancellation¶
Every network-touching operation takes a context.Context as its first
argument. Clone, in-memory clone, push, fetch, pull, and the pull that
CreateBranch performs all run against a remote, and a remote can hang. Without a context
there is no way to bound how long a clone against an unresponsive server blocks.
On a ThreadSafeRepo that is worse than a stall,
because the mutex is held for the operation's full duration, so one hung clone
wedges every other method behind it. The context is the cancellation handle that
fixes both.
go-git's own types, and go-git's own cancellation¶
The role interfaces traffic in go-git's own concrete types: *git.Repository,
*git.Worktree, *object.File, plumbing.ReferenceName, *git.PushOptions,
and so on. That is deliberate: this package adds binding, role decomposition,
forge-aware auth, and concurrency safety, but it does not hide go-git behind an
abstraction of its own. Threading a context through the network methods follows
from that. It wires each call to the …Context form go-git already provides
(CloneContext, PlainCloneContext, PushContext, FetchContext,
PullContext) rather than inventing a cancellation mechanism.
Pull checks the context once more after its fetch, immediately before it moves
the branch, so a cancellation that arrives during the fetch stops it with nothing
moved but the remote-tracking ref. The reset after that check is local and is not
interrupted.
Which methods take a context¶
The network-touching methods of the Opener, Committer, Brancher, Fetcher
and Puller roles:
Open(ctx, repoType, location, branch, opts...)
OpenLocal(ctx, location) // branch parameter removed, see below
OpenInMemory(ctx, location, branch, opts...)
Clone(ctx, uri, targetPath, opts...)
Commit(ctx, message, opts)
Push(ctx, opts)
CreateBranch(ctx, branchName)
Fetch(ctx, opts)
Pull(ctx, opts)
Commit and OpenLocal do no network I/O, but they belong to roles whose other
methods do, so they take the context too for a uniform role surface; they ignore
it.
Migration (pre-1.0 breaking change)¶
This is an API-breaking signature change. The module is pre-1.0, so it ships as a minor bump. To migrate:
- Add a context as the first argument to
Open,OpenLocal,OpenInMemory,Clone,Commit,Push, andCreateBranch. Pass the request/operation context you already have, orcontext.Background()at a top-level entry point. - Drop the
branchargument fromOpenLocal. It was silently unused on the open path.OpenLocal(ctx, location)opens an existing repository, and only when the path is genuinely not a repository (git.ErrRepositoryNotExists) does it initialise a fresh one onmain. To initialise on a specific branch, useInitLocal(location, branch), which is the purpose-built init entry point.
OpenLocal no longer clobbers on a non-fatal open error¶
Previously OpenLocal fell into initialise-a-new-repository on any
git.PlainOpen failure: a corrupt repository, a permission error, anything. So a
transient fault on a real project directory got an empty repository initialised
over it, destroying the evidence of the original problem. It now initialises
only for git.ErrRepositoryNotExists and returns every other open error
verbatim (wrapped as failed to open git repository at <path>). If you relied on
the old init-on-any-error behaviour, call InitLocal explicitly.
Since v0.3.0 one case inside git.ErrRepositoryNotExists is carved back out. A
.git file naming a git directory that has gone (a pruned linked worktree, a
moved --separate-git-dir checkout, a submodule whose superproject was
re-cloned) returns
ErrMissingGitDir
and writes nothing, because that directory holds real work rather than being
empty.