I wanted to use a git post-commit hook to perform an action on every file that had been committed. A git command can be used to list files committed (from a question on stackoverflow):
git diff-tree -r --name-only --no-commit-id HEAD
However, this doesn’t escape spaces in the filename, which leads to problems when trying to use the command with a bash loop:
me@pc ~/tmp/testrepo $ git diff-tree -r --name-only --no-commit-id HEAD
a file
me@pc ~/tmp/testrepo $ for f in `git diff-tree -r --name-only --no-commit-id HEAD`; do ls $f; done
ls: cannot access a: No such file or directory
ls: cannot access file: No such file or directory
Using quotes with the ls command didn’t help:
me@pc ~/tmp/testrepo $ for f in `git diff-tree -r --name-only --no-commit-id HEAD`; do ls "$f"; done
ls: cannot access a: No such file or directory
ls: cannot access file: No such file or directory
I tried piping the output through sed, both to escape the spaces and surround each filename with quotes, but this didn’t help either:
me@pc ~/tmp/testrepo $ for f in `git diff-tree -r --name-only --no-commit-id HEAD | sed -e 's/ /\\\ /g'`; do ls $f; done
ls: cannot access a\: No such file or directory
ls: cannot access file: No such file or directory
me@pc ~/tmp/testrepo $ for f in `git diff-tree -r --name-only --no-commit-id HEAD | sed -e 's/.*/"&"/g'`; do ls $f; done
ls: cannot access "a: No such file or directory
ls: cannot access file": No such file or directory
It turns out you need quotes around both the git command and the ls command’s arguments:
me@pc ~/tmp/testrepo $ for f in "`git diff-tree -r --name-only --no-commit-id HEAD`"; do ls "$f"; done
a file