code: func loadExcludeFilename(filename, workDir string, excludePaths []filepathfilter.Pattern) ([]filepathfilter.Pattern, error) {
  	f, err := os.OpenFile(filename, os.O_RDONLY, 0644)
  	if err != nil {
  		if os.IsNotExist(err) {
  			return excludePaths, nil
  		}
  		return excludePaths, err
  	}
  	defer f.Close()
  
  	retPaths := excludePaths
  	modified := false
  
  	scanner := bufio.NewScanner(f)
  	for scanner.Scan() {
  		line := strings.TrimSpace(scanner.Text())
  		// Skip blanks, comments and negations (not supported right now)
  		if len(line) == 0 || strings.HasPrefix(line, "#") || strings.HasPrefix(line, "!") {
  			continue
  		}
  
  		if !modified {
  			// copy on write
  			retPaths = make([]filepathfilter.Pattern, len(excludePaths))
  			copy(retPaths, excludePaths)
  			modified = true
  		}
  
  		path := line
  		// Add pattern in context if exclude has separator, or no wildcard
  		// Allow for both styles of separator at this point
  		if strings.ContainsAny(path, "/\\") ||
  			!strings.Contains(path, "*") {
  			path = join(workDir, line)
  		}
  		retPaths = append(retPaths, filepathfilter.NewPattern(path))
  	}
  
  	return retPaths, nil
  }
docs: // loadExcludeFilename reads the given file in gitignore format and returns a
  // revised array of exclude paths if there are any changes.
  // If any changes are made a copy of the array is taken so the original is not
  // modified