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

Make use of git status --porcelain in fish_git_prompt to improve performance #7871

Closed
blahgeek opened this issue Mar 28, 2021 · 7 comments
Closed

Comments

@blahgeek
Copy link

fish_git_prompt can be very slow in large git repos. There's multiple issues reporting this previously (#7705, #6764).

Currently fish_git_prompt uses multiple git commands separately to get numbers of stages files, untracked files, etc., but they can be replaced with one faster command git status --porcelain (also mentioned in #4842 (comment))

Some other git prompt implementations already do this (e.g. https://github.com/magicmonty/bash-git-prompt/blob/master/gitstatus.sh (as I see it, it provides the same information as fish_git_prompt)), we can check out how it's implemented.

In one of my large git repos, the performance difference between them are significant:

  • git status --porcelain=v1: 0.14s
  • bash-git-prompt/gitstatus.sh: 0.16s
  • fish_git_prompt: 1.06s
@faho
Copy link
Member

faho commented Mar 28, 2021

git status --porcelain has three problems:

  1. The v1 format is unusable, we need the v2 one, but the v2 one was only introduced in git 2.11. For some reason people insist on using new fish on old and crusty distributions.
  2. It is in some circumstances slower than what we currently do
  3. It is still counting stuff

Really, what you want most of the time is to turn off the "informative" prompt and stop counting the number of files. That'll get you a nice and responsive prompt with the useful info.

@IlanCosman
Copy link
Contributor

What do you dislike about porcelain v1? It works perfectly for me in Tide.

@faho
Copy link
Member

faho commented Mar 28, 2021

Let me direct you to the completions. In that case it was about the paths it prints, but just using spaces here is quite awkward, and some other, more unusual, notations are awful. I recall renamed files being a particular PITA.

Basically, both versions of git status --porcelain are bad, but the v1 format is truly horrible once you look a little closer.

It "works perfectly" for you because you barely do anything with it. Technically the porcelain format was meant to be machine-readable, which implies that you need to be able to use arbitrary filenames - that includes newlines. Only nobody turns on the -z NUL-delimited mode.

And the speedup is typically because it counts differently - git status --porcelain will not decend into subdirectories. For instance I've run your code on a test repo of mine, it reports "3" untracked files, while the current code reports 60000 - because it just reports that 3 directories have changed. Add -uall, and the result matches, but suddenly all of the performance improvement disappears.

That's basically the same point about counting stuff again. The bit in git prompts that is always the slowest is counting how many modified/staged/untracked/etc files there are. If you stop that, and just see if there are modified/staged/untracked/etc things are much faster, while still giving you the important information (do you act any differently if there are 3 modified files as opposed to 2?). That's what I mean when I say you want to turn off the informative prompt. Frankly I've thought about removing it entirely, and that might be the better way to go.

@zanchey

This comment has been minimized.

@faho
Copy link
Member

faho commented Mar 29, 2021

So, as far as I can tell, there are three options here:

  • Keep it as it is, with the count reflecting all the files
  • Switch to git status --porcelain, without "-uall" (because that makes it slower than what we have now), with the count reflecting untracked directories or files in tracked directories
  • Remove the informative prompt entirely

To be honest, I do not believe that the informative prompt really helps. It's not useful information. You're not going to act differently if you know there's 15 modified files as opposed to 12. You just need to know that the repo is "dirty", and in what way.

So, given how many reports we have about the git prompt being slow, I'm leaning towards the third option. Just nuke it from orbit, make the option just enable the nicer symbols (that I still maintain should be the default).

@faho faho closed this as completed in f75cf5c Mar 30, 2021
@faho faho added this to the fish 3.3.0 milestone Mar 30, 2021
@faho
Copy link
Member

faho commented Mar 30, 2021

As I have no interest in dealing with the inevitable backlash if we remove the informative prompt, I've just changed it to use git status --porcelain, the v1 format, which should be supported with any git released since at least 2015 (v2.2.3 being the oldest that I can find docs for).

We do pass -unormal, which makes it not descend into untracked directories, instead it just counts them as "1". Otherwise this exercise is a bit pointless because that's where most of the performance benefit comes from.

As a sidenote, I've now personally configured the status characters on my system to be more intuitively understandable:

set -g __fish_git_prompt_char_dirtystate \U1F4a9
set -g __fish_git_prompt_char_untrackedfiles "?"

(I always forget what "..." is supposed to be, and I don't understand why a red plus would be "dirty". On the other hand U+1F4A9 should be obvious)

We might think about some nicer defaults here.

@zanchey
Copy link
Member

zanchey commented Apr 1, 2021

I like the informative mode. I use it when I'm adding patches bit-by-bit to keep track of how I'm going.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants