Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Performance improvement for large repos! (Avoid using "git status") #52

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

simonsthings
Copy link

The function find_git_dirty() delayed prompt display by over a second when in a large repo, so I now use the plumbing commands instead of "git status". Because we don't actually need to generate a list of all the changed files just to see if the repo is dirty. Further improvements possible.

Also, there's some more verbosity to keep the command output reliable.
(Errcode 128 applies e.g. when in any .git folder)

Finally, I surrounded this by the test for branch name as in find_git_branch(), to avoid output on non-git folders. Other implementation imaginable.

@AaronDMarasco-VSI
Copy link

I have had problems with this in large repos as well, and appreciate the improvement.

However, in the past, I've had trouble with "git rev-parse" before. I'll annotate the changeset.

prompt.sh Outdated
if [[ "$status" != "" ]]; then
git_dirty='*'
local branch
if branch=$(git rev-parse --abbrev-ref HEAD 2> /dev/null); then

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've had problems with this before; it didn't work in a detached head state. My solution was to instead use "git name-rev --name-only HEAD" instead.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That part is just copied from the find_git_branch() function. The actual contribution here is in line 20: "git diff-index ..."

But yes, lines 4 and 16 could probably be improved, too.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I just checked the behaviour by checking out an old commit (4 commits ago), and while the traditional output for line 4 is "(detached*)", yours becomes the slightly more verbose "(remotes/origin/HEAD~4)".
But this seems like a matter of taste? Or what were the specific problems?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm confused and it was something else, sorry. I have a Makefile that tries to determine branch name, so "detached" wasn't good enough. For an interactive prompt, it should be.

@simonsthings
Copy link
Author

Ah just saw that this also doesn't show dirty for untracked files. But I think there were some other pull requestes dealing with that? Might be good to have two separate indicators for this, anyway.

Copy link

@AaronDMarasco-VSI AaronDMarasco-VSI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (not that I am anybody special)

@AaronDMarasco-VSI
Copy link

Honestly, I don't want/use untracked indication. That is different than dirty.

…present. (Without using "git status")

This nicely splits up the needed functionality of "git status" into two functions without the speed loss.
There is now also a small function that combines both indicators into what used to be given by "git status", but without the performance loss on large repos.

These strings can now be used in your git-aware prompt:

\$git_changed - Shows if tracked files have been changed.
\$git_untracked - Shows if untracked files (or folders) are present.
\$git_untracked_num - Shows the number of untracked files or folders if present.

\$git_dirty - Shows if tracked files have been changed or untracked files are present. (Combines the above)
\$git_branch - The current branch, as before.
@simonsthings
Copy link
Author

simonsthings commented May 4, 2017

Oh, oops. Well, now i've made them anyway.
But people can now choose which indicator they want to use.
(And the speed benefits over "git status" are still present.)
(Otherwise just only use the first commit)

@alanhamlett
Copy link

alanhamlett commented Apr 25, 2019

This change is still slow for me on very large repos. Here's a function to read .git/HEAD for branch name which is extremely fast:

alanhamlett/dotfiles/bashrc#L15

find_git_branch() {
  local firstline
  local folder
  folder=`pwd`
  while [ "$folder" != "/" ] ; do
    if [[ -f "$folder/.git/HEAD" ]]; then
      break
    fi
    folder=`dirname "$folder"`
  done
  if [ "$folder" != "/" ] ; then
    read -r firstline<"$folder/.git/HEAD"
    git_branch="(${firstline/ref: refs\/heads\//})"
  else
    git_branch=""
  fi
}

@alanhamlett
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants