track: provide an option to handle paths literally

Normally, the arguments to "git lfs track" are taken as glob patterns.
This is generally useful, but sometimes there are filenames that contain
special characters. Add a "--filename" option that forces arguments to
be taken as literal paths instead of glob patterns to make handling
these files easier.

In the test helpers, pass -F to grep so that our unusual file names
don't trigger undesired pattern matching. This has no effect on other
tests, as they all pass a literal filename here.
This commit is contained in:
brian m. carlson 2019-08-05 20:44:27 +00:00
parent 277940a34e
commit fc421da1c1
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
4 changed files with 51 additions and 1 deletions

@ -27,6 +27,7 @@ var (
trackDryRunFlag bool
trackNoModifyAttrsFlag bool
trackNoExcludedFlag bool
trackFilenameFlag bool
)
func trackCommand(cmd *cobra.Command, args []string) {
@ -95,6 +96,13 @@ ArgsLoop:
lockableArg = " " + git.LockableAttrib
}
if trackFilenameFlag {
// We need to do this after escapeAttrPattern since that
// function turns backslashes into slashes.
encodedArg = escapeGlobCharacters(encodedArg)
pattern = escapeGlobCharacters(pattern)
}
changedAttribLines[pattern] = fmt.Sprintf("%s filter=lfs diff=lfs merge=lfs -text%v%s", encodedArg, lockableArg, lineEnd)
if trackLockableFlag {
@ -290,8 +298,16 @@ var (
" ": "[[:space:]]",
"#": "\\#",
}
trackEscapeStrings = []string{"*", "[", "]", "?"}
)
func escapeGlobCharacters(s string) string {
for _, ch := range trackEscapeStrings {
s = strings.Replace(s, ch, fmt.Sprintf("\\%s", ch), -1)
}
return s
}
func escapeAttrPattern(unescaped string) string {
var escaped string = strings.Replace(unescaped, `\`, "/", -1)
@ -320,5 +336,6 @@ func init() {
cmd.Flags().BoolVarP(&trackDryRunFlag, "dry-run", "d", false, "preview results of running `git lfs track`")
cmd.Flags().BoolVarP(&trackNoModifyAttrsFlag, "no-modify-attrs", "", false, "skip modifying .gitattributes file")
cmd.Flags().BoolVarP(&trackNoExcludedFlag, "no-excluded", "", false, "skip listing excluded paths")
cmd.Flags().BoolVarP(&trackFilenameFlag, "filename", "", false, "treat this pattern as a literal filename")
})
}

@ -31,6 +31,11 @@ to match paths.
Disabled by default.
* `--filename`
Treat the arguments as literal filenames, not as patterns. Any special glob
characters in the filename will be escaped when writing the `.gitattributes`
file.
* `--lockable` `-l`
Make the paths 'lockable', meaning they should be locked to edit them, and
will be made read-only in the working copy when not locked.

@ -653,3 +653,31 @@ begin_test "track: escaped pattern in .gitattributes"
fi
)
end_test
begin_test "track: escaped glob pattern in .gitattributes"
(
set -e
# None of these characters are valid in the Win32 subsystem.
[ "$IS_WINDOWS" -eq 1 ] && exit 0
reponame="track-escaped-glob"
git init "$reponame"
cd "$reponame"
filename='*[foo]bar?.txt'
contents='I need escaping'
contents_oid=$(calc_oid "$contents")
git lfs track --filename "$filename"
git add .
cat .gitattributes
printf "%s" "$contents" > "$filename"
git add .
git commit -m 'Add unusually named file'
# If Git understood our escaping, we'll have a pointer. Otherwise, we won't.
assert_pointer "master" "$filename" "$contents_oid" 15
)
end_test

@ -14,7 +14,7 @@ assert_pointer() {
while read -r -d $'\0' x; do
echo $x
done |
grep "$path" | cut -f 3 -d " ")
grep -F "$path" | cut -f 3 -d " ")
actual=$(git cat-file -p $gitblob)
expected=$(pointer $oid $size)