lfs,git: send refspec in batch api calls from smudge filter
This commit is contained in:
parent
0855165dc8
commit
8c1ad56924
101
git/refs.go
Normal file
101
git/refs.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package git
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/rubyist/tracerx"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RefUpdate struct {
|
||||||
|
git Env
|
||||||
|
remote string
|
||||||
|
left *Ref
|
||||||
|
right *Ref
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRefUpdate(g Env, remote string, l, r *Ref) *RefUpdate {
|
||||||
|
return &RefUpdate{
|
||||||
|
git: g,
|
||||||
|
remote: remote,
|
||||||
|
left: l,
|
||||||
|
right: r,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *RefUpdate) Left() *Ref {
|
||||||
|
return u.left
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *RefUpdate) LeftCommitish() string {
|
||||||
|
return refCommitish(u.Left())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *RefUpdate) Right() *Ref {
|
||||||
|
if u.right == nil {
|
||||||
|
u.right = defaultRemoteRef(u.git, u.remote, u.Left())
|
||||||
|
}
|
||||||
|
return u.right
|
||||||
|
}
|
||||||
|
|
||||||
|
// defaultRemoteRef returns the remote ref receiving a push based on the current
|
||||||
|
// repository config and local ref being pushed.
|
||||||
|
//
|
||||||
|
// See push.default rules in https://git-scm.com/docs/git-config
|
||||||
|
func defaultRemoteRef(g Env, remote string, left *Ref) *Ref {
|
||||||
|
pushMode, _ := g.Get("push.default")
|
||||||
|
tracerx.Printf("DEBUG %q pushmode = %q", remote, pushMode)
|
||||||
|
switch pushMode {
|
||||||
|
case "", "simple":
|
||||||
|
brRemote, _ := g.Get(fmt.Sprintf("branch.%s.remote", left.Name))
|
||||||
|
if brRemote == remote {
|
||||||
|
// in centralized workflow, work like 'upstream' with an added safety to
|
||||||
|
// refuse to push if the upstream branch’s name is different from the
|
||||||
|
// local one.
|
||||||
|
return trackingRef(g, left)
|
||||||
|
}
|
||||||
|
|
||||||
|
// When pushing to a remote that is different from the remote you normally
|
||||||
|
// pull from, work as current.
|
||||||
|
return left
|
||||||
|
case "upstream", "tracking":
|
||||||
|
// push the current branch back to the branch whose changes are usually
|
||||||
|
// integrated into the current branch
|
||||||
|
return trackingRef(g, left)
|
||||||
|
case "current":
|
||||||
|
// push the current branch to update a branch with the same name on the
|
||||||
|
// receiving end.
|
||||||
|
return left
|
||||||
|
default:
|
||||||
|
tracerx.Printf("WARNING: %q push mode not supported", pushMode)
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func trackingRef(g Env, left *Ref) *Ref {
|
||||||
|
if merge, ok := g.Get(fmt.Sprintf("branch.%s.merge", left.Name)); ok {
|
||||||
|
tracerx.Printf("DEBUG %q branch merge %q", left.Name, merge)
|
||||||
|
return ParseRef(merge, "")
|
||||||
|
}
|
||||||
|
tracerx.Printf("DEBUG %q branch merge default %+v", left.Name, left)
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *RefUpdate) RightCommitish() string {
|
||||||
|
return refCommitish(u.Right())
|
||||||
|
}
|
||||||
|
|
||||||
|
func refCommitish(r *Ref) string {
|
||||||
|
if len(r.Sha) > 0 {
|
||||||
|
return r.Sha
|
||||||
|
}
|
||||||
|
return r.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy of env
|
||||||
|
type Env interface {
|
||||||
|
Get(key string) (val string, ok bool)
|
||||||
|
GetAll(key string) (vals []string)
|
||||||
|
Bool(key string, def bool) (val bool)
|
||||||
|
Int(key string, def int) (val int)
|
||||||
|
All() map[string][]string
|
||||||
|
}
|
@ -3,6 +3,7 @@ package lfs
|
|||||||
import (
|
import (
|
||||||
"github.com/git-lfs/git-lfs/config"
|
"github.com/git-lfs/git-lfs/config"
|
||||||
"github.com/git-lfs/git-lfs/fs"
|
"github.com/git-lfs/git-lfs/fs"
|
||||||
|
"github.com/git-lfs/git-lfs/git"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitFilter provides clean and smudge capabilities
|
// GitFilter provides clean and smudge capabilities
|
||||||
@ -19,3 +20,7 @@ func NewGitFilter(cfg *config.Configuration) *GitFilter {
|
|||||||
func (f *GitFilter) ObjectPath(oid string) (string, error) {
|
func (f *GitFilter) ObjectPath(oid string) (string, error) {
|
||||||
return f.fs.ObjectPath(oid)
|
return f.fs.ObjectPath(oid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *GitFilter) RemoteRef() *git.Ref {
|
||||||
|
return git.NewRefUpdate(f.cfg.Git, f.cfg.PushRemote(), f.cfg.CurrentRef(), nil).Right()
|
||||||
|
}
|
||||||
|
@ -80,7 +80,10 @@ func (f *GitFilter) downloadFile(writer io.Writer, ptr *Pointer, workingfile, me
|
|||||||
// Either way, forward it into the *tq.TransferQueue so that updates are
|
// Either way, forward it into the *tq.TransferQueue so that updates are
|
||||||
// sent over correctly.
|
// sent over correctly.
|
||||||
|
|
||||||
q := tq.NewTransferQueue(tq.Download, manifest, f.cfg.Remote(), tq.WithProgressCallback(cb))
|
q := tq.NewTransferQueue(tq.Download, manifest, f.cfg.Remote(),
|
||||||
|
tq.WithProgressCallback(cb),
|
||||||
|
tq.RemoteRef(f.RemoteRef()),
|
||||||
|
)
|
||||||
q.Add(filepath.Base(workingfile), mediafile, ptr.Oid, ptr.Size)
|
q.Add(filepath.Base(workingfile), mediafile, ptr.Oid, ptr.Size)
|
||||||
q.Wait()
|
q.Wait()
|
||||||
|
|
||||||
|
88
test/test-fetch-refspec.sh
Executable file
88
test/test-fetch-refspec.sh
Executable file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
. "test/testlib.sh"
|
||||||
|
|
||||||
|
begin_test "fetch with good ref"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="fetch-master-branch-required"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
# $ echo "a" | shasum -a 256
|
||||||
|
oid="87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
assert_server_object "$reponame" "$oid" "refs/heads/master"
|
||||||
|
|
||||||
|
rm -rf .git/lfs/objects
|
||||||
|
git lfs fetch --all
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "fetch with tracked ref"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="fetch-tracked-branch-required"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
git push origin master:tracked
|
||||||
|
|
||||||
|
# $ echo "a" | shasum -a 256
|
||||||
|
oid="87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
assert_server_object "$reponame" "$oid" "refs/heads/tracked"
|
||||||
|
|
||||||
|
rm -rf .git/lfs/objects
|
||||||
|
git config push.default upstream
|
||||||
|
git config branch.master.merge refs/heads/tracked
|
||||||
|
git lfs fetch --all
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "fetch with bad ref"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="fetch-other-branch-required"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
git push origin master:other
|
||||||
|
|
||||||
|
# $ echo "a" | shasum -a 256
|
||||||
|
oid="87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
assert_server_object "$reponame" "$oid" "refs/heads/other"
|
||||||
|
|
||||||
|
rm -rf .git/lfs/objects
|
||||||
|
GIT_CURL_VERBOSE=1 git lfs fetch --all 2>&1 | tee fetch.log
|
||||||
|
if [ "0" -eq "${PIPESTATUS[0]}" ]; then
|
||||||
|
echo >&2 "fatal: expected 'git lfs fetch' to fail"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep 'Expected ref "refs/heads/other", got "refs/heads/master"' fetch.log
|
||||||
|
)
|
||||||
|
end_test
|
@ -93,6 +93,62 @@ begin_test "happy path on non-origin remote"
|
|||||||
)
|
)
|
||||||
end_test
|
end_test
|
||||||
|
|
||||||
|
begin_test "happy path on good ref"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="happy-path-master-branch-required"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
git push origin master
|
||||||
|
|
||||||
|
# $ echo "a" | shasum -a 256
|
||||||
|
oid="87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
assert_server_object "$reponame" "$oid" "refs/heads/master"
|
||||||
|
|
||||||
|
clone_repo "$reponame" "$reponame-clone"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
|
begin_test "happy path on tracked ref"
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
|
||||||
|
reponame="happy-path-tracked-branch-required"
|
||||||
|
setup_remote_repo "$reponame"
|
||||||
|
clone_repo "$reponame" "$reponame"
|
||||||
|
|
||||||
|
git lfs track "*.dat"
|
||||||
|
echo "a" > a.dat
|
||||||
|
git add .gitattributes a.dat
|
||||||
|
git commit -m "add a.dat"
|
||||||
|
|
||||||
|
git push origin master:tracked
|
||||||
|
|
||||||
|
# $ echo "a" | shasum -a 256
|
||||||
|
oid="87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7"
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
assert_server_object "$reponame" "$oid" "refs/heads/tracked"
|
||||||
|
|
||||||
|
git lfs clone "$GITSERVER/$reponame" --exclude "*"
|
||||||
|
|
||||||
|
git config credential.helper lfstest
|
||||||
|
git config push.default upstream
|
||||||
|
git config branch.master.merge refs/heads/tracked
|
||||||
|
|
||||||
|
git checkout
|
||||||
|
assert_local_object "$oid" 2
|
||||||
|
)
|
||||||
|
end_test
|
||||||
|
|
||||||
begin_test "clears local temp objects"
|
begin_test "clears local temp objects"
|
||||||
(
|
(
|
||||||
set -e
|
set -e
|
||||||
|
Loading…
Reference in New Issue
Block a user