I am trying to practice using xargs. I tried the following, passing the SHA1 via xargs:

$ git show SHA1 --name-only

I also tried:

$ git log --author=jim --grep="patch" |head -n 1|cut -d ' ' -f2|xargs {} git show {} --name-only

It returned xargs: {}: No such file or directory

So, I moved on to this:

$ git log --author=jim --grep="patch" |head -n 1|cut -d ' ' -f2|xargs -0 -I {} git show {} --name-only

Which returned:

fatal: ambiguous argument 'a1237ac27321f2daea365787664e4119b339c483': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

The SHA mentioned is the correct one, but I don't understand why this does not work either

2 Answers 2


xargs -0 means to use only null bytes to separate input records, and include newline characters and other whitespace in the input. You're going to have a newline at the end of the revision output there, which head and cut will leave there, and which will be included in the argument given to git. Git doesn't like that. I think you've edited the newline out of the error message, but it is actually a part of the message here and what's causing your problem.

Removing -0 makes your command work for me. Given the input you're generating, the default newline-separated behaviour of xargs is safe.

You don't really need to use -I {} in this case either — git is quite happy to have the revision as the last argument, but I guess you're using it for practice's sake. By default, xargs just puts the arguments at the very end of the given command (unlike find -exec, which uses the {} substitution).

You're also doing a bit much work, though, with your cut. Git is more than capable of arranging its output in a format you can use with xargs. Using the --pretty=tformat... option we can make it spit out just the SHA1 hashes, one per line:

git log --author=jim --grep="patch" --pretty=tformat:'%H'

will output all the hashes of matching commits in your repository, one per line. --pretty sets the output formatting; tformat means to put a newline at the end of every hash; '%H' means the hash.

You can pipe that into xargs, and since the entire input is "clean" [a-f0-9] you can use it with the default line-separation

  • But why doesn't the first version without -0 and without -I work?
    – Jim
    Commented Jul 8, 2014 at 12:42
  • xargs doesn't use {} for substitution. That's find. xargs just puts them at the end by default, unless you use -I. Commented Jul 8, 2014 at 19:51
  • I created git tag for each merge with pipe and with xargs:
    • git log --oneline --merges --pretty=format:"V%ad %H" --date=format:"%Y%m%d_%H_%M" |xargs -n2 git tag --force


  • I created git tag for each merge with pipe and with awk in the place of xargs:

    • git log --oneline --merges --pretty=format:"V%ad %H" --date=format:"%Y%m%d_%H_%M" | awk '{system("git tag --force " $1 " " $2)}'


  • with xargs and bash

    • git log --oneline --merges --pretty=format:"V%ad %H" --date=format:"%Y%m%d_%H_%M" | xargs -l bash -c 'git tag $0 $1 --force'


  • An Other with subject in the tag name
    • git log --oneline --merges --pretty=format:"V%ad_%f %H" --date=format:"%Y%m%d_%H_%M" | sed "s/\./_/g" | xargs -l bash -c 'var="$0" && git tag --force ${var:0:100} $1'

and after : git push --tags origin mytargetbranch


Alternative from git log --oneline --merges --pretty=format:"V%ad_%f %H" where %f (sanitized subject) is replaced by %s and the perl sanitize to accept extended latin alphabet

git log --oneline --merges --pretty=format:"V%ad_%s+++%H" --date=format:"%Y%m%d_%H_%M"| perl -pe 's/[\?\[\]\/\\=<>:;,\x27"&\$#*()|~`!{}%]//g;' |   sed "s/[ .]/_/g" |   sed "s/+++/ /g"  |   sed "s/+//g" | xargs  -l bash -c 'var="$0";git tag --force  ${var:0:100} $1' && git push --tags origin mytargetbranch


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .