git

package module
v2.2.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Feb 16, 2016 License: MIT Imports: 18 Imported by: 0

README

go-git GoDoc Build Status codecov.io codebeat badge

A low level and highly extensible git client library for reading repositories from git servers. It is written in Go from scratch, without any C dependencies.

We have been following the open/close principle in its design to facilitate extensions.

go-git does not claim to be a replacement of git2go as its approach and functionality is quite different.

ok, but why? ...

At source{d} we analyze almost all the public open source contributions made to git repositories in the world.

We want to extract detailed information from each GitHub repository, which requires downloading repository packfiles and analyzing them: extracting their code, authors, dates and the languages and ecosystems they use. We are also interested in knowing who contributes to what, so we can tell top contributors from the more casual ones.

You can obtain all this information using the standard git command running over a local clone of a repository, but this simple solution does not scale well over millions of repositories: we want to avoid having local copies of the unpacked repositories in a regular file system; go-git allows us to work with an in-memory representation of repositories instead.

I see... but this is production ready?

Yes!!!, we have been using go-git at source{d} since August 2015 to analyze all GitHub public repositories (i.e. 16M of repositories).

Coming Soon

Blame support: right now we are using a forward version of a line-tracking algorithm and we are having some problems handling merges. The plan is to get merges right and change to a backward line-tracking algorithm soon.

Installation

The recommended way to install go-git is:

go get -u gopkg.in/src-d/go-git.v2/...

Examples

Basic example: retrieving the commits for a given repository:

r, err := git.NewRepository("https://github.com/src-d/go-git", nil)
if err != nil {
	panic(err)
}

if err := r.Pull("origin", "refs/heads/master"); err != nil {
	panic(err)
}

iter := r.Commits()
defer iter.Close()

for {
	commit, err := iter.Next()
	if err != nil {
		if err == io.EOF {
			break
		}

		panic(err)
	}

	fmt.Println(commit)
}

Outputs:

commit 2275fa7d0c75d20103f90b0e1616937d5a9fc5e6
Author: Máximo Cuadros <mcuadros@gmail.com>
Date:   2015-10-23 00:44:33 +0200 +0200

commit 35b585759cbf29f8ec428ef89da20705d59f99ec
Author: Carlos Cobo <toqueteos@gmail.com>
Date:   2015-05-20 15:21:37 +0200 +0200

commit 7e3259c191a9de23d88b6077dcb1cd427e925432
Author: Alberto Cortés <alberto@sourced.tech>
Date:   2016-01-21 03:29:57 +0100 +0100

commit 24b8ae50db91f3909b11304014564bffc6fdee79
Author: Alberto Cortés <alberto@sourced.tech>
Date:   2015-12-11 17:57:10 +0100 +0100
...

Acknowledgements

The earlier versions of the packfile reader are based on git-chain, project done by @yrashk

License

MIT, see LICENSE

Documentation

Overview

Package git is a low level and highly extensible git client library for reading repositories from git servers. It is written in Go from scratch, without any C dependencies.

We have been following the open/close principle in its design to facilitate extensions.

Small example extracting the commits from a repository:

func ExampleBasic_printCommits() {
  r, err := git.NewRepository("https://github.com/src-d/go-git", nil)
  if err != nil {
  	panic(err)
  }

  if err := r.Pull("origin", "refs/heads/master"); err != nil {
  	panic(err)
  }

  iter := r.Commits()
  defer iter.Close()

  for {
  	commit, err := iter.Next()
  	if err != nil {
  		if err == io.EOF {
  			break
  		}

  		panic(err)
  	}

  	fmt.Println(commit)
  }
}

Index

Constants

View Source
const (
	DefaultRemoteName = "origin"
)

Variables

View Source
var ErrFileNotFound = errors.New("file not found")

New errors defined by this package.

View Source
var (
	ObjectNotFoundErr = errors.New("object not found")
)

Functions

func SortCommits

func SortCommits(l []*Commit)

SortCommits sort a commit list by commit date, from older to newer.

Types

type Blame

type Blame struct {
	Path  string
	Rev   core.Hash
	Lines []*line
}

type Blob

type Blob struct {
	Hash core.Hash
	Size int64
	// contains filtered or unexported fields
}

Blob is used to store file data - it is generally a file.

func (*Blob) Decode

func (b *Blob) Decode(o core.Object) error

Decode transform an core.Object into a Blob struct

func (*Blob) Reader

func (b *Blob) Reader() io.Reader

Reader returns a reader allow the access to the content of the blob

type Commit

type Commit struct {
	Hash      core.Hash
	Author    Signature
	Committer Signature
	Message   string
	// contains filtered or unexported fields
}

Commit points to a single tree, marking it as what the project looked like at a certain point in time. It contains meta-information about that point in time, such as a timestamp, the author of the changes since the last commit, a pointer to the previous commit(s), etc. http://schacon.github.io/gitbook/1_the_git_object_model.html

func (*Commit) Blame

func (c *Commit) Blame(path string) (*Blame, error)

Blame returns the last commit that modified each line of a file in a repository.

The file to blame is identified by the input arguments: repo, commit and path. The output is a slice of commits, one for each line in the file.

Blaming a file is a two step process:

1. Create a linear history of the commits affecting a file. We use revlist.New for that.

2. Then build a graph with a node for every line in every file in the history of the file.

Each node (line) holds the commit where it was introduced or last modified. To achieve that we use the FORWARD algorithm described in Zimmermann, et al. "Mining Version Archives for Co-changed Lines", in proceedings of the Mining Software Repositories workshop, Shanghai, May 22-23, 2006.

Each node is asigned a commit: Start by the nodes in the first commit. Assign that commit as the creator of all its lines.

Then jump to the nodes in the next commit, and calculate the diff between the two files. Newly created lines get assigned the new commit as its origin. Modified lines also get this new commit. Untouched lines retain the old commit.

All this work is done in the assignOrigin function which holds all the internal relevant data in a "blame" struct, that is not exported.

TODO: ways to improve the efficiency of this function:

1. Improve revlist

2. Improve how to traverse the history (example a backward traversal will be much more efficient)

TODO: ways to improve the function in general:

1. Add memoization between revlist and assign.

2. It is using much more memory than needed, see the TODOs below.

func (*Commit) Decode

func (c *Commit) Decode(o core.Object) error

Decode transform an core.Object into a Blob struct

func (*Commit) File

func (c *Commit) File(path string) (file *File, err error)

File returns the file with the specified "path" in the commit and a nil error if the file exists. If the file does not exists, it returns a nil file and the ErrFileNotFound error.

func (*Commit) NumParents

func (c *Commit) NumParents() int

NumParents returns the number of parents in a commit.

func (*Commit) Parents

func (c *Commit) Parents() *CommitIter

func (*Commit) References

func (c *Commit) References(path string) ([]*Commit, error)

References returns a References for the file at "path", the commits are sorted in commit order. It stops searching a branch for a file upon reaching the commit were the file was created.

Caveats:

  • Moves and copies are not currently supported.
  • Cherry-picks are not detected unless there are no commits between them and therefore can appear repeated in the list. (see git path-id for hints on how to fix this).

func (*Commit) String

func (c *Commit) String() string

func (*Commit) Tree

func (c *Commit) Tree() *Tree

type CommitIter

type CommitIter struct {
	// contains filtered or unexported fields
}

func NewCommitIter

func NewCommitIter(r *Repository) *CommitIter

func (*CommitIter) Add

func (i *CommitIter) Add(o core.Object)

func (*CommitIter) Close

func (i *CommitIter) Close()

func (*CommitIter) Next

func (i *CommitIter) Next() (*Commit, error)

type File

type File struct {
	Name string
	io.Reader
	Hash core.Hash
}

File represents git file objects.

func (*File) Contents

func (f *File) Contents() string

Contents returns the contents of a file as a string.

func (*File) Lines

func (f *File) Lines() []string

Lines returns a slice of lines from the contents of a file, stripping all end of line characters. If the last line is empty (does not end in an end of line), it is also stripped.

type Hash

type Hash core.Hash

type Remote

type Remote struct {
	Endpoint common.Endpoint
	Auth     common.AuthMethod
	// contains filtered or unexported fields
}

func NewAuthenticatedRemote

func NewAuthenticatedRemote(url string, auth common.AuthMethod) (*Remote, error)

NewAuthenticatedRemote returns a new Remote using the given AuthMethod, using as client http.DefaultClient

func NewRemote

func NewRemote(url string) (*Remote, error)

NewRemote returns a new Remote, using as client http.DefaultClient

func (*Remote) Capabilities

func (r *Remote) Capabilities() *common.Capabilities

Capabilities returns the remote capabilities

func (*Remote) Connect

func (r *Remote) Connect() error

Connect with the endpoint

func (*Remote) DefaultBranch

func (r *Remote) DefaultBranch() string

DefaultBranch returns the name of the remote's default branch

func (*Remote) Fetch

Fetch returns a reader using the request

func (*Remote) FetchDefaultBranch

func (r *Remote) FetchDefaultBranch() (io.ReadCloser, error)

FetchDefaultBranch returns a reader for the default branch

func (*Remote) Info

func (r *Remote) Info() *common.GitUploadPackInfo

Info returns the git-upload-pack info

func (*Remote) Ref

func (r *Remote) Ref(refName string) (core.Hash, error)

Ref returns the Hash pointing the given refName

func (*Remote) Refs

func (r *Remote) Refs() map[string]core.Hash

Refs returns the Hash pointing the given refName

type Repository

type Repository struct {
	Remotes map[string]*Remote
	Storage *core.RAWObjectStorage
	URL     string
}

func NewPlainRepository

func NewPlainRepository() *Repository

NewPlainRepository creates a new repository without remotes

func NewRepository

func NewRepository(url string, auth common.AuthMethod) (*Repository, error)

NewRepository creates a new repository setting remote as default remote

func (*Repository) Commit

func (r *Repository) Commit(h core.Hash) (*Commit, error)

Commit return the commit with the given hash

func (*Repository) Commits

func (r *Repository) Commits() *CommitIter

Commits decode the objects into commits

func (*Repository) Pull

func (r *Repository) Pull(remoteName, branch string) (err error)

Pull connect and fetch the given branch from the given remote, the branch should be provided with the full path not only the abbreviation, eg.: "refs/heads/master"

func (*Repository) Tree

func (r *Repository) Tree(h core.Hash) (*Tree, error)

Tree return the tree with the given hash

type Signature

type Signature struct {
	Name  string
	Email string
	When  time.Time
}

Signature represents an action signed by a person

func (*Signature) Decode

func (s *Signature) Decode(b []byte)

Decode decodes a byte slice into a signature

func (*Signature) String

func (s *Signature) String() string

type Tree

type Tree struct {
	Entries map[string]TreeEntry
	Hash    core.Hash
	// contains filtered or unexported fields
}

Tree is basically like a directory - it references a bunch of other trees and/or blobs (i.e. files and sub-directories)

func (*Tree) Decode

func (t *Tree) Decode(o core.Object) error

Decode transform an core.Object into a Tree struct

func (*Tree) File

func (t *Tree) File(path string) (*File, error)

File returns the hash of the file identified by the `path` argument. The path is interpreted as relative to the tree receiver.

func (*Tree) Files

func (t *Tree) Files() chan *File

type TreeEntry

type TreeEntry struct {
	Name string
	Mode os.FileMode
	Hash core.Hash
}

TreeEntry represents a file

type TreeIter

type TreeIter struct {
	// contains filtered or unexported fields
}

func NewTreeIter

func NewTreeIter(r *Repository) *TreeIter

func (*TreeIter) Add

func (i *TreeIter) Add(o core.Object)

func (*TreeIter) Close

func (i *TreeIter) Close()

func (*TreeIter) Next

func (i *TreeIter) Next() (*Tree, error)

Directories

Path Synopsis
Go-git needs the packfile and the refs of the repo.
Go-git needs the packfile and the refs of the repo.
common
Package common contains utils used by the clients
Package common contains utils used by the clients
http
Package http implements a HTTP client for go-git.
Package http implements a HTTP client for go-git.
ssh
Package ssh implements a ssh client for go-git.
Package ssh implements a ssh client for go-git.
Package core implement the core interfaces and structs used by go-git
Package core implement the core interfaces and structs used by go-git
Package diff implements line oriented diffs, similar to the ancient Unix diff command.
Package diff implements line oriented diffs, similar to the ancient Unix diff command.
examples
formats

Jump to

Keyboard shortcuts

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