From 5af2ba3cc9420011749a039456a0eae3d0dff9df Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Mon, 24 Apr 2017 09:22:33 -0600 Subject: [PATCH] commands/track: teach --no-modify-attrs --- commands/command_track.go | 98 ++++++++++++++++++++--------------- docs/man/git-lfs-track.1.ronn | 4 ++ test/test-track.sh | 31 +++++++++++ 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/commands/command_track.go b/commands/command_track.go index de37012b..adea86f4 100644 --- a/commands/command_track.go +++ b/commands/command_track.go @@ -26,6 +26,7 @@ var ( trackNotLockableFlag bool trackVerboseLoggingFlag bool trackDryRunFlag bool + trackNoModifyAttrsFlag bool ) func trackCommand(cmd *cobra.Command, args []string) { @@ -66,13 +67,15 @@ func trackCommand(cmd *cobra.Command, args []string) { ArgsLoop: for _, unsanitizedPattern := range args { pattern := cleanRootPath(unsanitizedPattern) - for _, known := range knownPatterns { - if known.Path == filepath.Join(relpath, pattern) && - ((trackLockableFlag && known.Lockable) || // enabling lockable & already lockable (no change) - (trackNotLockableFlag && !known.Lockable) || // disabling lockable & not lockable (no change) - (!trackLockableFlag && !trackNotLockableFlag)) { // leave lockable as-is in all cases - Print("%q already supported", pattern) - continue ArgsLoop + if !trackNoModifyAttrsFlag { + for _, known := range knownPatterns { + if known.Path == filepath.Join(relpath, pattern) && + ((trackLockableFlag && known.Lockable) || // enabling lockable & already lockable (no change) + (trackNotLockableFlag && !known.Lockable) || // disabling lockable & not lockable (no change) + (!trackLockableFlag && !trackNotLockableFlag)) { // leave lockable as-is in all cases + Print("%q already supported", pattern) + continue ArgsLoop + } } } @@ -98,49 +101,57 @@ ArgsLoop: // replacing any lines where the values have changed, and appending new lines // change this: - attribContents, err := ioutil.ReadFile(".gitattributes") - // it's fine for file to not exist - if err != nil && !os.IsNotExist(err) { - Print("Error reading .gitattributes file") - return - } - // Re-generate the file with merge of old contents and new (to deal with changes) - attributesFile, err := os.OpenFile(".gitattributes", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0660) - if err != nil { - Print("Error opening .gitattributes file") - return - } - defer attributesFile.Close() - - if len(attribContents) > 0 { - scanner := bufio.NewScanner(bytes.NewReader(attribContents)) - for scanner.Scan() { - line := scanner.Text() - fields := strings.Fields(line) - if len(fields) < 1 { - continue - } - - pattern := fields[0] - if newline, ok := changedAttribLines[pattern]; ok { - // Replace this line (newline already embedded) - attributesFile.WriteString(newline) - // Remove from map so we know we don't have to add it to the end - delete(changedAttribLines, pattern) - } else { - // Write line unchanged (replace newline) - attributesFile.WriteString(line + lineEnd) - } + var ( + attribContents []byte + attributesFile *os.File + ) + if !trackNoModifyAttrsFlag { + attribContents, err = ioutil.ReadFile(".gitattributes") + // it's fine for file to not exist + if err != nil && !os.IsNotExist(err) { + Print("Error reading .gitattributes file") + return } + // Re-generate the file with merge of old contents and new (to deal with changes) + attributesFile, err = os.OpenFile(".gitattributes", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0660) + if err != nil { + Print("Error opening .gitattributes file") + return + } + defer attributesFile.Close() - // Our method of writing also made sure there's always a newline at end + if len(attribContents) > 0 { + scanner := bufio.NewScanner(bytes.NewReader(attribContents)) + for scanner.Scan() { + line := scanner.Text() + fields := strings.Fields(line) + if len(fields) < 1 { + continue + } + + pattern := fields[0] + if newline, ok := changedAttribLines[pattern]; ok { + // Replace this line (newline already embedded) + attributesFile.WriteString(newline) + // Remove from map so we know we don't have to add it to the end + delete(changedAttribLines, pattern) + } else { + // Write line unchanged (replace newline) + attributesFile.WriteString(line + lineEnd) + } + } + + // Our method of writing also made sure there's always a newline at end + } } // Any items left in the map, write new lines at the end of the file // Note this is only new patterns, not ones which changed locking flags for pattern, newline := range changedAttribLines { - // Newline already embedded - attributesFile.WriteString(newline) + if !trackNoModifyAttrsFlag { + // Newline already embedded + attributesFile.WriteString(newline) + } // Also, for any new patterns we've added, make sure any existing git // tracked files have their timestamp updated so they will now show as @@ -272,5 +283,6 @@ func init() { cmd.Flags().BoolVarP(&trackNotLockableFlag, "not-lockable", "", false, "remove lockable attribute from pattern") cmd.Flags().BoolVarP(&trackVerboseLoggingFlag, "verbose", "v", false, "log which files are being tracked and modified") 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") }) } diff --git a/docs/man/git-lfs-track.1.ronn b/docs/man/git-lfs-track.1.ronn index dc4a8d9f..fa88161a 100644 --- a/docs/man/git-lfs-track.1.ronn +++ b/docs/man/git-lfs-track.1.ronn @@ -39,6 +39,10 @@ to match paths. Remove the lockable flag from the paths so they are no longer read-only unless locked. +* `--no-modify-attrs` + Makes matched entries stat-dirty so that Git can re-index files you wish to + convert to LFS. Does not modify any `.gitattributes` file(s). + ## EXAMPLES * List the patterns that Git LFS is currently tracking: diff --git a/test/test-track.sh b/test/test-track.sh index 4dd2a24e..c2c5d635 100755 --- a/test/test-track.sh +++ b/test/test-track.sh @@ -463,3 +463,34 @@ begin_test "track escaped pattern" assert_attributes_count "\\#" "filter=lfs" 1 ) end_test + +begin_test "track (--no-modify-attrs)" +( + set -e + + reponame="track-no-modify-attrs" + git init "$reponame" + cd "$reponame" + + echo "contents" > a.dat + git add a.dat + + # Git assumes that identical results from `stat(1)` between the index and + # working copy are stat dirty. To prevent this, wait at least one second to + # yield different `stat(1)` results. + sleep 1 + + git commit -m "add a.dat" + + echo "*.dat filter=lfs diff=lfs merge=lfs -text" > .gitattributes + + git add .gitattributes + git commit -m "asdf" + + [ -z "$(git status --porcelain)" ] + + git lfs track --no-modify-attrs "*.dat" + + [ " M a.dat" = "$(git status --porcelain)" ] +) +end_test