8 "github.com/git-lfs/git-lfs/subprocess"
9 "github.com/rubyist/tracerx"
14 gitVersionMu sync.Mutex
17 func Version() (string, error) {
19 defer gitVersionMu.Unlock()
21 if gitVersion == nil {
22 v, err := subprocess.SimpleExec("git", "version")
27 return *gitVersion, nil
30 // IsVersionAtLeast returns whether the git version is the one specified or higher
31 // argument is plain version string separated by '.' e.g. "2.3.1" but can omit minor/patch
32 func IsGitVersionAtLeast(ver string) bool {
33 gitver, err := Version()
35 tracerx.Printf("Error getting git version: %v", err)
38 return IsVersionAtLeast(gitver, ver)
41 // IsVersionAtLeast compares 2 version strings (ok to be prefixed with 'git version', ignores)
42 func IsVersionAtLeast(actualVersion, desiredVersion string) bool {
43 // Capture 1-3 version digits, optionally prefixed with 'git version' and possibly
44 // with suffixes which we'll ignore (e.g. unstable builds, MinGW versions)
45 verregex := regexp.MustCompile(`(?:git version\s+)?(\d+)(?:.(\d+))?(?:.(\d+))?.*`)
48 // Support up to 1000 in major/minor/patch digits
49 const majorscale = 1000 * 1000
50 const minorscale = 1000
52 if match := verregex.FindStringSubmatch(desiredVersion); match != nil {
53 // Ignore errors as regex won't match anything other than digits
54 major, _ := strconv.Atoi(match[1])
55 atleast += uint64(major * majorscale)
57 minor, _ := strconv.Atoi(match[2])
58 atleast += uint64(minor * minorscale)
61 patch, _ := strconv.Atoi(match[3])
62 atleast += uint64(patch)
67 if match := verregex.FindStringSubmatch(actualVersion); match != nil {
68 major, _ := strconv.Atoi(match[1])
69 actual += uint64(major * majorscale)
71 minor, _ := strconv.Atoi(match[2])
72 actual += uint64(minor * minorscale)
75 patch, _ := strconv.Atoi(match[3])
76 actual += uint64(patch)
80 return actual >= atleast