Add worktree support - Bump version of libgit2 #956
|
@ -12,7 +12,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: [ 'release-1.3', 'release-1.2', 'release-1.1', 'release-1.0', 'release-0.28', 'release-0.27' ]
|
||||
branch: [ 'release-1.6', 'release-1.5', 'release-1.3', 'release-1.2', 'release-1.1', 'release-1.0', 'release-0.28', 'release-0.27' ]
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
libgit2:
|
||||
- 'v1.5.0'
|
||||
- 'v1.7.0'
|
||||
name: Go (system-wide, dynamic)
|
||||
|
||||
runs-on: ubuntu-20.04
|
||||
|
|
|
@ -10,8 +10,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_STATIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 5 || LIBGIT2_VER_MINOR > 5
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.5.0 and v1.5.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 7 || LIBGIT2_VER_MINOR > 7
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v1.7.x"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -8,8 +8,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_DYNAMIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 5 || LIBGIT2_VER_MINOR > 5
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.5.0 and v1.5.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 7 || LIBGIT2_VER_MINOR > 7
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v1.7.x"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
|
@ -8,8 +8,8 @@ package git
|
|||
#cgo CFLAGS: -DLIBGIT2_STATIC
|
||||
#include <git2.h>
|
||||
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 5 || LIBGIT2_VER_MINOR > 5
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.5.0 and v1.5.0"
|
||||
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 7 || LIBGIT2_VER_MINOR > 7
|
||||
# error "Invalid libgit2 version; this git2go supports libgit2 v1.7.x"
|
||||
#endif
|
||||
*/
|
||||
import "C"
|
||||
|
|
14
README.md
14
README.md
|
@ -10,7 +10,9 @@ Due to the fact that Go 1.11 module versions have semantic meaning and don't nec
|
|||
|
||||
| libgit2 | git2go |
|
||||
|---------|---------------|
|
||||
| main | (will be v35) |
|
||||
| main | (will be v37) |
|
||||
| 1.7 | v36 |
|
||||
| 1.6 | v35 |
|
||||
| 1.5 | v34 |
|
||||
| 1.3 | v33 |
|
||||
| 1.2 | v32 |
|
||||
|
@ -20,13 +22,13 @@ Due to the fact that Go 1.11 module versions have semantic meaning and don't nec
|
|||
| 0.28 | v28 |
|
||||
| 0.27 | v27 |
|
||||
|
||||
You can import them in your project with the version's major number as a suffix. For example, if you have libgit2 v1.2 installed, you'd import git2go v34 with:
|
||||
You can import them in your project with the version's major number as a suffix. For example, if you have libgit2 v1.2 installed, you'd import git2go v35 with:
|
||||
|
||||
```sh
|
||||
go get github.com/libgit2/git2go/v34
|
||||
go get github.com/libgit2/git2go/v36
|
||||
```
|
||||
```go
|
||||
import "github.com/libgit2/git2go/v34"
|
||||
import "github.com/libgit2/git2go/v36"
|
||||
```
|
||||
|
||||
which will ensure there are no sudden changes to the API.
|
||||
|
@ -50,7 +52,7 @@ This project wraps the functionality provided by libgit2. If you're using a vers
|
|||
When linking dynamically against a released version of libgit2, install it via your system's package manager. CGo will take care of finding its pkg-config file and set up the linking. Import via Go modules, e.g. to work against libgit2 v1.2
|
||||
|
||||
```go
|
||||
import "github.com/libgit2/git2go/v34"
|
||||
import "github.com/libgit2/git2go/v36"
|
||||
```
|
||||
|
||||
### Versioned branch, static linking
|
||||
|
@ -80,7 +82,7 @@ In order to let Go pass the correct flags to `pkg-config`, `-tags static` needs
|
|||
|
||||
One thing to take into account is that since Go expects the `pkg-config` file to be within the same directory where `make install-static` was called, so the `go.mod` file may need to have a [`replace` directive](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) so that the correct setup is achieved. So if `git2go` is checked out at `$GOPATH/src/github.com/libgit2/git2go` and your project at `$GOPATH/src/github.com/my/project`, the `go.mod` file of `github.com/my/project` might need to have a line like
|
||||
|
||||
replace github.com/libgit2/git2go/v34 => ../../libgit2/git2go
|
||||
replace github.com/libgit2/git2go/v36 => ../../libgit2/git2go
|
||||
|
||||
Parallelism and network operations
|
||||
----------------------------------
|
||||
|
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
|||
module github.com/libgit2/git2go/v34
|
||||
module github.com/libgit2/git2go/v36
|
||||
|
||||
go 1.13
|
||||
|
||||
|
|
|
@ -36,6 +36,9 @@ type Repository struct {
|
|||
// Stashes represents the collection of stashes and can be used to
|
||||
// save, apply and iterate over stash states in this repository.
|
||||
Stashes StashCollection
|
||||
// Worktrees represents the collection of worktrees and can be used to
|
||||
// add, list and remove worktrees for this repository
|
||||
Worktrees WorktreeCollection
|
||||
|
||||
// weak indicates that a repository is a weak pointer and should not be
|
||||
// freed.
|
||||
|
@ -52,6 +55,7 @@ func newRepositoryFromC(ptr *C.git_repository) *Repository {
|
|||
repo.Notes.repo = repo
|
||||
repo.Tags.repo = repo
|
||||
repo.Stashes.repo = repo
|
||||
repo.Worktrees.repo = repo
|
||||
|
||||
runtime.SetFinalizer(repo, (*Repository).Free)
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit fbea439d4b6fc91c6b619d01b85ab3b7746e4c19
|
||||
Subproject commit 3e2baa6d0bfb42f9016e24cba1733a6ae26a8ae6
|
|
@ -0,0 +1,271 @@
|
|||
package git
|
||||
|
||||
/*
|
||||
#include <git2.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type WorktreeCollection struct {
|
||||
doNotCompare
|
||||
repo *Repository
|
||||
}
|
||||
|
||||
type Worktree struct {
|
||||
doNotCompare
|
||||
ptr *C.git_worktree
|
||||
}
|
||||
|
||||
type AddWorktreeOptions struct {
|
||||
// Lock the newly created worktree
|
||||
Lock bool
|
||||
// Reference to use for the new worktree
|
||||
Reference *Reference
|
||||
// CheckoutOptions is used for configuring the checkout for the newly created worktree
|
||||
CheckoutOptions CheckoutOptions
|
||||
}
|
||||
|
||||
// Add adds a new working tree for the given repository
|
||||
func (c *WorktreeCollection) Add(name string, path string, options *AddWorktreeOptions) (*Worktree, error) {
|
||||
cName := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cName))
|
||||
|
||||
cPath := C.CString(path)
|
||||
defer C.free(unsafe.Pointer(cPath))
|
||||
|
||||
var err error
|
||||
cOptions := populateAddWorktreeOptions(&C.git_worktree_add_options{}, options, &err)
|
||||
defer freeAddWorktreeOptions(cOptions)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_worktree
|
||||
ret := C.git_worktree_add(&ptr, c.repo.ptr, cName, cPath, cOptions)
|
||||
runtime.KeepAlive(c)
|
||||
if options != nil && options.Reference != nil {
|
||||
runtime.KeepAlive(options.Reference)
|
||||
}
|
||||
|
||||
if ret == C.int(ErrorCodeUser) && err != nil {
|
||||
return nil, err
|
||||
} else if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
return newWorktreeFromC(ptr), nil
|
||||
}
|
||||
|
||||
// List lists names of linked working trees for the given repository
|
||||
func (c *WorktreeCollection) List() ([]string, error) {
|
||||
var strC C.git_strarray
|
||||
defer C.git_strarray_dispose(&strC)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_list(&strC, c.repo.ptr)
|
||||
runtime.KeepAlive(c)
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
|
||||
w := makeStringsFromCStrings(strC.strings, int(strC.count))
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// Lookup gets a working tree by its name for the given repository
|
||||
func (c *WorktreeCollection) Lookup(name string) (*Worktree, error) {
|
||||
cname := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cname))
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_worktree
|
||||
ret := C.git_worktree_lookup(&ptr, c.repo.ptr, cname)
|
||||
runtime.KeepAlive(c)
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
} else if ptr == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return newWorktreeFromC(ptr), nil
|
||||
}
|
||||
|
||||
// OpenFromRepository retrieves a worktree for the given repository
|
||||
func (c *WorktreeCollection) OpenFromRepository() (*Worktree, error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
var ptr *C.git_worktree
|
||||
ret := C.git_worktree_open_from_repository(&ptr, c.repo.ptr)
|
||||
runtime.KeepAlive(c)
|
||||
|
||||
if ret < 0 {
|
||||
return nil, MakeGitError(ret)
|
||||
}
|
||||
return newWorktreeFromC(ptr), nil
|
||||
}
|
||||
|
||||
func newWorktreeFromC(ptr *C.git_worktree) *Worktree {
|
||||
worktree := &Worktree{ptr: ptr}
|
||||
runtime.SetFinalizer(worktree, (*Worktree).Free)
|
||||
return worktree
|
||||
}
|
||||
|
||||
func freeAddWorktreeOptions(cOptions *C.git_worktree_add_options) {
|
||||
if cOptions == nil {
|
||||
return
|
||||
}
|
||||
freeCheckoutOptions(&cOptions.checkout_options)
|
||||
}
|
||||
|
||||
func populateAddWorktreeOptions(cOptions *C.git_worktree_add_options, options *AddWorktreeOptions, errorTarget *error) *C.git_worktree_add_options {
|
||||
C.git_worktree_add_options_init(cOptions, C.GIT_WORKTREE_ADD_OPTIONS_VERSION)
|
||||
if options == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
populateCheckoutOptions(&cOptions.checkout_options, &options.CheckoutOptions, errorTarget)
|
||||
cOptions.lock = cbool(options.Lock)
|
||||
if options.Reference != nil {
|
||||
cOptions.ref = options.Reference.ptr
|
||||
}
|
||||
return cOptions
|
||||
}
|
||||
|
||||
// Free a previously allocated worktree
|
||||
func (w *Worktree) Free() {
|
||||
runtime.SetFinalizer(w, nil)
|
||||
C.git_worktree_free(w.ptr)
|
||||
}
|
||||
|
||||
// IsLocked checks if the given worktree is locked
|
||||
func (w *Worktree) IsLocked() (locked bool, reason string, err error) {
|
||||
buf := C.git_buf{}
|
||||
defer C.git_buf_dispose(&buf)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_is_locked(&buf, w.ptr)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return false, "", MakeGitError(ret)
|
||||
}
|
||||
return ret != 0, C.GoString(buf.ptr), nil
|
||||
}
|
||||
|
||||
type WorktreePruneFlag uint32
|
||||
|
||||
const (
|
||||
// WorktreePruneValid means prune working tree even if working tree is valid
|
||||
WorktreePruneValid WorktreePruneFlag = C.GIT_WORKTREE_PRUNE_VALID
|
||||
// WorktreePruneLocked means prune working tree even if it is locked
|
||||
WorktreePruneLocked WorktreePruneFlag = C.GIT_WORKTREE_PRUNE_LOCKED
|
||||
// WorktreePruneWorkingTree means prune checked out working tree
|
||||
WorktreePruneWorkingTree WorktreePruneFlag = C.GIT_WORKTREE_PRUNE_WORKING_TREE
|
||||
)
|
||||
|
||||
// IsPrunable checks that the worktree is prunable with the given flags
|
||||
func (w *Worktree) IsPrunable(flags WorktreePruneFlag) (bool, error) {
|
||||
cOptions := C.git_worktree_prune_options{}
|
||||
C.git_worktree_prune_options_init(&cOptions, C.GIT_WORKTREE_PRUNE_OPTIONS_VERSION)
|
||||
cOptions.flags = C.uint32_t(flags)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_is_prunable(w.ptr, &cOptions)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return false, MakeGitError(ret)
|
||||
}
|
||||
return ret != 0, nil
|
||||
}
|
||||
|
||||
// Lock locks the worktree if not already locked
|
||||
func (w *Worktree) Lock(reason string) error {
|
||||
var cReason *C.char
|
||||
if reason != "" {
|
||||
cReason = C.CString(reason)
|
||||
defer C.free(unsafe.Pointer(cReason))
|
||||
}
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_lock(w.ptr, cReason)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Name retrieves the name of the worktree
|
||||
func (w *Worktree) Name() string {
|
||||
s := C.GoString(C.git_worktree_name(w.ptr))
|
||||
runtime.KeepAlive(w)
|
||||
return s
|
||||
}
|
||||
|
||||
// Path retrieves the path of the worktree
|
||||
func (w *Worktree) Path() string {
|
||||
s := C.GoString(C.git_worktree_path(w.ptr))
|
||||
runtime.KeepAlive(w)
|
||||
return s
|
||||
}
|
||||
|
||||
// Prune the worktree with the provided flags
|
||||
func (w *Worktree) Prune(flags WorktreePruneFlag) error {
|
||||
cOptions := C.git_worktree_prune_options{}
|
||||
C.git_worktree_prune_options_init(&cOptions, C.GIT_WORKTREE_PRUNE_OPTIONS_VERSION)
|
||||
cOptions.flags = C.uint32_t(flags)
|
||||
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_prune(w.ptr, &cOptions)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unlock a locked worktree
|
||||
func (w *Worktree) Unlock() (notLocked bool, err error) {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_unlock(w.ptr)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return false, MakeGitError(ret)
|
||||
}
|
||||
return ret != 0, nil
|
||||
}
|
||||
|
||||
// Validate checks if the given worktree is valid
|
||||
func (w *Worktree) Validate() error {
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
ret := C.git_worktree_validate(w.ptr)
|
||||
runtime.KeepAlive(w)
|
||||
|
||||
if ret < 0 {
|
||||
return MakeGitError(ret)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package git
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertSamePath(t *testing.T, expected string, actual string) {
|
||||
var err error
|
||||
expected, err = filepath.EvalSymlinks(expected)
|
||||
checkFatal(t, err)
|
||||
actual, err = filepath.EvalSymlinks(actual)
|
||||
checkFatal(t, err)
|
||||
|
||||
if expected != actual {
|
||||
t.Fatalf("wrong path (expected %s, got %s)", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddWorkspace(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
worktreeName := "testWorktree"
|
||||
worktreePath := filepath.Join(worktreeTemporaryPath, "worktree")
|
||||
|
||||
worktree, err := repo.Worktrees.Add(worktreeName, worktreePath, &AddWorktreeOptions{
|
||||
Lock: true, CheckoutOptions: CheckoutOptions{Strategy: CheckoutForce},
|
||||
})
|
||||
checkFatal(t, err)
|
||||
|
||||
if name := worktree.Name(); name != worktreeName {
|
||||
t.Fatalf("wrong worktree name: %s != %s", worktreeName, name)
|
||||
}
|
||||
locked, _, err := worktree.IsLocked()
|
||||
checkFatal(t, err)
|
||||
if locked != true {
|
||||
t.Fatal("worktree isn't locked")
|
||||
}
|
||||
assertSamePath(t, worktreePath, worktree.Path())
|
||||
checkFatal(t, worktree.Validate())
|
||||
}
|
||||
|
||||
func TestAddWorkspaceWithoutOptions(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
worktreeName := "testWorktree"
|
||||
worktreePath := filepath.Join(worktreeTemporaryPath, "worktree")
|
||||
|
||||
worktree, err := repo.Worktrees.Add(worktreeName, worktreePath, nil)
|
||||
checkFatal(t, err)
|
||||
|
||||
if name := worktree.Name(); name != worktreeName {
|
||||
t.Fatalf("wrong worktree name: %s != %s", worktreeName, name)
|
||||
}
|
||||
locked, _, err := worktree.IsLocked()
|
||||
checkFatal(t, err)
|
||||
if locked != false {
|
||||
t.Fatal("worktree is locked")
|
||||
}
|
||||
assertSamePath(t, worktreePath, worktree.Path())
|
||||
checkFatal(t, worktree.Validate())
|
||||
}
|
||||
|
||||
func TestLookupWorkspace(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
worktreeName := "testWorktree"
|
||||
|
||||
worktree, err := repo.Worktrees.Add(worktreeName, filepath.Join(worktreeTemporaryPath, "worktree"), nil)
|
||||
checkFatal(t, err)
|
||||
retrievedWorktree, err := repo.Worktrees.Lookup(worktreeName)
|
||||
checkFatal(t, err)
|
||||
|
||||
assertSamePath(t, worktree.Path(), retrievedWorktree.Path())
|
||||
}
|
||||
|
||||
func TestListWorkspaces(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
|
||||
worktreeNames := []string{"worktree1", "worktree2", "worktree3"}
|
||||
for _, name := range worktreeNames {
|
||||
_, err = repo.Worktrees.Add(name, filepath.Join(worktreeTemporaryPath, name), nil)
|
||||
checkFatal(t, err)
|
||||
}
|
||||
listedWorktree, err := repo.Worktrees.List()
|
||||
checkFatal(t, err)
|
||||
|
||||
if len(worktreeNames) != len(listedWorktree) {
|
||||
t.Fatalf("len(worktreeNames) != len(listedWorktree) as %d != %d", len(worktreeNames), len(listedWorktree))
|
||||
}
|
||||
for _, name := range worktreeNames {
|
||||
found := false
|
||||
for _, nameToMatch := range listedWorktree {
|
||||
if name == nameToMatch {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
t.Fatalf("worktree %s is missing", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestOpenWorkspaceFromRepository(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
|
||||
worktree, err := repo.Worktrees.Add("testWorktree", filepath.Join(worktreeTemporaryPath, "worktree"), nil)
|
||||
checkFatal(t, err)
|
||||
worktreeRepo, err := OpenRepository(worktree.Path())
|
||||
checkFatal(t, err)
|
||||
worktreeFromRepo, err := worktreeRepo.Worktrees.OpenFromRepository()
|
||||
checkFatal(t, err)
|
||||
|
||||
if worktreeFromRepo.Name() != worktree.Name() {
|
||||
t.Fatalf("wrong name (expected %s, got %s)", worktreeFromRepo.Name(), worktree.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorktreeIsPrunable(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
|
||||
worktree, err := repo.Worktrees.Add("testWorktree", filepath.Join(worktreeTemporaryPath, "worktree"), nil)
|
||||
checkFatal(t, err)
|
||||
err = worktree.Lock("test")
|
||||
checkFatal(t, err)
|
||||
|
||||
isPrunableWithoutLockedFlag, err := worktree.IsPrunable(WorktreePruneValid)
|
||||
checkFatal(t, err)
|
||||
if isPrunableWithoutLockedFlag {
|
||||
t.Fatal("worktree shouldn't be prunable without the WorktreePruneLocked flag")
|
||||
}
|
||||
isPrunableWithLockedFlag, err := worktree.IsPrunable(WorktreePruneValid | WorktreePruneLocked)
|
||||
checkFatal(t, err)
|
||||
if !isPrunableWithLockedFlag {
|
||||
t.Fatal("worktree should be prunable with the WorktreePruneLocked flag")
|
||||
}
|
||||
|
||||
err = worktree.Prune(WorktreePruneValid | WorktreePruneLocked)
|
||||
checkFatal(t, err)
|
||||
}
|
||||
|
||||
func TestWorktreeCanBeLockedAndUnlocked(t *testing.T) {
|
||||
t.Parallel()
|
||||
repo := createTestRepo(t)
|
||||
defer cleanupTestRepo(t, repo)
|
||||
seedTestRepo(t, repo)
|
||||
|
||||
worktreeTemporaryPath, err := ioutil.TempDir("", "git2go")
|
||||
checkFatal(t, err)
|
||||
defer func() { checkFatal(t, os.RemoveAll(worktreeTemporaryPath)) }()
|
||||
|
||||
worktree, err := repo.Worktrees.Add("testWorktree", filepath.Join(worktreeTemporaryPath, "worktree"), nil)
|
||||
checkFatal(t, err)
|
||||
notLocked, err := worktree.Unlock()
|
||||
checkFatal(t, err)
|
||||
if !notLocked {
|
||||
t.Fatal("worktree should be unlocked by default")
|
||||
}
|
||||
|
||||
expectedReason := "toTestIt"
|
||||
err = worktree.Lock(expectedReason)
|
||||
checkFatal(t, err)
|
||||
isLocked, reason, err := worktree.IsLocked()
|
||||
checkFatal(t, err)
|
||||
if !isLocked {
|
||||
t.Fatal("worktree should be locked after the locking operation")
|
||||
}
|
||||
if expectedReason != reason {
|
||||
t.Fatalf("locked reason doesn't match: %s != %s", expectedReason, reason)
|
||||
}
|
||||
|
||||
notLocked, err = worktree.Unlock()
|
||||
checkFatal(t, err)
|
||||
if notLocked {
|
||||
t.Fatal("worktree was lock before so notLocked should be false")
|
||||
}
|
||||
isLocked, _, err = worktree.IsLocked()
|
||||
checkFatal(t, err)
|
||||
if isLocked {
|
||||
t.Fatal("worktree should be unlocked after the Unlock() call")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue