Compare commits

...

11 Commits

Author SHA1 Message Date
lhchavez 7c1ecf79b4 Fix the `github-tag-action` workflow (#932)
This has been failing for a while because of some changes in `git`.

(cherry picked from commit 4b14d29c20)
2022-10-05 01:12:39 +00:00
github-actions[bot] a53cd8b512
Add refspec bindings (#898) (#907)
This add support for the parse, access, and transform functions for
refspec objects.

(cherry picked from commit eae00773cc)

Co-authored-by: William Bain <bain.william.a@gmail.com>
2022-02-24 19:31:34 -08:00
github-actions[bot] a7dc7d41b9
rebase: Add wrapper for `git_rebase_inmemory_index()` (#900) (#904)
* rebase: Fix missing initialization of the repo pointer

While the `Rebase` structure has a pointer to the repository the rebase
is creatde in, this pointer isn't ever initialized. Fix this.

* rebase: Add wrapper for `git_rebase_inmemory_index()`

Add a new wrapper for `git_rebase_inmemory_index()`, which can be used
to retrieve the index for an in-memory rebase.

Co-authored-by: Patrick Steinhardt <psteinhardt@gitlab.com>
(cherry picked from commit e7d1b2b69f)

Co-authored-by: Patrick Steinhardt <ps@pks.im>
2022-02-24 19:20:37 -08:00
Dylan Richardson 8230ed934e
readme: link to godoc for current main branch (#892)
This is a release-specific change corresponding to #886
2022-01-22 19:04:16 -08:00
github-actions[bot] 9dfdab765a
Add ProxyOptions for push operations (#872) (#882)
Analog to #623 but for push operations rather than fetch.

(cherry picked from commit 5eca48cda9)

Co-authored-by: Aurélien <6292584+au2001@users.noreply.github.com>
2022-01-17 19:06:48 -08:00
github-actions[bot] a3f32b93cd
Add EnableFsyncGitDir to enable synchronized writes to the gitdir (#874) (#877)
This adds support for the GIT_OPT_ENABLE_FSYNC_GITDIR option in libgit2.

Co-authored-by: James Fargher <jfargher@gitlab.com>
(cherry picked from commit 1fcc9d8743)

Co-authored-by: James Fargher <proglottis@gmail.com>
2022-01-17 19:00:12 -08:00
lhchavez a964575453
Generate stringer files automatically (#841) (#865)
Added `stringer` annotations to `git.go` for `ErrorClass` and
`ErrorCode`. Added `generate` rule for `Makefile` to generate
string representations for these types (first building cgo files
in `_obj` dir to get C constants). Finally, updated `ci` actions
workflow to check that generated files are up to date.

Fixes: #543
(cherry picked from commit 5e35338d58)

Co-authored-by: Kirill <g4s8.public@gmail.com>
2021-11-09 06:46:28 -08:00
lhchavez a6446ac047
Fix replace statement example in README.md (#859) (#860)
(cherry picked from commit 533c82f270)

Co-authored-by: Ignacio Taranto <ignacio_taranto@protonmail.com>
2021-11-09 06:36:00 -08:00
github-actions[bot] 3033505879
Make ssh commands used in the git smart transport compatible with libgit2 (#852) (#856)
* Fix ssh commands used in go SmartSubtransport

Before the fix, the commands sent were of the form:

```
git-upload-pack "/bar/test-reponame"
```

This resulted in the git server returning error:
`error parsing command: invalid git command`

This change replaces the double quotes with single quotes:

```
git-upload-pack '/bar/test-reponame'
```

* Update ssh.go

Co-authored-by: lhchavez <lhchavez@lhchavez.com>
(cherry picked from commit 6cea7a7a59)

Co-authored-by: Sunny <darkowlzz@protonmail.com>
Co-authored-by: lhchavez <lhchavez@lhchavez.com>
2021-11-09 06:27:24 -08:00
github-actions[bot] bacde67336
bugfix: HTTPS Clone fails with remote pointer not found using Go transport (#836) (#842) (#849)
Fixes: #836

Changes:

* adding a weak bool param for Remote
* create a new remote in the smartTransportCallback incase one is not found

(cherry picked from commit 0e8009f00a)

Co-authored-by: Yashodhan Ghadge <codexetreme@users.noreply.github.com>
Co-authored-by: lhchavez <lhchavez@lhchavez.com>
2021-11-09 06:23:02 -08:00
lhchavez 37d4d3ddf8
Declare forward-compatibility with libgit2 v1.3.0 #minor (#843)
This commit marks this (Golang) version of git2go as being compatible
with libgit2 v1.3.0.
2021-10-16 04:50:06 -07:00
18 changed files with 427 additions and 18 deletions

View File

@ -63,6 +63,7 @@ jobs:
matrix:
libgit2:
- '109b4c887ffb63962c7017a66fc4a1f48becb48e' # v1.2.0 with a fixed symbol
- 'v1.3.0'
name: Go (system-wide, dynamic)
runs-on: ubuntu-20.04
@ -105,3 +106,26 @@ jobs:
sudo ./script/build-libgit2.sh --static --system
- name: Test
run: go test --count=1 --tags "static,system_libgit2" ./...
check-generate:
name: Check generated files were not modified
runs-on: ubuntu-20.04
steps:
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: '1.17'
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Install libgit2 build dependencies
run: |
git submodule update --init
sudo apt-get install -y --no-install-recommends libssh2-1-dev
go install golang.org/x/tools/cmd/stringer@latest
- name: Generate files
run: |
export PATH=$(go env GOPATH)/bin:$PATH
make generate
- name: Check nothing changed
run: git diff --quiet --exit-code || (echo "detected changes after generate" ; git status ; exit 1)

View File

@ -19,7 +19,7 @@ jobs:
fetch-depth: 0
- name: Bump version and push tag
id: bump-version
uses: anothrNick/github-tag-action@9aaabdb5e989894e95288328d8b17a6347217ae3
uses: anothrNick/github-tag-action@43ed073f5c1445ca8b80d920ce2f8fa550ae4e8d
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
WITH_V: true

View File

@ -10,8 +10,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
#endif
*/
import "C"

View File

@ -8,8 +8,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_DYNAMIC
#include <git2.h>
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
#endif
*/
import "C"

View File

@ -8,8 +8,8 @@ package git
#cgo CFLAGS: -DLIBGIT2_STATIC
#include <git2.h>
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 2
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.2.0"
#if LIBGIT2_VER_MAJOR != 1 || LIBGIT2_VER_MINOR < 2 || LIBGIT2_VER_MINOR > 3
# error "Invalid libgit2 version; this git2go supports libgit2 between v1.2.0 and v1.3.0"
#endif
*/
import "C"

View File

@ -2,6 +2,10 @@ TEST_ARGS ?= --count=1
default: test
generate: static-build/install/lib/libgit2.a
go generate --tags "static" ./...
# System library
# ==============
# This uses whatever version of libgit2 can be found in the system.

View File

@ -1,6 +1,6 @@
git2go
======
[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go) [![Build Status](https://travis-ci.org/libgit2/git2go.svg?branch=main)](https://travis-ci.org/libgit2/git2go)
[![GoDoc](https://godoc.org/github.com/libgit2/git2go?status.svg)](http://godoc.org/github.com/libgit2/git2go/v32) [![Build Status](https://travis-ci.org/libgit2/git2go.svg?branch=main)](https://travis-ci.org/libgit2/git2go)
Go bindings for [libgit2](http://libgit2.github.com/).
@ -78,7 +78,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/v32 ../../libgit2/git2go
replace github.com/libgit2/git2go/v32 => ../../libgit2/git2go
Parallelism and network operations
----------------------------------

View File

@ -2,6 +2,7 @@ package git
import (
"io/ioutil"
"os"
"testing"
)
@ -70,3 +71,17 @@ func TestCloneWithCallback(t *testing.T) {
}
defer remote.Free()
}
// TestCloneWithExternalHTTPUrl
func TestCloneWithExternalHTTPUrl(t *testing.T) {
path, err := ioutil.TempDir("", "git2go")
defer os.RemoveAll(path)
// clone the repo
url := "https://github.com/libgit2/TestGitRepository"
_, err = Clone(url, path, &CloneOptions{})
if err != nil {
t.Fatal("cannot clone remote repo via https, error: ", err)
}
}

2
git.go
View File

@ -14,6 +14,7 @@ import (
"unsafe"
)
//go:generate stringer -type ErrorClass -trimprefix ErrorClass -tags static
type ErrorClass int
const (
@ -48,6 +49,7 @@ const (
ErrorClassPatch ErrorClass = C.GIT_ERROR_PATCH
)
//go:generate stringer -type ErrorCode -trimprefix ErrorCode -tags static
type ErrorCode int
const (

View File

@ -318,7 +318,7 @@ func (r *Repository) InitRebase(branch *AnnotatedCommit, upstream *AnnotatedComm
return nil, MakeGitError(ret)
}
return newRebaseFromC(ptr, cOpts), nil
return newRebaseFromC(ptr, r, cOpts), nil
}
// OpenRebase opens an existing rebase that was previously started by either an invocation of InitRebase or by another client.
@ -340,7 +340,7 @@ func (r *Repository) OpenRebase(opts *RebaseOptions) (*Rebase, error) {
return nil, MakeGitError(ret)
}
return newRebaseFromC(ptr, cOpts), nil
return newRebaseFromC(ptr, r, cOpts), nil
}
// OperationAt gets the rebase operation specified by the given index.
@ -392,6 +392,27 @@ func (rebase *Rebase) Next() (*RebaseOperation, error) {
return newRebaseOperationFromC(ptr), nil
}
// InmemoryIndex gets the index produced by the last operation, which is the
// result of `Next()` and which will be committed by the next invocation of
// `Commit()`. This is useful for resolving conflicts in an in-memory rebase
// before committing them.
//
// This is only applicable for in-memory rebases; for rebases within a working
// directory, the changes were applied to the repository's index.
func (rebase *Rebase) InmemoryIndex() (*Index, error) {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
var ptr *C.git_index
err := C.git_rebase_inmemory_index(&ptr, rebase.ptr)
runtime.KeepAlive(rebase)
if err < 0 {
return nil, MakeGitError(err)
}
return newIndexFromC(ptr, rebase.r), nil
}
// Commit commits the current patch.
// You must have resolved any conflicts that were introduced during the patch application from the Next() invocation.
func (rebase *Rebase) Commit(ID *Oid, author, committer *Signature, message string) error {
@ -457,8 +478,8 @@ func (r *Rebase) Free() {
freeRebaseOptions(r.options)
}
func newRebaseFromC(ptr *C.git_rebase, opts *C.git_rebase_options) *Rebase {
rebase := &Rebase{ptr: ptr, options: opts}
func newRebaseFromC(ptr *C.git_rebase, repo *Repository, opts *C.git_rebase_options) *Rebase {
rebase := &Rebase{ptr: ptr, r: repo, options: opts}
runtime.SetFinalizer(rebase, (*Rebase).Free)
return rebase
}

View File

@ -14,6 +14,80 @@ import (
// Tests
func TestRebaseInMemoryWithConflict(t *testing.T) {
repo := createTestRepo(t)
defer cleanupTestRepo(t, repo)
seedTestRepo(t, repo)
// Create two branches with common history, where both modify "common-file"
// in a conflicting way.
_, err := commitSomething(repo, "common-file", "a\nb\nc\n", commitOptions{})
checkFatal(t, err)
checkFatal(t, createBranch(repo, "branch-a"))
checkFatal(t, createBranch(repo, "branch-b"))
checkFatal(t, repo.SetHead("refs/heads/branch-a"))
_, err = commitSomething(repo, "common-file", "1\nb\nc\n", commitOptions{})
checkFatal(t, err)
checkFatal(t, repo.SetHead("refs/heads/branch-b"))
_, err = commitSomething(repo, "common-file", "x\nb\nc\n", commitOptions{})
checkFatal(t, err)
branchA, err := repo.LookupBranch("branch-a", BranchLocal)
checkFatal(t, err)
onto, err := repo.AnnotatedCommitFromRef(branchA.Reference)
checkFatal(t, err)
// We then rebase "branch-b" onto "branch-a" in-memory, which should result
// in a conflict.
rebase, err := repo.InitRebase(nil, nil, onto, &RebaseOptions{InMemory: 1})
checkFatal(t, err)
_, err = rebase.Next()
checkFatal(t, err)
index, err := rebase.InmemoryIndex()
checkFatal(t, err)
// We simply resolve the conflict and commit the rebase.
if !index.HasConflicts() {
t.Fatal("expected index to have conflicts")
}
conflict, err := index.Conflict("common-file")
checkFatal(t, err)
resolvedBlobID, err := repo.CreateBlobFromBuffer([]byte("resolved contents"))
checkFatal(t, err)
resolvedEntry := *conflict.Our
resolvedEntry.Id = resolvedBlobID
checkFatal(t, index.Add(&resolvedEntry))
checkFatal(t, index.RemoveConflict("common-file"))
var commitID Oid
checkFatal(t, rebase.Commit(&commitID, signature(), signature(), "rebased message"))
checkFatal(t, rebase.Finish())
// And then assert that we can look up the new merge commit, and that the
// "common-file" has the expected contents.
commit, err := repo.LookupCommit(&commitID)
checkFatal(t, err)
if commit.Message() != "rebased message" {
t.Fatalf("unexpected commit message %q", commit.Message())
}
tree, err := commit.Tree()
checkFatal(t, err)
blob, err := repo.LookupBlob(tree.EntryByName("common-file").Id)
checkFatal(t, err)
if string(blob.Contents()) != "resolved contents" {
t.Fatalf("unexpected resolved blob contents %q", string(blob.Contents()))
}
}
func TestRebaseAbort(t *testing.T) {
// TEST DATA

149
refspec.go Normal file
View File

@ -0,0 +1,149 @@
package git
/*
#include <git2.h>
*/
import "C"
import (
"runtime"
"unsafe"
)
type Refspec struct {
doNotCompare
ptr *C.git_refspec
}
// ParseRefspec parses a given refspec string
func ParseRefspec(input string, isFetch bool) (*Refspec, error) {
var ptr *C.git_refspec
cinput := C.CString(input)
defer C.free(unsafe.Pointer(cinput))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_refspec_parse(&ptr, cinput, cbool(isFetch))
if ret < 0 {
return nil, MakeGitError(ret)
}
spec := &Refspec{ptr: ptr}
runtime.SetFinalizer(spec, (*Refspec).Free)
return spec, nil
}
// Free releases a refspec object which has been created by ParseRefspec
func (s *Refspec) Free() {
runtime.SetFinalizer(s, nil)
C.git_refspec_free(s.ptr)
}
// Direction returns the refspec's direction
func (s *Refspec) Direction() ConnectDirection {
direction := C.git_refspec_direction(s.ptr)
return ConnectDirection(direction)
}
// Src returns the refspec's source specifier
func (s *Refspec) Src() string {
var ret string
cstr := C.git_refspec_src(s.ptr)
if cstr != nil {
ret = C.GoString(cstr)
}
runtime.KeepAlive(s)
return ret
}
// Dst returns the refspec's destination specifier
func (s *Refspec) Dst() string {
var ret string
cstr := C.git_refspec_dst(s.ptr)
if cstr != nil {
ret = C.GoString(cstr)
}
runtime.KeepAlive(s)
return ret
}
// Force returns the refspec's force-update setting
func (s *Refspec) Force() bool {
force := C.git_refspec_force(s.ptr)
return force != 0
}
// String returns the refspec's string representation
func (s *Refspec) String() string {
var ret string
cstr := C.git_refspec_string(s.ptr)
if cstr != nil {
ret = C.GoString(cstr)
}
runtime.KeepAlive(s)
return ret
}
// SrcMatches checks if a refspec's source descriptor matches a reference
func (s *Refspec) SrcMatches(refname string) bool {
cname := C.CString(refname)
defer C.free(unsafe.Pointer(cname))
matches := C.git_refspec_src_matches(s.ptr, cname)
return matches != 0
}
// SrcMatches checks if a refspec's destination descriptor matches a reference
func (s *Refspec) DstMatches(refname string) bool {
cname := C.CString(refname)
defer C.free(unsafe.Pointer(cname))
matches := C.git_refspec_dst_matches(s.ptr, cname)
return matches != 0
}
// Transform a reference to its target following the refspec's rules
func (s *Refspec) Transform(refname string) (string, error) {
buf := C.git_buf{}
cname := C.CString(refname)
defer C.free(unsafe.Pointer(cname))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_refspec_transform(&buf, s.ptr, cname)
if ret < 0 {
return "", MakeGitError(ret)
}
defer C.git_buf_dispose(&buf)
return C.GoString(buf.ptr), nil
}
// Rtransform converts a target reference to its source reference following the
// refspec's rules
func (s *Refspec) Rtransform(refname string) (string, error) {
buf := C.git_buf{}
cname := C.CString(refname)
defer C.free(unsafe.Pointer(cname))
runtime.LockOSThread()
defer runtime.UnlockOSThread()
ret := C.git_refspec_rtransform(&buf, s.ptr, cname)
if ret < 0 {
return "", MakeGitError(ret)
}
defer C.git_buf_dispose(&buf)
return C.GoString(buf.ptr), nil
}

75
refspec_test.go Normal file
View File

@ -0,0 +1,75 @@
package git
import (
"testing"
)
func TestRefspec(t *testing.T) {
t.Parallel()
const (
input = "+refs/heads/*:refs/remotes/origin/*"
mainLocal = "refs/heads/main"
mainRemote = "refs/remotes/origin/main"
)
refspec, err := ParseRefspec(input, true)
checkFatal(t, err)
// Accessors
s := refspec.String()
if s != input {
t.Errorf("expected string %q, got %q", input, s)
}
if d := refspec.Direction(); d != ConnectDirectionFetch {
t.Errorf("expected fetch refspec, got direction %v", d)
}
if pat, expected := refspec.Src(), "refs/heads/*"; pat != expected {
t.Errorf("expected refspec src %q, got %q", expected, pat)
}
if pat, expected := refspec.Dst(), "refs/remotes/origin/*"; pat != expected {
t.Errorf("expected refspec dst %q, got %q", expected, pat)
}
if !refspec.Force() {
t.Error("expected refspec force flag")
}
// SrcMatches
if !refspec.SrcMatches(mainLocal) {
t.Errorf("refspec source did not match %q", mainLocal)
}
if refspec.SrcMatches("refs/tags/v1.0") {
t.Error("refspec source matched under refs/tags")
}
// DstMatches
if !refspec.DstMatches(mainRemote) {
t.Errorf("refspec destination did not match %q", mainRemote)
}
if refspec.DstMatches("refs/tags/v1.0") {
t.Error("refspec destination matched under refs/tags")
}
// Transforms
fromLocal, err := refspec.Transform(mainLocal)
checkFatal(t, err)
if fromLocal != mainRemote {
t.Errorf("transform by refspec returned %s; expected %s", fromLocal, mainRemote)
}
fromRemote, err := refspec.Rtransform(mainRemote)
checkFatal(t, err)
if fromRemote != mainLocal {
t.Errorf("rtransform by refspec returned %s; expected %s", fromRemote, mainLocal)
}
}

View File

@ -182,6 +182,9 @@ type Remote struct {
ptr *C.git_remote
callbacks RemoteCallbacks
repo *Repository
// weak indicates that a remote is a weak pointer and should not be
// freed.
weak bool
}
type remotePointerList struct {
@ -288,6 +291,9 @@ type PushOptions struct {
// Headers are extra headers for the push operation.
Headers []string
// Proxy options to use for this push operation
ProxyOptions ProxyOptions
}
type RemoteHead struct {
@ -602,6 +608,9 @@ func (r *Remote) free() {
// Free releases the resources of the Remote.
func (r *Remote) Free() {
r.repo.Remotes.untrackRemote(r)
if r.weak {
return
}
r.free()
}
@ -995,6 +1004,7 @@ func populatePushOptions(copts *C.git_push_options, opts *PushOptions, errorTarg
strings: makeCStringsFromStrings(opts.Headers),
}
populateRemoteCallbacks(&copts.callbacks, &opts.RemoteCallbacks, errorTarget)
populateProxyOptions(&copts.proxy_opts, &opts.ProxyOptions)
return copts
}
@ -1004,6 +1014,7 @@ func freePushOptions(copts *C.git_push_options) {
}
untrackCallbacksPayload(&copts.callbacks)
freeStrarray(&copts.custom_headers)
freeProxyOptions(&copts.proxy_opts)
}
// Fetch performs a fetch operation. refspecs specifies which refspecs
@ -1231,3 +1242,12 @@ func freeRemoteCreateOptions(ptr *C.git_remote_create_options) {
C.free(unsafe.Pointer(ptr.name))
C.free(unsafe.Pointer(ptr.fetchspec))
}
// createNewEmptyRemote used to get a new empty object of *Remote
func createNewEmptyRemote() *Remote {
return &Remote{
callbacks: RemoteCallbacks{},
repo: nil,
weak: false,
}
}

View File

@ -101,6 +101,14 @@ func EnableStrictHashVerification(enabled bool) error {
}
}
func EnableFsyncGitDir(enabled bool) error {
if enabled {
return setSizet(C.GIT_OPT_ENABLE_FSYNC_GITDIR, 1)
} else {
return setSizet(C.GIT_OPT_ENABLE_FSYNC_GITDIR, 0)
}
}
func CachedMemory() (current int, allowed int, err error) {
return getSizetSizet(C.GIT_OPT_GET_CACHED_MEMORY)
}

View File

@ -65,6 +65,14 @@ func TestEnableStrictHashVerification(t *testing.T) {
checkFatal(t, err)
}
func TestEnableFsyncGitDir(t *testing.T) {
err := EnableFsyncGitDir(false)
checkFatal(t, err)
err = EnableFsyncGitDir(true)
checkFatal(t, err)
}
func TestCachedMemory(t *testing.T) {
current, allowed, err := CachedMemory()
checkFatal(t, err)

12
ssh.go
View File

@ -17,6 +17,7 @@ import (
"net"
"net/url"
"runtime"
"strings"
"unsafe"
"golang.org/x/crypto/ssh"
@ -74,6 +75,13 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
return nil, err
}
// Escape \ and '.
uPath := strings.Replace(u.Path, `\`, `\\`, -1)
uPath = strings.Replace(uPath, `'`, `\'`, -1)
// TODO: Add percentage decode similar to libgit2.
// Refer: https://github.com/libgit2/libgit2/blob/358a60e1b46000ea99ef10b4dd709e92f75ff74b/src/str.c#L455-L481
var cmd string
switch action {
case SmartServiceActionUploadpackLs, SmartServiceActionUploadpack:
@ -83,7 +91,7 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
}
t.Close()
}
cmd = fmt.Sprintf("git-upload-pack %q", u.Path)
cmd = fmt.Sprintf("git-upload-pack '%s'", uPath)
case SmartServiceActionReceivepackLs, SmartServiceActionReceivepack:
if t.currentStream != nil {
@ -92,7 +100,7 @@ func (t *sshSmartSubtransport) Action(urlString string, action SmartServiceActio
}
t.Close()
}
cmd = fmt.Sprintf("git-receive-pack %q", u.Path)
cmd = fmt.Sprintf("git-receive-pack '%s'", uPath)
default:
return nil, fmt.Errorf("unexpected action: %v", action)

View File

@ -22,7 +22,6 @@ void _go_git_setup_smart_subtransport_stream(_go_managed_smart_subtransport_stre
*/
import "C"
import (
"errors"
"fmt"
"io"
"reflect"
@ -306,8 +305,10 @@ func smartTransportCallback(
registeredSmartTransport := pointerHandles.Get(handle).(*RegisteredSmartTransport)
remote, ok := remotePointers.get(owner)
if !ok {
err := errors.New("remote pointer not found")
return setCallbackError(errorMessage, err)
// create a new empty remote and set it
// as a weak pointer, so that control stays in golang
remote = createNewEmptyRemote()
remote.weak = true
}
managed := &managedSmartSubtransport{