git

package
v1.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2024 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package git contains an implementation of git functionality.

The implementation consists of the Git interface and the Plumbing interface.

The Git interface (and it's default instance Default) provide a usable interface to Git Functionality. The Git interface will automatically choose between using a os.Exec() call to a native "git" wrapper, or using a pure golang git implementation. This should be used directly by callers.

The Plumbing interface provides more direct control over which interface is used to interact with repositories. Calls to a Plumbing typically place assumptions on the caller and require some setup. For this reason, implementation of the Plumbing interface are not exported.

Index

Constants

This section is empty.

Variables

View Source
var ErrArgumentsUnsupported = errors.New("Plumbing does not support extra clone arguments")

ErrArgumentsUnsupported is an error that is returned when arguments are not supported by a Plumbing.

View Source
var ErrCloneAlreadyExists = errors.New("repository already exists")

ErrCloneAlreadyExists is an error that is returned when an operation can not be completed because a clone at the provided path already exists.

View Source
var ErrNoUpstream = errors.New("no corresponding upstream to track")
View Source
var ErrNotARepository = errors.New("not a repository")

ErrNotARepository is an error that is returned when the clonePath parameter is not a repository

Functions

This section is empty.

Types

type ExitError

type ExitError struct {

	// Code that the git process exited with
	Code int
	// contains filtered or unexported fields
}

ExitError is an error that indicates the 'git' process exited abnormally This type is compatible with https://golang.org/pkg/errors/

func (ExitError) Cause

func (err ExitError) Cause() error

Cause returns the cause of this error

type Git

type Git interface {
	// Plumbing returns the plumbing used by this git.
	Plumbing() Plumbing

	// IsRepository checks if the directory at localPath is the root of a git repository.
	IsRepository(localPath string) bool

	// IsRepositoryQuick efficiently checks if the directly at localPath contains a repository.
	// It is like IsRepository, except that it returns false more quickly than IsRepository.
	IsRepositoryQuick(localPath string) bool

	// Clone clones a remote repository from remoteURI to clonePath.
	// May attempt to read credentials from stream.Stdin.
	// Writes to stream.Stdout and stream.Stderr.
	//
	// remoteURI is the remote git uri to clone the repository from.
	// clonePath is the local path to clone the repository to.
	// extraArgs are arguments as would be passed to a 'git clone' command.
	//
	// If there is already a repository at clonePath returns ErrCloneAlreadyExists.
	// If the underlying 'git' process exits abnormally, returns.
	// If extraArgs is non-empty and extra arguments are not supported by this Wrapper, returns ErrArgumentsUnsupported.
	// May return other error types for other errors.
	Clone(stream stream.IOStream, remoteURI, clonePath string, extraArgs ...string) error

	// GetHeadRef gets a resolved reference to head at the repository at clonePath.
	//
	// When getting the reference succeeded, returns err = nil.
	// If there is no repository at clonePath returns err = ErrNotARepository.
	// May return other error types for other errors.
	GetHeadRef(clonePath string) (ref string, err error)

	// Fetch fetches all remotes of the repository at clonePath.
	// May attempt to read credentials from stream.Stdin.
	// Writes to stream.Stdout and stream.Stderr.
	//
	// When fetching succeeded, returns nil.
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	Fetch(stream stream.IOStream, clonePath string) error

	// Pull fetches the repository at clonePath and merges in changes where appropriate.
	// May attempt to read credentials from stream.Stdin.
	// Writes to stream.Stdout and stream.Stderr.
	//
	// When pulling succeeded, returns nil.
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	Pull(stream stream.IOStream, clonePath string) error

	// GetRemote gets the url of the canonical remote at clonePath.
	// The semantics of 'canonical' are determined by the underlying git implementation.
	// Typically this function returns the url of the tracked remote of the currently checked out branch or the 'origin' remote.
	// If no remote exists, an empty url is returned.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	GetRemote(clonePath string) (url string, err error)

	// UpdateRemotes updates the urls of all remotes of the repository at clonePath.
	// updateFunc is a function that is called for each remote url to be updated.
	// It should return the new url corresponding to each old url.
	// If it returns a non-nil error, updating the current remote of the repository is instead aborted and error is returned.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	UpdateRemotes(clonePath string, updateFunc func(url, name string) (newURL string, err error)) error

	// GetBranches gets the names of all branches contained in the repository at clonePath.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	GetBranches(clonePath string) (branches []string, err error)

	// ContainsBranch checks if the repository at clonePath contains a branch with the provided name.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	ContainsBranch(clonePath, branch string) (exists bool, err error)

	// IsDirty checks if the repository at clonePath contains uncommitted changes.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	IsDirty(clonePath string) (dirty bool, err error)

	// IsSync checks if the repository at clonePath contains branches that are not yet synced with their upstream.
	//
	// If there is no repository at clonePath returns ErrNotARepository.
	// May return other error types for other errors.
	IsSync(clonePath string) (synced bool, err error)

	// GitPath returns the path to the git executable being used, if any.
	GitPath() string
}

Git represents a wrapper around a Plumbing instance. It is goroutine-safe and initialization free.

As opposed to Plumbing, which poses certain requirements and assumptions on the caller, a Git does not. Using a Git can be as simple as:

err := git.Pull(stream.NewEnvIOStream(), "/home/user/Projects/github.com/hello/world")

func NewGitFromPlumbing

func NewGitFromPlumbing(plumbing Plumbing, path string) Git

NewGitFromPlumbing creates a new Git wrapping a specific Plumbing.

When git is nil, attempts to automatically select a Plumbing automatically. The second parameter is only used when plumbing is nil; it should contain the value of 'PATH' environment variable.

The implementation of this function relies on the underlying Plumbing (be it a default one or a caller provided one) to conform according to the specification. In particular, this function does not checks on the error values returned and passes them directly from the implementation to the caller

type Plumbing

type Plumbing interface {

	// Init is used to initialize this Plumbing.
	// Init should only be called once per Plumbing instance.
	// When initialization fails, for example due to missing dependencies, returns a non-nil error,
	Init() error

	// IsRepository checks if the directory at localPath is the root of a git repository.
	// May assume that localPath exists and is a repository.
	//
	// This function returns a pair, a boolean isRepo that indicates if this object is a repository
	// and an optional repoObject value.
	// The repoObject value will only be taken into account when isRepo is true, and passed to other functions in this git implementation.
	// The semantics of the repoObject are determined by this Plumbing and should not be used outside of it.
	// Note that the repoObject may be used for more than one subsequent call.
	//
	// This function suppresses all errors, and if something goes wrong assumed that isRepo is false.
	IsRepository(localPath string) (repoObject any, isRepo bool)

	// IsRepositoryUnsafe efficiently checks if the directly at localPath contains a repository.
	// It is like IsRepository, except that it may return false positives, but no false negatives.
	// This function is optimized to be called a lot of times.
	IsRepositoryUnsafe(localPath string) bool

	// GetHeadRef returns a reference to the current head of the repository cloned at clonePath.
	// The string ref should contain a git REFLIKE, that is a branch, a tag or a commit id.
	//
	// This function should only be called if IsRepository(clonePath) returns true.
	// The second parameter must be the returned value from IsRepository().
	GetHeadRef(clonePath string, repoObject any) (ref string, err error)

	// GetRemotes returns the names and urls of the remotes of the repository cloned at clonePath.
	// If determining the remotes is not possible, and error is returned instead.
	//
	// This function should only be called if IsRepository(clonePath) returns true.
	// The second parameter must be the returned value from IsRepository().
	GetRemotes(clonePath string, repoObject any) (remotes map[string][]string, err error)

	// GetCanonicalRemote gets the name of the canonical remote of the repository cloned at clonePath.
	// The Plumbing is free to decided what the canonical remote is, but it is typically the remote of the currently checked out branch or the 'origin' remote.
	// If no remote exists, an empty name is returned.
	//
	// This function should only be called if IsRepository(clonePath) returns true.
	// The second parameter must be the returned value from IsRepository().
	GetCanonicalRemote(clonePath string, repoObject any) (name string, urls []string, err error)

	// SetRemoteURLs set the remote 'remote' of the repository at clonePath to urls.
	// The remote 'name' must exist.
	// Furthermore newURLs must be of the same length as the old URLs.
	//
	// This function should only be called if IsRepository(clonePath) returns true.
	// The second parameter must be the returned value from IsRepository().
	SetRemoteURLs(clonePath string, repoObject any, name string, urls []string) (err error)

	// Clone tries to clone the repository at 'from' to the folder 'to'.
	// May attempt to read credentials from stream.Stdin.
	// Output is directed to stream.Stdout and stream.Stderr.
	//
	// remoteURI will be the uri of the remote repository.
	// clonePath will be the path to a local folder where the repository should be cloned to.
	// It's parent is guaranteed to exist.
	//
	// extraArgs will be additional arguments, in the form of arguments of a 'git clone' command.
	// When this implementation does not support arguments, it returns ErrArgumentsUnsupported whenever arguments is a list of length > 0.
	//
	// If the clone succeeds returns, err = nil.
	// If the underlying clone command returns a non-zero code, returns an error of type ExitError.
	// If something else goes wrong, may return any other error type.
	Clone(stream stream.IOStream, remoteURI, clonePath string, extraArgs ...string) error

	// Fetch should fetch new objects and refs from all remotes of the repository cloned at clonePath.
	// May attempt to read credentials from stream.Stdin.
	// Output is directed to stream.Stdout and stream.Stderr.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	Fetch(stream stream.IOStream, clonePath string, cache any) (err error)

	// Pull should fetch new objects and refs from all remotes of the repository cloned at clonePath.
	// It then merges them into the local branch wherever an upstream is set.
	// May attempt to read credentials from stream.Stdin.
	// Output is directed to stream.Stdout and stream.Stderr.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	Pull(stream stream.IOStream, clonePath string, cache any) (err error)

	// GetBranches gets the names of all branches contained in the repository at clonePath.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	GetBranches(clonePath string, cache any) (branches []string, err error)

	// ContainsBranch checks if the repository at clonePath contains a branch with the provided branch.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	ContainsBranch(clonePath string, cache any, branch string) (contains bool, err error)

	// IsDirty checks if the repository at clonePath contains uncommitted changes.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	IsDirty(clonePath string, cache any) (dirty bool, err error)

	// IsSync checks if the repository at clonePath does not have branches synced with their upstream.
	//
	// This function will only be called if IsRepository(clonePath) returns true.
	// The second parameter passed will be the returned value from IsRepository().
	IsSync(clonePath string, cache any) (dirty bool, err error)
}

Plumbing is an interface that represents a working internal implementation of git. Plumbing is intended to be goroutine-safe, i.e. everything except the Init() method can be called from multiple goroutines at once.

It is not intended to be called directly by an external caller, instead it is intended to be called by the Git interface only. The reason for this is that it requires initialization and places certain assumptions on the caller.

For instance, to pull a repository, the following code is required:

plumbing.Init() // called exactly once
cache, isRepo := plumbing.IsRepository("/home/user/Projects/github.com/hello/world")
if !isRepo {
  // error, not a repository
}
err = plumbing.Pull(stream.NewEnvIOStream(), "/home/user/Projects/github.com/hello/world", cache)

Such code is typically handled by a Git instance that wraps a Plumbing.

func NewPlumbing added in v1.6.0

func NewPlumbing() Plumbing

NewPlumbing returns an implementation of a plumbing that has no external dependencies. The plumbing is guaranteed to have been initialized.

There is no guarantee as to what plumbing is returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL