Fastest way to get git status in bash

Not entirely your answer, but bash-completion has this built-in.

If you set the bash ENV GIT_PS1_SHOWDIRTYSTATE to a nonempty value, unstaged (*) and staged (+) changes will be shown next to the branch name. You can configure this per-repository ith the bash.showDirtyState variable, which defaults to true once GIT_PS1_SHOWDIRTYSTATE is enabled.

You can also see if currently something is stashed, by setting GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed, then a '$' will be shown next to the branch name.

If you would like to see if there are untracked files, then you can set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there are untracked files, then a '%' will be shown next to the branch name.

Not sure about the speed degrade when you enable this though. If you want to do the coloring:

Staged files:

if git rev-parse --quiet --verify HEAD >/dev/null; then
 git diff-index --cached --quiet HEAD -- || color for staged changes
  color unstaged changes

Stashed files

git rev-parse --verify refs/stash >/dev/null 2>&1 && color for stashed files

Untracked files

if [ -n "$(git ls-files --others --exclude-standard)" ]; then
  Color untrack files

The above snippets come from the bash-completion script.

Note: Git 2.6+ (Q3 2015) should accelerate that __git_ps1 status:

See commit dd160d7, commit 6bfab99 (19 Jul 2015) by SZEDER Gábor (szeder).
(Merged by Junio C Hamano -- gitster -- in commit 461c119, 03 Aug 2015)

bash prompt: faster untracked status indicator with untracked directories

If the untracked status indicator is enabled, __git_ps1() looks for untracked files by running 'git ls-files'.
This can be perceptibly slow in case of an untracked directory containing lot of files, because it lists all files found in the untracked directory only to be redirected into /dev/null right away.
This is the actual command run by __git_ps1():

$ ls untracked-dir/ |wc -l
$ time git ls-files --others --exclude-standard --error-unmatch \
  -- ':/*' >/dev/null 2>/dev/null

real    0m0.955s
user    0m0.936s
sys 0m0.016s

Eliminate this delay by additionally passing the '--directory --no-empty-directory' options to 'git ls-files' to show only the name of non-empty untracked directories instead of all their content:

$ time git ls-files --others --exclude-standard --directory \
  --no-empty-directory --error-unmatch -- ':/*' >/dev/null 2>/dev/null

real    0m0.010s
user    0m0.008s
sys 0m0.000s

This follows suit of ea95c7b (completion: improve untracked directory filtering for filename completion, 2013-09-18, git 1.8.5).

Make sure to tuse Git 2.29 (Q4 2020), as a leakfix is available in a part of the code which influences git ls-files.

See commit eceba53, commit dad4f23 (18 Aug 2020) by Elijah Newren (newren).
(Merged by Junio C Hamano -- gitster -- in commit ad00f44, 24 Aug 2020)

dir: fix problematic API to avoid memory leaks

Signed-off-by: Elijah Newren

The dir structure seemed to have a number of leaks and problems around it.

First I noticed that parent_hashmap and recursive_hashmap were being leaked (though Peff noticed and submitted fixes before me).

Then I noticed in the previous commit that clear_directory() was only taking responsibility for a subset of fields within dir_struct, despite the fact that entries[] and ignored[] we allocated internally to dir.c.
That, of course, resulted in many callers either leaking or haphazardly trying to free these arrays and their contents.

Digging further, I found that despite the pretty clear documentation near the top of dir.h that folks were supposed to call clear_directory() when the user no longer needed the dir_struct, there were four callers that didn't bother doing that at all.
However, two of them clearly thought about leaks since they had an UNLEAK(dir) directive, which to me suggests that the method to free the data was too unclear.
I suspect the non-obviousness of the API and its holes led folks to avoid it, which then snowballed into further problems with the entries[], ignored[], parent_hashmap, and recursive_hashmap problems.

Rename clear_directory() to dir_clear() to be more in line with other data structures in git, and introduce a dir_init() to handle the suggested memsetting of dir_struct to all zeroes.
I hope that a name like "dir_clear()" is more clear, and that the presence of dir_init() will provide a hint to those looking at the code that they need to look for either a dir_clear() or a dir_free() and lead them to find dir_clear().

That influences:

  • git add
  • git check-ignore
  • git clean
  • git grep
  • git ls-files
  • git stash
  • git merge