A highly extensible Git implementation in pure Go.

go-git logo GoDoc Build Status Go Report Card

go-git is a highly extensible git implementation library written in pure Go.

It can be used to manipulate git repositories at low level (plumbing) or high level (porcelain), through an idiomatic Go API. It also supports several types of storage, such as in-memory filesystems, or custom implementations, thanks to the Storer interface.

It's being actively developed since 2015 and is being used extensively by Keybase, Gitea or Pulumi, and by many other libraries and tools.

Project Status

After the legal issues with the src-d organization, the lack of update for four months and the requirement to make a hard fork, the project is now back to normality.

The project is currently actively maintained by individual contributors, including several of the original authors, but also backed by a new company, gitsight, where go-git is a critical component used at scale.

Comparison with git

go-git aims to be fully compatible with git, all the porcelain operations are implemented to work exactly as git does.

git is a humongous project with years of development by thousands of contributors, making it challenging for go-git to implement all the features. You can find a comparison of go-git vs git in the compatibility documentation.

Installation

The recommended way to install go-git is:

import "github.com/go-git/go-git/v5" // with go modules enabled (GO111MODULE=on or outside GOPATH)
import "github.com/go-git/go-git" // with go modules disabled

Examples

Please note that the CheckIfError and Info functions used in the examples are from the examples package just to be used in the examples.

Basic example

A basic example that mimics the standard git clone command

// Clone the given repository to the given directory
Info("git clone https://github.com/go-git/go-git")

_, err := git.PlainClone("/tmp/foo", false, &git.CloneOptions{
    URL:      "https://github.com/go-git/go-git",
    Progress: os.Stdout,
})

CheckIfError(err)

Outputs:

Counting objects: 4924, done.
Compressing objects: 100% (1333/1333), done.
Total 4924 (delta 530), reused 6 (delta 6), pack-reused 3533

In-memory example

Cloning a repository into memory and printing the history of HEAD, just like git log does

// Clones the given repository in memory, creating the remote, the local
// branches and fetching the objects, exactly as:
Info("git clone https://github.com/go-git/go-billy")

r, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
    URL: "https://github.com/go-git/go-billy",
})

CheckIfError(err)

// Gets the HEAD history from HEAD, just like this command:
Info("git log")

// ... retrieves the branch pointed by HEAD
ref, err := r.Head()
CheckIfError(err)


// ... retrieves the commit history
cIter, err := r.Log(&git.LogOptions{From: ref.Hash()})
CheckIfError(err)

// ... just iterates over the commits, printing it
err = cIter.ForEach(func(c *object.Commit) error {
	fmt.Println(c)
	return nil
})
CheckIfError(err)

Outputs:

commit ded8054fd0c3994453e9c8aacaf48d118d42991e
Author: Santiago M. Mola <[email protected]>
Date:   Sat Nov 12 21:18:41 2016 +0100

    index: ReadFrom/WriteTo returns IndexReadError/IndexWriteError. (#9)

commit df707095626f384ce2dc1a83b30f9a21d69b9dfc
Author: Santiago M. Mola <[email protected]>
Date:   Fri Nov 11 13:23:22 2016 +0100

    readwriter: fix bug when writing index. (#10)

    When using ReadWriter on an existing siva file, absolute offset for
    index entries was not being calculated correctly.
...

You can find this example and many others in the examples folder.

Contribute

Contributions are more than welcome, if you are interested please take a look to our Contributing Guidelines.

License

Apache License Version 2.0, see LICENSE

Owner
go-git
A highly extensible Git implementation in pure Go.
go-git
Comments
  • plumbing: format/packfile, prevent large objects from being read into memory completely

    plumbing: format/packfile, prevent large objects from being read into memory completely

    This PR adds code to prevent large objects from being read into memory from packfiles or the filesystem through the use of a new Option, the LargeObjectThreshold.

    Objects greater than the provided (optional) LargeObjectThreshold are now no longer directly stored in the cache or read completely into memory.

    This PR differs and improves the previous broken #303 by fixing several bugs in the reader and transparently wrapping ReaderAt as a Reader.

    Signed-off-by: Andrew Thornton [email protected]


    (UPDATED: Make LOT an Option on the ObjectStorage - defaulted to off.)

  • pumbling: packfile, resolve external reference delta

    pumbling: packfile, resolve external reference delta

    I don't really want to take any credit for this work. This solution is a carbon copy of what was proposed in https://github.com/go-git/go-git/pull/111

    Would really appreciate some feedback

  • Support build under wasm and/or js

    Support build under wasm and/or js

    Fixes the following build error under GOOS=js GOARCH=wasm go build -v:

    package github.com/go-git/go-git/v5        
            imports github.com/go-git/go-billy/v5/osfs
            imports golang.org/x/sys/unix: build constraints exclude all Go files in /home/paralin/go/pkg/mod/golang.org/x/[email protected]/unix
    
  • Error building without CGO

    Error building without CGO

    Trying to built a program using go-git v5.5.0 with CGO_ENABLED set to 0 results in an error:

     	imports github.com/go-git/go-git/v5
     	imports github.com/go-git/go-git/v5/config
     	imports github.com/go-git/go-git/v5/plumbing
     	imports github.com/go-git/go-git/v5/plumbing/hash
     	imports github.com/pjbgf/sha1cd/cgo: build constraints exclude all Go files in /home/jenkins/go/pkg/mod/github.com/pjbgf/[email protected]/cgo
    

    This seems to have been added/changed in #618.

    Using

    hash.RegisterHash(crypto.SHA1, sha1.New)
    

    as suggested in the PR, does not fix the problem.

  • config: support insteadOf for remotes' URLs

    config: support insteadOf for remotes' URLs

    Added support for insteadOf configuration for remote's urls. Can also be applied to submodules, but I didn't implement that.

    This fixes: https://github.com/go-git/go-git/issues/76

  • git-ssh: try multiple algorithms for known_hosts

    git-ssh: try multiple algorithms for known_hosts

    Hi,

    When using git over ssh, it seems that if a host (eg: GitHub.com) has multiple keys (eg: an rsa and an ed25519 ones), but only one of those keys is listed in the $HOME/.ssh/known_hosts, and the one that's not listed has a higher preference (e.g. ed25519 over rsa), then the git clone operation will fail.

    I feel it should try to be more intelligent and try to use the rsa one.

  • Fix object not found error in OFS deltas

    Fix object not found error in OFS deltas

    Unfortunately the code in #303 was incorrect for large objects in OFS deltas.

    The underlying fault is that the seeker in the packfile was seeking away whilst the delta was being read.

    This PR simply reads the delta into a buffer.

    Fix #323

    Signed-off-by: Andrew Thornton [email protected]

  • plumbing: wire up contexts for Transport.AdvertisedReferences

    plumbing: wire up contexts for Transport.AdvertisedReferences

    This is primarily for the sake of the http transport, which otherwise makes its first call without a context, causing context timeouts to not work if the remote is unresponsive.

    Fixed up several tests which were getting this wrong. I am particularly fond of the ones which canceled the context and then proceeded to test that the function worked after being canceled.

    The AdvertisedReferences function can be removed after this change, but this is technically breaking the API, since library users could call it, so it should really be deferred to v6.

  •  authentication required

    authentication required

    I am cloning a private library

    And comes with a username and password

    But this doesn't seem to work and got authentication required error

    	options := git.CloneOptions{
    		URL:               getGitURL(r.repo, username, password), // https://username:[email protected]/owner/repo.git
    		Progress:          os.Stdout,
    		SingleBranch:      true,
    		Depth:             1,
    		RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
    	}
    
    	_, err := git.CloneContext(ctx, memory.NewStorage(), fs, &options)
    
  • config: add missing functions for completeness

    config: add missing functions for completeness

    This PR complete the Config functions.

    Add Options.Has to check if an Option exist.

    Wherever a collection of Option exist, make sure that the following functions exists as well:

    • Option
    • OptionAll (new, return all values)
    • HasOption (new)
    • AddOption
    • SetOption
    • RemoveOption

    For Config and Section, make sure that the following exist to access the sublevel:

    • X
    • HasX (HasSection was missing)
    • RemoveX (RemoveSubsection was missing)

    This PR also does some shuffling to have a consistent ordering of functions.

  • plumbing: diff, add colored output support

    plumbing: diff, add colored output support

    Fixes #33.

    This is a draft PR. Please tell me if it more-or-less follows the project's coding style and what changes are likely to be needed to make it more acceptable.

    At the moment, it only supports the default git diff colors as defined by git 2.26.2. It should be extensible to reading custom colors from a git config file, if needed.

    Before merging, this needs a few tweaks to ensure the output matches git's as far as reasonably possible.

  • fatal: protocol error: bad line length character: PACK

    fatal: protocol error: bad line length character: PACK

    I'm getting a weird bug that I think is a bug in go-git.

    On the client-side I'm seeing the following:

    $ git pull -vvv --rebase
    Server version is go-git/5.x
    Server supports ofs-delta
    want 526e79c8c4037c2fcbee50acc2d9be1992b60893 (refs/heads/main)
    have 51ea2dea8b05b8e631928a990f16fe7566e3c96f
    have 6901305097043b4a25e2e20bafab359e635fc476
    have 5b5fab934eef3b3957fe5d712672487e9234d0ce
    have 2f572924460cb3bcc140cb1b30fab1619bad9b5a
    have b701bbb46c14441442376191fcd9476a0ede3120
    have 070676a07101c3ddf22bc3169980e0c5068295c0
    have f1b049c1238065e2b4908d8526a595dcc5e0a811
    have 26fbee7ff623814fb37568c72c89ee515bfb7d8e
    have 44101b43124b4eba0308dbeef85bd77b48230d93
    have dae95318ea4236d3d157999b7ca2654edb06af36
    have 6a7fff648f7922355a6fb965bf9b7c17d939d5e3
    have c5bbbf3b1813827981a1746ad450afb10910c203
    have f8d8ff5de51ba02b28a52b55ca0523b231ff8acd
    have 6f8b2b27f5c3d35dfb41a5a38a3795d8c4962692
    have 65d71b41dd0a5f531e9ca577ab11af88762a4e78
    have 7d7bf6318f7470b17204767364ff22ff7ad2620d
    POST git-upload-pack (903 bytes)
    have 5fc5fd9ba13b98582cb2b7ae2b39f28ed7f127a0
    have e99894102fc0c98583e35b42ffc2d578dc9a1c1c
    have a0f95b37c000e3bda2af160f9ae24cbcc4def343
    have 30b8f348eaf906caf0c32bba15b6b8868245d91f
    have 5d4b79d0a19658b41ddbe2454f8699d841beb52f
    have 99a6559b96f6fe976a5d5cd7b2f396d29492c8b9
    have 74fcb64cc38fd5cc4d33c419e29c460f5be6f615
    have 983dabb33c2dddcdba65b8ab9d0922bd338628aa
    have 30559cd9c23ca4e803364ba1848442d217560143
    have f661e6e4ce1177352b5bc40238351920cc25a69b
    have 2b57b6e0b1b936f45aa4ed8fd0ed2f57b7d370f3
    have 2fe14eca63e9d3e907c7b725407c146a82cc129f
    have d58151dbb07a5d5dd7eaf6fc9f12566898823a46
    have a64f9d8f14762e341a851d0e211814958e044a64
    have d6b8143f569c95bda9a1e5a494affed26b058ce6
    have 6e6648e344c889767240a33f42febf9498250131
    fatal: protocol error: bad line length character: PACK
    

    On the server-side the request/context is cancelled (probably becuase the client bailed above):

    time="2022-12-29T14:59:47Z" level=error msg="error encoding upload-pack response" func=gitxt.net/gitxt/internal/git.UploadPackHandler.func1 file="/src/internal/git/handler.go:243" error="write tcp 10.0.2.216:5555->10.0.2.163:42390: write: broken pipe"
    2022/12/29 14:59:47 http: superfluous response.WriteHeader call from gitxt.net/gitxt/internal/git.UploadPackHandler.func1 (handler.go:244)
    

    I'm really not sure what's going wrong here 🤔

  • warning: remote HEAD refers to nonexistent ref, unable to checkout.

    warning: remote HEAD refers to nonexistent ref, unable to checkout.

    What does this error/warning mean on the client git when cloning a repo being served by go-git?

    warning: remote HEAD refers to nonexistent ref, unable to checkout.
    

    What am I missing in the code that handles this? 🤔

  • Is there a way to skip certain file format during clone and pull?

    Is there a way to skip certain file format during clone and pull?

    I am building an app based on Git mechanism. This pkg is a great lib for my purpose.

    The repo is a mix of text files and large image files. Cloning/pulling everything is slow.

    Is there a way to clone/pull only the text files?

    Thanks.

  • Status.IsClean fooled by LFS files (and other smudge filters)

    Status.IsClean fooled by LFS files (and other smudge filters)

    I know this project isn't intending to support LFS, but I think this problem isn't LFS specific. I suspect it'd happen with any repo that uses a smudge filter. Specifically, a file that was downloaded by LFS has it's Status.Worktree == Modified so this code reports that any repo that's using a smudge filter is not clean:

    func (s Status) IsClean() bool {
    	for _, status := range s {
    		if status.Worktree != Unmodified || status.Staging != Unmodified {
    			return false
    		}
    	}
    
    	return true
    }
    

    I'm not quite sure what the workaround would be but there must be a way as git status does not report these files as modified. Clearly the .gitattributes contains some information but I think git must store additional info about what smudge filters did somewhere so it knows if a file was "really" modified or not.

  • tag checkout not working

    tag checkout not working

    Hello @mcuadros ref https://github.com/src-d/go-git/issues/574

    git branch just shows (no branch)

    package main
    
    import (
    	"fmt"
    	"github.com/go-git/go-git/v5"
    	"github.com/go-git/go-git/v5/plumbing"
    	"os"
    )
    
    func main() {
    	// Create the temporary directory for cloning
    	dir := "git2"
    
    	// Clone it into the target directory getting only the tag commit
    	repo, err := git.PlainClone(dir, false, &git.CloneOptions{
    		URL: "https://github.com/mitchellh/go-git-test-failure.git",
    	})
    	if err != nil {
    		os.RemoveAll(dir)
    		panic(err)
    	}
    
    	// Get the working tree so we can change refs
    	tree, err := repo.Worktree()
    	if err != nil {
    		panic(err)
    	}
    
    	tagName := "v0.1.0"
    
    	// Checkout our tag
    	err = tree.Checkout(&git.CheckoutOptions{
    		Branch: plumbing.ReferenceName("refs/tags/" + tagName),
    	})
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(dir)
    }
    
  • When accessing cloudlab git server over https invalid pkt-len found

    When accessing cloudlab git server over https invalid pkt-len found

    When I'm trying use PlainClone over https on a cloudlab server I'm seeing 'invalid pkt-len found' This uses a token for authentication in the form of https://user:[email protected]

    From my command line this works with git just not go-git.

Git with a cup of tea, painless self-hosted git service
Git with a cup of tea, painless self-hosted git service

Gitea - Git with a cup of tea View the chinese version of this document Purpose The goal of this project is to make the easiest, fastest, and most pai

Jan 2, 2023
A Git RPC service for handling all the git calls made by GitLab
A Git RPC service for handling all the git calls made by GitLab

Quick Links: Roadmap | Want to Contribute? | GitLab Gitaly Issues | GitLab Gitaly Merge Requests | Gitaly is a Git RPC service for handling all the gi

Nov 13, 2021
A simple cli tool for switching git user easily inspired by Git-User-Switch
A simple cli tool for switching git user easily inspired by Git-User-Switch

gitsu A simple cli tool for switching git user easily inspired by Git-User-Switch Installation Binary releases are here. Homebrew brew install matsuyo

Dec 31, 2022
Removes unnecessarily saved git objects to optimize the size of the .git directory.

Git Repo Cleaner Optimizes the size of the .git directory by removing all of the files that are unnecessarily-still-saved as part of the git history.

Mar 24, 2022
Gum - Git User Manager (GUM) - Switch between git user profiles
Gum - Git User Manager (GUM) - Switch between git user profiles

Git User Manager (GUM) Add your profile info to config.yaml Build project: go bu

Feb 14, 2022
Git-now-playing - Git commits are the new AIM status messages

git-now-playing git-now-playing is an attempt to bring some of the panache of th

Apr 4, 2022
Implementation of git internals from scratch in Go language
Implementation of git internals from scratch in Go language

This project is part of a learning exercise to implement a subset of "git" commands. It can be used to create and maintain git objects, such as blobs, trees, commits, references and tags.

Nov 27, 2022
Gogs is a painless self-hosted Git service
Gogs is a painless self-hosted Git service

Gogs - A painless self-hosted Git service 简体中文 ?? Vision The Gogs (/gɑgz/) project aims to build a simple, stable and extensible self-hosted Git servi

Jan 9, 2023
commit/branch/workdir explorer for git

gitin gitin is a commit/branch/status explorer for git gitin is a minimalist tool that lets you explore a git repository from the command line. You ca

Dec 31, 2022
A command-line tool that makes git easier to use with GitHub.

hub is a command line tool that wraps git in order to extend it with extra features and commands that make working with GitHub easier. For an official

Jan 1, 2023
A tool to monitor git repositories and automatically pull & push changes

git-o-matic A tool to monitor git repositories and automatically pull & push changes Installation Packages & Binaries Arch Linux: gitomatic Binaries f

Dec 20, 2022
SQL interface to git repositories, written in Go. https://docs.sourced.tech/gitbase

gitbase gitbase, is a SQL database interface to Git repositories. This project is now part of source{d} Community Edition, which provides the simplest

Dec 25, 2022
Fast and powerful Git hooks manager for any type of projects.
Fast and powerful Git hooks manager for any type of projects.

Lefthook The fastest polyglot Git hooks manager out there Fast and powerful Git hooks manager for Node.js, Ruby or any other type of projects. Fast. I

Jan 4, 2023
A Simple and Comprehensive Vulnerability Scanner for Container Images, Git Repositories and Filesystems. Suitable for CI
A Simple and Comprehensive Vulnerability Scanner for Container Images, Git Repositories and Filesystems. Suitable for CI

A Simple and Comprehensive Vulnerability Scanner for Containers and other Artifacts, Suitable for CI. Abstract Trivy (tri pronounced like trigger, vy

Jan 9, 2023
go mod vendor lets you check in your dependencies to git, but that's both bloaty (for developers) and tedious (remembering to update it).

go-mod-archiver Afraid of being unable to build historical versions of your Go program? go mod vendor lets you check in your dependencies to git, but

Dec 1, 2022
Quickly clone git repositories into a nested folders like GOPATH.

cl cl clones git repositories into nested folders like GOPATH and outputs the path of the cloned directory. Example: cl https://github.com/foo/bar Is

Nov 30, 2022
Switch between your git profiles easily
Switch between your git profiles easily

Git Profile Switcher Switch between your git profiles easily Install With Brew brew install theykk/tap/git-switcher With golang go get github.com/the

Dec 11, 2022
Store private data inside a git repository.

git-private lets you store private data inside a git repo. A common use case is protecting files containing API keys et.c.

Nov 13, 2022
Simple git hooks written in go that installs globally to your machine

Go-hooks Simple git hooks written in go that installs globally to your machine Install curl -fsSL

Oct 19, 2022