diff --git a/go/libraries/doltcore/doltdb/ignore.go b/go/libraries/doltcore/doltdb/ignore.go index 127f855c33..ac3d3cacc6 100644 --- a/go/libraries/doltcore/doltdb/ignore.go +++ b/go/libraries/doltcore/doltdb/ignore.go @@ -110,6 +110,7 @@ func compilePattern(pattern string) (*regexp.Regexp, error) { pattern = "^" + regexp.QuoteMeta(pattern) + "$" pattern = strings.Replace(pattern, "\\?", ".", -1) pattern = strings.Replace(pattern, "\\*", ".*", -1) + pattern = strings.Replace(pattern, "%", ".*", -1) return regexp.Compile(pattern) } @@ -118,12 +119,29 @@ func compilePattern(pattern string) (*regexp.Regexp, error) { // match pattern B, but not vice versa.) func getMoreSpecificPatterns(lessSpecific string) (*regexp.Regexp, error) { pattern := "^" + regexp.QuoteMeta(lessSpecific) + "$" - // A ? can expand to any character except for a *, since that also has special meaning in patterns. - pattern = strings.Replace(pattern, "\\?", "[^\\*]", -1) + // A ? can expand to any character except for a * or %, since that also has special meaning in patterns. + + pattern = strings.Replace(pattern, "\\?", "[^\\*%]", -1) pattern = strings.Replace(pattern, "\\*", ".*", -1) + pattern = strings.Replace(pattern, "%", ".*", -1) return regexp.Compile(pattern) } +// normalizePattern generates an equivalent pattern, such that all equivalent patterns have the same normalized pattern. +// It accomplishes this by replacing all * with %, and removing multiple adjacent %. +// This will get a lot harder to implement once we support escaped characters in patterns. +func normalizePattern(pattern string) string { + pattern = strings.Replace(pattern, "*", "%", -1) + for { + newPattern := strings.Replace(pattern, "%%", "%", -1) + if newPattern == pattern { + break + } + pattern = newPattern + } + return pattern +} + func resolveConflictingPatterns(trueMatches, falseMatches []string, tableName string) (IgnoreResult, error) { trueMatchesToRemove := map[string]struct{}{} falseMatchesToRemove := map[string]struct{}{} @@ -133,6 +151,9 @@ func resolveConflictingPatterns(trueMatches, falseMatches []string, tableName st return ErrorOccurred, err } for _, falseMatch := range falseMatches { + if normalizePattern(trueMatch) == normalizePattern(falseMatch) { + return IgnorePatternConflict, DoltIgnoreConflictError{Table: tableName, TruePatterns: []string{trueMatch}, FalsePatterns: []string{falseMatch}} + } if trueMatchRegExp.MatchString(falseMatch) { trueMatchesToRemove[trueMatch] = struct{}{} } diff --git a/integration-tests/bats/ignore.bats b/integration-tests/bats/ignore.bats index 26f68ccf19..f5a8396d4a 100644 --- a/integration-tests/bats/ignore.bats +++ b/integration-tests/bats/ignore.bats @@ -12,6 +12,8 @@ INSERT INTO dolt_ignore VALUES ("*_ignore", true), ("do_not_ignore", false), + ("%_ignore_too", true), + ("commit_*", false), ("commit_me_not", true), @@ -85,6 +87,7 @@ SQL dolt sql <