lfs,git: send refspec in batch api calls from smudge filter

This commit is contained in:
rick olson 2018-01-05 15:01:29 -07:00
parent 0855165dc8
commit 8c1ad56924
5 changed files with 254 additions and 1 deletions

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 branchs 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 (
"github.com/git-lfs/git-lfs/config"
"github.com/git-lfs/git-lfs/fs"
"github.com/git-lfs/git-lfs/git"
)
// GitFilter provides clean and smudge capabilities
@ -19,3 +20,7 @@ func NewGitFilter(cfg *config.Configuration) *GitFilter {
func (f *GitFilter) ObjectPath(oid string) (string, error) {
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
// 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.Wait()

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
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"
(
set -e