88

EDIT:

I would like to make a recommendation that parsing colors is a generally ill-conceived idea.

Part of why i wanted it was so I can both parse it and pass it along in my own script output. This is... okay, but it would probably be saner to use porcelain or some such and re-build the colored parts myself!

Original question follows.


I like to see color because my scripting is robust enough (so far) to handle the color codes. It does seem like I'm going against the grain here, but I honestly don't see what the big deal is about having to parse stuff like escape codes in scripts. If colors help for interactive use, why wouldn't they help in script use where I might be aggregating data and crunching even more data than I would manually? Wouldn't colors be even more important?

Anyway, I have a neat little shell script I wrote that munges git status output, and i'm just looking to make this script keep the colors intact. My global git config is set so that the lists of changed and untracked files show up in color in the git status. Unfortunately unlike git diff there is no option for forcing color for git status that I can find.

To be abundantly clear, this is the issue:

$ git status

produces perfect output, but (excerpt from my script follows)

git status | sed "s/^#/\x1b[34m#[0m/"

produces no colored git status output, and you can even see here that I'm explicitly converting the leading hash-characters to blue because it helps highlight the different regions of output from my script.

Does anyone know how to get it to put out the colors? Is there maybe a standard program I can use that can be used as a "fake terminal" STDIN/STDOUT pipe? I am in fact also working on a pty pseudoterminal tool so I could certainly make use of that for this purpose, but it's a rather heavy-handed solution (and not ready for use yet as I haven't finished building it).

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • Also check [How to colorize output of git](http://unix.stackexchange.com/q/44266/54586) – Sithsu Oct 18 '14 at 10:10
  • 7
    One issue with parsing colour codes to extract meaningful data for scripts is that a different user may have configured different colours in their config file. To avoid the issues that would cause, git offers the `--porcelain` option for various commands, which should provides a format that is easier to parse and less prone to change between environments. – joeytwiddle Oct 21 '14 at 09:58
  • 1
    To add to @joeytwiddle's comment, as a design note, it's a bad idea to encode status information as *only* color since some people have various kinds of color blindness (red-green is the most common but there is also blue-yellow, and more; for details see https://nei.nih.gov/health/color_blindness/facts_about). It affects roughly 10% of humans! Always make sure that there is some way other than mere color to extract necessary information. – torek Sep 20 '18 at 22:51

3 Answers3

148

To avoid changing your git config, you can enable colour just for the current command by passing a config variable with -c.

For the status command, the variable is color.status:

    git -c color.status=always status | less -REX

For diff, show, log and grep commands, the variable is color.ui:

    git -c color.ui=always diff | less -REX

Note that -c must come before the status or diff argument, and not after.

Alternatively, for diff, show, log and grep commands, you can use --color=always after the command:

    git diff --color=always | less -REX

Note: As Steven said, if you are trying to extract meaningful data, then instead of parsing colours to extract meaning, you can use --porcelain to get more parser-friendly output.

    git status --porcelain | awk ...

Then if you wanted, you could reintroduce colours later.

To get the user's configured colours, you can use git config --get-colour:

    reset_color="$(tput sgr0)"
    remote_branch_color="$(git config --get-color color.branch.remote white)"

    echo "Pushing to ${remote_branch_color}${branch_name}${reset_color}"

Some more examples here.

joeytwiddle
  • 29,306
  • 13
  • 121
  • 110
  • 2
    You say it works for **log**, but I don't find that is the case. :( – Adrian Jan 02 '18 at 16:29
  • 3
    Hmmm, looks like this is different for **log**. the command is `git log --color=always`. Too bad about the inconsistencies with the command line interface. – Adrian Jan 02 '18 at 16:41
  • 2
    Looks like git tried to unify this with **diff**, **show** and **log**, using the `--color=...` switch after the command as I stated, but didn't update this with **status**. – Adrian Jan 02 '18 at 16:51
  • 2
    I posted the question; In the parts of my code that do parse `git status`, they parse the output of `git status --porcelain`. Nevertheless, this is very cool to know that we can override config for git for the current invocation using `-c`. – Steven Lu Sep 21 '18 at 02:23
  • More useful git colourise / colorize information in this answer: https://unix.stackexchange.com/a/44283/357604 – NeilG Sep 03 '19 at 01:00
  • @Adrian, I could kiss that man. For `git grep` you can also use `--color=always` to make it persist. For example: `git -c color.grep.filename="14 20" grep color=always foo | fzf --ansi` – DZet May 03 '20 at 03:38
  • Can you please incorporate Adrian's correction regarding log? ```git log --color=always``` – Josiah Yoder May 26 '20 at 18:55
  • @JosiahYoder Done. – joeytwiddle Jul 28 '20 at 02:59
  • Damn, the BSD version doesn't have `-c` (my version is `git version 2.21.1 (Apple Git-122.3)`). – Sridhar Sarnobat Aug 17 '20 at 18:19
  • 2
    `git -c color.ui=always status` works in git version 2.20.1, no need to use another variable `color.status`. – ks1322 Jan 09 '22 at 19:20
24

EDIT:

I would like to make a strong recommendation that parsing colors is a generally ill-conceived idea.

Part of why i wanted it was so I can both parse it and pass it along in my own script output. This is... okay, but it would probably be saner to use porcelain or some such and re-build the colored parts myself!

Original answer follows.


I keep finding answers really quickly after asking questions. Something to do with thinking about a problem long enough to write it out that you formulate better approaches for solving it. Anyway, the solution to this is just

git config color.status always

I imagine that a general purpose solution involves expect or something pty related to force any programs that require it into thinking they are on a terminal.

Steven Lu
  • 41,389
  • 58
  • 210
  • 364
  • 7
    @joeytwiddle has a better answer... always forcing color means you may to get color in some places where you don't want it. Using -c limits the scope to the script in question. – danwyand Oct 20 '14 at 19:41
  • 4
    `git config --global color.ui auto ` – Ashish Sajwan May 12 '15 at 08:27
  • 1
    I switched my accept, it does more directly answer my question. @AshishSajwan setting color to auto means it will NOT produce colors when run with a script. – Steven Lu May 12 '15 at 10:55
  • Yes, outputs are usually either meant to be either HUMAN-READABLE or MACHINE-READABLE, and they have quite different properties. – Raúl Salinas-Monteagudo Jun 13 '19 at 08:55
  • 1
    If you do go the route of parsing porcelain data and then adding your own colour codes to the output, you can check if the user has configured a preferred colour for certain things like this: `current_branch_termcode="$(git config --get-color color.branch.current green)"` where `green` is the fallback you want to use if there is no custom configuration found (ideally put git's default colour there). – joeytwiddle Jun 13 '19 at 17:16
2

I had this same issue when using a git alias that executes a shell command. Apparently the git shell doesn't inherit from the current environment, so it knows nothing about my coloring settings.

In addition to adding the global git color ui setting, I fixed this by making my alias look like below, its the secondary command that requires being told to use colors, as git will by default as of whatever 1.8.x version people have mentioned.

[alias]
  ignored = !git ls-files -v|grep --color '^h'

This produces equivalent colorized output now when run as the alias the same as if I just ran the command.

For sed, this other answer appears to work more reliably, use tput. https://unix.stackexchange.com/a/45954

Community
  • 1
  • 1
dragon788
  • 3,583
  • 1
  • 40
  • 49