func translateGlob(glob string) string {
	var regex bytes.Buffer
	escape := false
	for i := 0; i < len(glob); i++ {
		char := glob[i]
		switch {
		case escape:
			escape = false
			regex.WriteString(regexp.QuoteMeta(string(char)))
		case char == '\\':
			escape = true
		case char == '*':
			regex.WriteString("[^/]*")
		case char == '?':
			regex.WriteString("[^/]")
		case char == '[':
			regex.WriteString(translateBraketExpression(&i, glob))
		default:
			regex.WriteString(regexp.QuoteMeta(string(char)))
		}
	}
	return regex.String()
}
NOTE: This is derived from `fnmatch.translate()` and is similar to
the POSIX function `fnmatch()` with the `FNM_PATHNAME` flag set.
package pathspec
import (
	"bufio"
	"bytes"
	"io"
	"regexp"
	"strings"
)
type GitIgnorePattern struct {
	Regex   string
	Include bool
}
func GitIgnore(content io.Reader, name string) (ignore bool, err error) {
	scanner := bufio.NewScanner(content)
	for scanner.Scan() {
		pattern := strings.TrimSpace(scanner.Text())
		if len(pattern) == 0 || pattern[0] == '#' {
			continue
		}
		p := parsePattern(pattern)
		match, err := regexp.MatchString(p.Regex, name)
		if err != nil {
			return ignore, err
		}
		if match {
			if p.Include {
				return false, scanner.Err()
			}
			ignore = true
		}
	}
	return ignore, scanner.Err()
}
func parsePattern(pattern string) *GitIgnorePattern {
	p := &GitIgnorePattern{}
	if strings.HasPrefix(pattern, "!") {
		pattern = pattern[1:]
		p.Include = true
	} else {
		p.Include = false
	}
	if strings.HasPrefix(pattern, "\\") {
		pattern = pattern[1:]
	}
	pattern_segs := strings.Split(pattern, "/")
	if pattern_segs[0] == "" {
		pattern_segs = pattern_segs[1:]
	} else if pattern_segs[0] != "**" {
		pattern_segs = append([]string{"**"}, pattern_segs...)
	}
	if pattern_segs[len(pattern_segs)-1] == "" {
		pattern_segs[len(pattern_segs)-1] = "**"
	}
	var expr bytes.Buffer
	expr.WriteString("^")
	need_slash := false
	for i, seg := range pattern_segs {
		switch seg {
		case "**":
			switch {
			case i == 0 && i == len(pattern_segs)-1:
				expr.WriteString(".+")
			case i == 0:
				expr.WriteString("(?:.+/)?")
				need_slash = false
			case i == len(pattern_segs)-1:
				expr.WriteString("/.+")
			default:
				expr.WriteString("(?:/.+)?")
				need_slash = true
			}
		case "*":
			if need_slash {
				expr.WriteString("/")
			}
			expr.WriteString("[^/]+")
			need_slash = true
		default:
			if need_slash {
				expr.WriteString("/")
			}
			expr.WriteString(translateGlob(seg))
			need_slash = true
		}
	}
	expr.WriteString("$")
	p.Regex = expr.String()
	return p
}