diff --git a/README.md b/README.md index 8bc3c65b..07716375 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,9 @@ setup and preferences. In addition, [binary packages](https://github.com/git-lfs/git-lfs/releases) are available for Linux, macOS, Windows, and FreeBSD. This repository can also be -built-from-source using the latest version of [Go](https://golang.org). +built from source using the latest version of [Go](https://golang.org), and the +available instructions in our +[Wiki](https://github.com/git-lfs/git-lfs/wiki/Installation#source). ### Usage diff --git a/commands/command_track.go b/commands/command_track.go index 5ba06925..8d160dcb 100644 --- a/commands/command_track.go +++ b/commands/command_track.go @@ -49,6 +49,8 @@ func trackCommand(cmd *cobra.Command, args []string) { return } + // Intentionally do _not_ consider global- and system-level + // .gitattributes here. knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir()) lineEnd := getAttributeLineEnding(knownPatterns) if len(lineEnd) == 0 { @@ -213,7 +215,7 @@ ArgsLoop: } func listPatterns() { - knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir()) + knownPatterns := getAllKnownPatterns() if len(knownPatterns) < 1 { return } @@ -228,6 +230,14 @@ func listPatterns() { } } +func getAllKnownPatterns() []git.AttributePath { + knownPatterns := git.GetAttributePaths(cfg.LocalWorkingDir(), cfg.LocalGitDir()) + knownPatterns = append(knownPatterns, git.GetRootAttributePaths(cfg.Git)...) + knownPatterns = append(knownPatterns, git.GetSystemAttributePaths(cfg.Os)...) + + return knownPatterns +} + func getAttributeLineEnding(attribs []git.AttributePath) string { for _, a := range attribs { if a.Source.Path == ".gitattributes" { diff --git a/docs/man/git-lfs-track.1.ronn b/docs/man/git-lfs-track.1.ronn index 234880e6..41810bca 100644 --- a/docs/man/git-lfs-track.1.ronn +++ b/docs/man/git-lfs-track.1.ronn @@ -59,6 +59,6 @@ to match paths. ## SEE ALSO -git-lfs-untrack(1), git-lfs-install(1), gitattributes(5). +git-lfs-untrack(1), git-lfs-install(1), gitattributes(5), gitignore(5). Part of the git-lfs(1) suite. diff --git a/docs/man/git-lfs.1.ronn b/docs/man/git-lfs.1.ronn index f8c8c96d..1621cfea 100644 --- a/docs/man/git-lfs.1.ronn +++ b/docs/man/git-lfs.1.ronn @@ -85,3 +85,28 @@ commands and low level ("plumbing") commands. Git process filter that converts between large files and pointers. * git-lfs-smudge(1): Git smudge filter that converts pointer in blobs to the actual content. + +## EXAMPLES + +To get started with Git LFS, the following commands can be used. + + 1. Setup Git LFS on your system. You only have to do this once per + repository per machine: + + git lfs install + + 2. Choose the type of files you want to track, for examples all `ISO` + images, with git-lfs-track(1): + + git lfs track "*.iso" + + 3. The above stores this information in gitattributes(5) files, so + that file need to be added to the repository: + + git add .gitattributes + + 3. Commit, push and work with the files normally: + + git add file.iso + git commit -m "Add disk image" + git push diff --git a/git/attribs.go b/git/attribs.go index fb690bf8..6a033b55 100644 --- a/git/attribs.go +++ b/git/attribs.go @@ -35,6 +35,36 @@ func (s *AttributeSource) String() string { return s.Path } +// GetRootAttributePaths beahves as GetRootAttributePaths, and loads information +// only from the global gitattributes file. +func GetRootAttributePaths(cfg Env) []AttributePath { + af, ok := cfg.Get("core.attributesfile") + if !ok { + return nil + } + + // The working directory for the root gitattributes file is blank. + return attrPaths(af, "") +} + +// GetSystemAttributePaths behaves as GetAttributePaths, and loads information +// only from the system gitattributes file, respecting the $PREFIX environment +// variable. +func GetSystemAttributePaths(env Env) []AttributePath { + prefix, _ := env.Get("PREFIX") + if len(prefix) == 0 { + prefix = string(filepath.Separator) + } + + path := filepath.Join(prefix, "etc", "gitattributes") + + if _, err := os.Stat(path); os.IsNotExist(err) { + return nil + } + + return attrPaths(path, "") +} + // GetAttributePaths returns a list of entries in .gitattributes which are // configured with the filter=lfs attribute // workingDir is the root of the working copy @@ -43,58 +73,66 @@ func GetAttributePaths(workingDir, gitDir string) []AttributePath { paths := make([]AttributePath, 0) for _, path := range findAttributeFiles(workingDir, gitDir) { - attributes, err := os.Open(path) - if err != nil { + paths = append(paths, attrPaths(path, workingDir)...) + } + + return paths +} + +func attrPaths(path, workingDir string) []AttributePath { + attributes, err := os.Open(path) + if err != nil { + return nil + } + + var paths []AttributePath + + relfile, _ := filepath.Rel(workingDir, path) + reldir := filepath.Dir(relfile) + source := &AttributeSource{Path: relfile} + + le := &lineEndingSplitter{} + scanner := bufio.NewScanner(attributes) + scanner.Split(le.ScanLines) + + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + + if strings.HasPrefix(line, "#") { continue } - relfile, _ := filepath.Rel(workingDir, path) - reldir := filepath.Dir(relfile) - source := &AttributeSource{Path: relfile} + // Check for filter=lfs (signifying that LFS is tracking + // this file) or "lockable", which indicates that the + // file is lockable (and may or may not be tracked by + // Git LFS). + if strings.Contains(line, "filter=lfs") || + strings.HasSuffix(line, "lockable") { - le := &lineEndingSplitter{} - scanner := bufio.NewScanner(attributes) - scanner.Split(le.ScanLines) - - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - - if strings.HasPrefix(line, "#") { - continue + fields := strings.Fields(line) + pattern := fields[0] + if len(reldir) > 0 { + pattern = filepath.Join(reldir, pattern) } - - // Check for filter=lfs (signifying that LFS is tracking - // this file) or "lockable", which indicates that the - // file is lockable (and may or may not be tracked by - // Git LFS). - if strings.Contains(line, "filter=lfs") || - strings.HasSuffix(line, "lockable") { - - fields := strings.Fields(line) - pattern := fields[0] - if len(reldir) > 0 { - pattern = filepath.Join(reldir, pattern) + // Find lockable flag in any position after pattern to avoid + // edge case of matching "lockable" to a file pattern + lockable := false + for _, f := range fields[1:] { + if f == LockableAttrib { + lockable = true + break } - // Find lockable flag in any position after pattern to avoid - // edge case of matching "lockable" to a file pattern - lockable := false - for _, f := range fields[1:] { - if f == LockableAttrib { - lockable = true - break - } - } - paths = append(paths, AttributePath{ - Path: pattern, - Source: source, - Lockable: lockable, - }) } + paths = append(paths, AttributePath{ + Path: pattern, + Source: source, + Lockable: lockable, + }) } - - source.LineEnding = le.LineEnding() } + source.LineEnding = le.LineEnding() + return paths } diff --git a/lfsapi/proxy.go b/lfsapi/proxy.go index d67f2dcd..c7410774 100644 --- a/lfsapi/proxy.go +++ b/lfsapi/proxy.go @@ -49,13 +49,6 @@ func proxyFromClient(c *Client) func(req *http.Request) (*url.URL, error) { } func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environment) (httpsProxy string, httpProxy string, noProxy string) { - if urlCfg != nil { - httpProxy, _ = urlCfg.Get("http", u.String(), "proxy") - if strings.HasPrefix(httpProxy, "https://") { - httpsProxy = httpProxy - } - } - if osEnv == nil { return } @@ -76,6 +69,16 @@ func getProxyServers(u *url.URL, urlCfg *config.URLConfig, osEnv config.Environm httpProxy, _ = osEnv.Get("http_proxy") } + if urlCfg != nil { + gitProxy, ok := urlCfg.Get("http", u.String(), "proxy") + if len(gitProxy) > 0 && ok { + if strings.HasPrefix(gitProxy, "https://") { + httpsProxy = gitProxy + } + httpProxy = gitProxy + } + } + noProxy, _ = osEnv.Get("NO_PROXY") if len(noProxy) == 0 { noProxy, _ = osEnv.Get("no_proxy") diff --git a/lfsapi/proxy_test.go b/lfsapi/proxy_test.go index ad98419b..e8e7e76a 100644 --- a/lfsapi/proxy_test.go +++ b/lfsapi/proxy_test.go @@ -20,7 +20,7 @@ func TestHttpsProxyFromGitConfig(t *testing.T) { require.Nil(t, err) proxyURL, err := proxyFromClient(c)(req) - assert.Equal(t, "proxy-from-git-config:8080", proxyURL.Host) + assert.Equal(t, "proxy-from-env:8080", proxyURL.Host) assert.Nil(t, err) } diff --git a/test/test-track.sh b/test/test-track.sh index 02ff7ce0..3823a1c7 100755 --- a/test/test-track.sh +++ b/test/test-track.sh @@ -558,3 +558,40 @@ begin_test "track (with current-directory prefix)" grep -e "^a.dat" .gitattributes ) end_test + +begin_test "track (global gitattributes)" +( + set -e + + reponame="track-global-gitattributes" + git init "$reponame" + cd "$reponame" + + global="$(cd .. && pwd)/gitattributes-global" + + echo "*.dat filter=lfs diff=lfs merge=lfs -text" > "$global" + git config --local core.attributesfile "$global" + + git lfs track 2>&1 | tee track.log + grep "*.dat" track.log +) +end_test + +begin_test "track (system gitattributes)" +( + set -e + + reponame="track-system-gitattributes" + git init "$reponame" + cd "$reponame" + + pushd "$TRASHDIR" > /dev/null + mkdir -p "prefix/${reponame}/etc" + cd "prefix/${reponame}/etc" + echo "*.dat filter=lfs diff=lfs merge=lfs -text" > gitattributes + popd > /dev/null + + PREFIX="${TRASHDIR}/prefix/${reponame}" git lfs track 2>&1 | tee track.log + grep "*.dat" track.log +) +end_test