Search code examples
windowsgitbatch-fileparameter-passinggitattributes

properly setting a git filter and passing parameters to it in Windows


I need to set a git filter with an executable file and a long list of parameters under Windows.

The executable is jq.exe the parameters I need to pass to it are --indent 1 "(.cells[] | select(has(\"outputs\")) | .outputs) = [] | (.cells[] | select(has(\"execution_count\")) | .execution_count) = null | .metadata = {\"language_info\": {\"name\": \"python\", \"pygments_lexer\": \"ipython3\"}} | .cells[].metadata = {}"

I have tried two ways to have git filter to invoke this long command. None of them has worked.


  1. I wrote a small bat file nbstrip.bat that contains the full invocation. I have put this bat file in the path. And I have set the filter git config --global --add filter.nbstrip.clean "cmd /c nbstrip"

    When I invoke this filter indirectly with a git add test.nb, git gets apparently "confused" and kinda interprets the output of the filter as new commands and tries to execute them.

    what is the correct way to set a window bat file as command in a git filter?


  1. I put all the parameters in a auxiliary file in %appdata% in order to simplify the command invocation. This way git config --global --add filter.nbstrip.clean "jq --indent 1 --from-file %appdata%\nbstrip.jq.txt".

    When I invoke this filter indirectly with a git add test.nb, the jq executable does not receive the correct filename, and complains with a error message jq.exe: Could not open C:UsersAdminAppDataRoamingnbstrip.jq.txt: No such file or directory as if it had all the backslashes removed before the name be passed to the executable.

    What is the correct way to have parms with backslashes in a git filter command specification?


Note that:

  • In both cases I have tried the command invocation directly in the command line and they work perfectly
  • there is no issue with the git filter definition in .gitattributes nor in the git config, they are correctly setup: if instead of invoking my command I set a simple log it works perfectly.

Do you have any additional strategy that could solve this situation?


Solution

  • These commands are passed to the shell (that is, Bash or Busybox sh), not cmd, so you need to write them in a way that's suitable for a Unix shell. In addition, the Bash version included with Git for Windows has some odd behavior with arguments starting with slash: it considers them Unix paths, and rewrites them as Windows paths unless they start with an additional slash (see this answer for more details).

    You should write your cmd /c nbstrip as cmd //c nbstrip so that it doesn't interpret the "/c" as a "c:\". You could also rewrite your batch script as a shell script and invoke it directly.

    In the second case, the shell treats backslashes as escape characters, so you need to quote it. Additionally, since it's being passed to the shell, you'd want to use a shell form of the environment variable. So you'd write it as jq --indent 1 --from-file "$appdata/nbstrip.jq.txt". Since this has double quotes in it, if you're invoking it from Git Bash, you'll need to write git config --global --add filter.nbstrip.clean 'jq --indent 1 --from-file "$appdata/nbstrip.jq.txt"'.

    Note that the above assumes that appdata refers to a globally accessible environment variable, and not one created explicitly by cmd or PowerShell. If it is in fact specific to those environments, you may need to use a different environment variable or technique to find the location.

    Git uses the Unix shell even on Windows since it was designed for Unix and having different command behavior on different systems would be undesirable. For example, if it used cmd on Windows, you wouldn't be able to share a .gitconfig or other configuration across systems due to incompatible behavior.