Git知识点:go-git库

685 阅读2分钟

go-git是一个使用Go语言实现的高度可扩展的Git库(类似libgit2或jgit),可以很方便地将Git集成到Go语言编写的服务中。go-git的目标是与git完全兼容,目前它涵盖了大多数基本的读操作和一些主要的写操作,但缺少诸如合并之类的主要操作,go-git支持的命令详见兼容性文档

JGit是Java语言实现的Git库。

Dulwich是Python语言实现的Git库。

Libgit2是C语言实现的Git库,Libgit2有很多种语言的绑定,git2go是Go语言的Libgit2绑定。

代码示例

1,使用go-git将本地目录初始化为Git仓库:git init <directory>

$ vim main.go
package main

import (
    "fmt"
    "os"
    "path/filepath"
    "time"

    "github.com/go-git/go-git/v5"
    "github.com/go-git/go-git/v5/plumbing/object"
)

// https://github.com/go-git/go-git/blob/master/_examples/sha256/main.go
func main() {
    var (
        directory string = "repository"
        filename  string = "example-git-file"
        content   string = "hello world!"
        message   string = "example go-git commit"
        name      string = "leitiannet"
        email     string = "347341200@qq.com"
    )
    // 删除仓库
    os.RemoveAll(directory)
    // 初始化仓库
    Info("git init %s", directory)
    r, err := git.PlainInit(directory, false)
    CheckIfError(err)
    // 新建文件
    Info("echo -n \"%s\" > %s", content, filename)
    err = os.WriteFile(filepath.Join(directory, filename), []byte(content), 0644)
    CheckIfError(err)
    // 将文件内容从工作目录添加到暂存区
    Info("git add %s", filename)
    w, err := r.Worktree()
    CheckIfError(err)
    _, err = w.Add(filename)
    CheckIfError(err)
    // 提交更新(将暂存区的内容在数据库中创建持久快照)
    Info("git commit -m \"%s\"", message)
    commit, err := w.Commit(message, &git.CommitOptions{
        Author: &object.Signature{
            Name:  name,
            Email: email,
            When:  time.Now(),
        },
    })
    CheckIfError(err)
    // 显示提交信息
    Info("git show -s")
    obj, err := r.CommitObject(commit)
    CheckIfError(err)
    fmt.Println(obj)
}

func CheckIfError(err error) {
    if err == nil {
        return
    }
    fmt.Printf("\x1b[31;1m%s\x1b[0m\n", fmt.Sprintf("error: %s", err))
    os.Exit(1)
}

func Info(format string, args ...interface{}) {
    fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...))
}
$ export GO111MODULE=on
$ export GOPROXY="https://goproxy.cn"
$ go mod init gogit
$ go mod edit -require github.com/go-git/go-git/v5@v5.6.0
$ go mod tidy
$ go run main.go
git init repository
echo -n "hello world!" > example-git-file
git add example-git-file
git commit -m "example go-git commit"
git show -s
commit 93974121806693d28738bdbc6a6025221ba01666
Author: leitiannet <347341200@qq.com>
Date:   Mon Jun 03 21:25:54 2024 +0800

    example go-git commit

2,使用go-git从其它服务器克隆Git仓库:git clone <repository> <directory>

$ vim main.go
package main

import (
	"fmt"
	"os"

	"github.com/go-git/go-git/v5"
)

// https://github.com/go-git/go-git/blob/master/_examples/clone/main.go
func main() {
	var (
		url       string = "https://github.com/leitiannet/template.git"
		directory string = "repository"
	)
	// 删除仓库
	os.RemoveAll(directory)
	// 克隆仓库
	Info("git clone %s %s", url, directory)
	r, err := git.PlainClone(directory, false, &git.CloneOptions{
		URL:      url,
		Progress: os.Stdout,
	})
	CheckIfError(err)
	// 显示提交历史
	Info("git log -1")
	// 获取HEAD指向的分支
	ref, err := r.Head()
	CheckIfError(err)
	commit, err := r.CommitObject(ref.Hash())
	CheckIfError(err)
	fmt.Println(commit)
}

func CheckIfError(err error) {
	if err == nil {
		return
	}
	fmt.Printf("\x1b[31;1m%s\x1b[0m\n", fmt.Sprintf("error: %s", err))
	os.Exit(1)
}

func Info(format string, args ...interface{}) {
	fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...))
}
$ export GO111MODULE=on
$ export GOPROXY="https://goproxy.cn"
$ go mod init gogit
$ go mod edit -require github.com/go-git/go-git/v5@v5.6.0
$ go mod tidy
$ go run main.go
git clone https://github.com/leitiannet/template.git repository
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Compressing objects: 100% (15/15), done.
Total 21 (delta 1), reused 21 (delta 1), pack-reused 0
git log -1
commit 192fceb15074c3ca7a208cbb21a39c3578589960
Author: leitiannet <347341200@qq.com>
Date:   Sun May 19 07:54:35 2024 +0800

    init Go project template

结构关系

image.png

  • Repository:仓库,只要拥有一个Repository实例,就可以访问相应仓库信息并对其进行改变
  • Worktree:工作树,即工作目录
  • storage.Storer:存储系统
  • billy.Filesystem:文件系统

参考资料

go-git

pkg.go.dev/github.com/…

在你的应用中嵌入 Git - go-git