Allow literal local paths as remotes

Currently, we allow literal paths as named remotes, but not specified as
literal remotes on the command line, since they fail to validate as
URLs.  To make this experience better, let's rewrite the local paths as
file URLs using the existing endpoint code if the validation fails and
then try validation again.  We check specifically that users can use "."
as a remote since that's a common idiom to update branches.
This commit is contained in:
brian m. carlson 2020-05-04 21:14:49 +00:00
parent 781f595eec
commit b2d3f1d787
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
4 changed files with 66 additions and 24 deletions

@ -268,7 +268,10 @@ func (c *Configuration) PushRemote() string {
func (c *Configuration) SetValidRemote(name string) error {
if err := git.ValidateRemote(name); err != nil {
return err
name := git.RewriteLocalPathAsURL(name)
if err := git.ValidateRemote(name); err != nil {
return err
}
}
c.SetRemote(name)
return nil
@ -276,7 +279,10 @@ func (c *Configuration) SetValidRemote(name string) error {
func (c *Configuration) SetValidPushRemote(name string) error {
if err := git.ValidateRemote(name); err != nil {
return err
name := git.RewriteLocalPathAsURL(name)
if err := git.ValidateRemote(name); err != nil {
return err
}
}
c.SetPushRemote(name)
return nil

@ -503,6 +503,34 @@ func ValidateRemoteURL(remote string) error {
}
}
func RewriteLocalPathAsURL(path string) string {
var slash string
if abs, err := filepath.Abs(path); err == nil {
// Required for Windows paths to work.
if !strings.HasPrefix(abs, "/") {
slash = "/"
}
path = abs
}
var gitpath string
if filepath.Base(path) == ".git" {
gitpath = path
path = filepath.Dir(path)
} else {
gitpath = filepath.Join(path, ".git")
}
if _, err := os.Stat(gitpath); err == nil {
path = gitpath
} else if _, err := os.Stat(path); err != nil {
// Not a local path. We check down here because we perform
// canonicalization by stripping off the .git above.
return path
}
return fmt.Sprintf("file://%s%s", slash, filepath.ToSlash(path))
}
func UpdateIndexFromStdin() *subprocess.Cmd {
return git("update-index", "-q", "--refresh", "--stdin")
}

@ -3,10 +3,10 @@ package lfshttp
import (
"fmt"
"net/url"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/git-lfs/git-lfs/git"
)
const UrlUnknown = "<unknown>"
@ -109,26 +109,7 @@ func EndpointFromHttpUrl(u *url.URL) Endpoint {
}
func EndpointFromLocalPath(path string) Endpoint {
var slash string
if abs, err := filepath.Abs(path); err == nil {
// Required for Windows paths to work.
if !strings.HasPrefix(abs, "/") {
slash = "/"
}
path = abs
}
var gitpath string
if filepath.Base(path) == ".git" {
gitpath = path
path = filepath.Dir(path)
} else {
gitpath = filepath.Join(path, ".git")
}
if _, err := os.Stat(gitpath); err == nil {
path = gitpath
}
return Endpoint{Url: fmt.Sprintf("file://%s%s", slash, filepath.ToSlash(path))}
return Endpoint{Url: git.RewriteLocalPathAsURL(path)}
}
// Construct a new endpoint from a file URL

@ -1275,3 +1275,30 @@ begin_test "pre-push with force-pushed ref"
git push origin +tagname
)
end_test
begin_test "pre-push with local path"
(
set -e
reponame="pre-push-local-path"
setup_remote_repo "$reponame"
clone_repo "$reponame" "$reponame-2"
cd ..
clone_repo "$reponame" "$reponame"
git lfs track "*.dat"
echo "hi" > a.dat
git add .gitattributes a.dat
git commit -m "add a.dat"
# Push to the other repo.
git push "../$reponame-2" master:foo
# Push to . to make sure that works.
git push "." master:foo
git lfs fsck
cd "../$reponame-2"
git checkout foo
git lfs fsck
)
end_test