From fc421da1c176a9d0844a38e6eb2cba154d864069 Mon Sep 17 00:00:00 2001 From: "brian m. carlson" Date: Mon, 5 Aug 2019 20:44:27 +0000 Subject: [PATCH] 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. --- commands/command_track.go | 17 +++++++++++++++++ docs/man/git-lfs-track.1.ronn | 5 +++++ t/t-track.sh | 28 ++++++++++++++++++++++++++++ t/testhelpers.sh | 2 +- 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/commands/command_track.go b/commands/command_track.go index cb46d20b..7c8c7df6 100644 --- a/commands/command_track.go +++ b/commands/command_track.go @@ -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") }) } diff --git a/docs/man/git-lfs-track.1.ronn b/docs/man/git-lfs-track.1.ronn index 70f2cd20..8dbef0dd 100644 --- a/docs/man/git-lfs-track.1.ronn +++ b/docs/man/git-lfs-track.1.ronn @@ -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. diff --git a/t/t-track.sh b/t/t-track.sh index b14be27c..55e353c8 100755 --- a/t/t-track.sh +++ b/t/t-track.sh @@ -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 diff --git a/t/testhelpers.sh b/t/testhelpers.sh index 28210207..62d50c2c 100644 --- a/t/testhelpers.sh +++ b/t/testhelpers.sh @@ -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)