I've been using some of the Linux tooling on my Windows machine for a little while now, since it comes with the git installation and it's a ton of fun to use. I've been particularly enamored with this command, which should theoretically allow me to delete all my extraneous git branches in one go:
git branch | grep -v 'master' | xargs git branch -d
A while ago, however, this stopped working. Instead I get a series of error messages for each branch along the following lines:
error: branch 'extraneous-branch-1?' not found.
error: branch 'extraneous-branch-2?' not found.
error: branch 'extraneous-branch-3?' not found.
...
Note that the question marks are not part of my branch names - those are apparently being added somehow when the values are piped from grep to xargs. When I run xargs in interactive mode to try to see what it's actually producing, I get an output that looks like this:
git branch -d 'extraneous-branch-1'$'\r' 'extraneous-branch-2'$'\r' 'extraneous-branch-3'$'\r' ...
It seems as if grep is piping the end-of-line and carriage-return entries as part of each match, though I don't know how to prevent it from doing that. What baffles me is that I definitely remember this working before - I have no idea what would have changed. Truthfully I know barely anything about the Linux command line tools, so I wouldn't be surprised if there's something obvious I'm overlooking here. Appreciate any advice either way.
Edit
When I run git branch | cat -A
, I get the following result:
extraneous-branch-1$
extraneous-branch-2$
extraneous-branch-3$
CodePudding user response:
Thanks to anubhava for pointing me in the right direction here. It appears grep is returning a bunch of non-printing characters that are visible when you run git branch | cat -A
. It turns out just adding cat
in there eliminates all those characters. Now it works perfectly.
git branch | grep -v master | cat | xargs git branch -d
a bit more verbose than before, but I'm not complaining.
CodePudding user response:
The root of the problem here is a specific example of a more general case: some Git commands produce output that is meant for a human to read, and other Git commands produce output that is meant for a computer to read. Reading human output with computer programs produces surprises, so: don't do that.
In particular, git branch
may add color encoding to branch names, or run its output through a pager that does fancy things. This is because git branch
is what Git calls a porcelain command, meaning it produces human-readable output. Fortunately, there's a similar plumbing command, git for-each-ref
, that—because it is "plumbing"—produces computer-readable output by default.
The for-each-ref
command is a little trickier to use because you must be more explicit. To get branch names, without further details, you need:
git for-each-ref --format="%(refname:short)" refs/heads
You can run this output through grep -v '^master$'
to drop the name master
. (Your existing grep is a little loose. It would also drop, e.g., the branch name stairmaster_bugfix
.)
For more on the git for-each-ref
command, see its documentation. Note that by default, git branch
attempts to drop fancy features like colorization and use of the pager by default if its stdout is not a "tty device" as determined by the C library isatty
function, but you can override these defaults with configuration settings. It is likely that you have done this, since git branch | grep
generally causes the C library isatty
to say "no, not a tty".