git-prompt has various describe styles, among them "describe" (by
annotated tags) and "default" (by exact match with any tag).
Add a mode "tag" that describes by any tag, annotated or not.
Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The git-prompt scriptlet (in contrib/) was not friendly with those
who uses "set -u", which has been fixed.
* vs/prompt-avoid-unset-variable:
git-prompt.sh: Don't error on null ${ZSH,BASH}_VERSION, $short_sha
When the shell is in "nounset" or "set -u" mode, referencing unset or
null variables results in an error. Protect $ZSH_VERSION and
$BASH_VERSION against that, and initialize $short_sha before use.
Signed-off-by: Ville Skyttä <ville.skytta@iki.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
__git_ps1() doesn't indicate dirty index while on an orphan branch.
To check the dirtiness of the index, __git_ps1() runs 'git diff-index
--cached ... HEAD', which doesn't work on an orphan branch,
because HEAD doesn't point to a valid commit.
Run 'git diff ... --cached' instead, as it does the right thing both
on valid and invalid HEAD, i.e. compares the index to the existing
HEAD in the former case and to the empty tree in the latter. This
fixes the two failing tests added in the first commit of this series.
The dirtiness of the worktree is already checked with 'git diff' and
is displayed correctly even on an orphan branch.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jeff King <peff@peff.net>
To get the dirty state indicator __git_ps1() runs 'git diff' with
'--quiet --exit-code' options. '--quiet' already implies
'--exit-code', so the latter is unnecessary and can be removed.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jeff King <peff@peff.net>
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
100000
$ 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 ea95c7b8f5 (completion: improve untracked directory
filtering for filename completion, 2013-09-18).
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The environment variable GIT_PS1_STATESEPARATOR can be used to set the
separator between the branch name and the state symbols in the prompt.
At present the variable is not mentioned in the inline documentation which
makes it difficult for the casual user to identify.
Signed-off-by: Joe Cridge <joe.cridge@me.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The prompt script (in contrib/) did not show the untracked sign
when working in a subdirectory without any untracked files.
* ct/prompt-untracked-fix:
git prompt: use toplevel to find untracked files
The __git_ps1() prompt function would not show an untracked state
when all the untracked files are outside the current working
directory.
Signed-off-by: Cody A Taylor <codemister99@yahoo.com>
Helped-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Using the exit status of the last command in the prompt, e.g.
PS1='$(__git_ps1) $? ', did not work well because the helper
function stomped on the exit status.
* tf/prompt-preserve-exit-status:
git-prompt: preserve value of $? in all cases
* rh/hide-prompt-in-ignored-directory:
git-prompt.sh: allow to hide prompt for ignored pwd
git-prompt.sh: if pc mode, immediately set PS1 to a plain prompt
Using the exit status of the last command in the prompt, e.g.
PS1='$(__git_ps1) $? ', did not work well because the helper
function stomped on the exit status.
* tf/prompt-preserve-exit-status:
git-prompt: preserve value of $? inside shell prompt
Optionally set __git_ps1 to display nothing when present working
directory is ignored, triggered by the new environment variable
GIT_PS1_HIDE_IF_PWD_IGNORED. This environment variable may be
overridden on any repository by setting bash.hideIfPwdIgnored to
"false". In the absence of GIT_PS1_HIDE_IF_PWD_IGNORED this change
has no effect.
Many people manage e.g. dotfiles in their home directory with git.
This causes the prompt generated by __git_ps1 to refer to that "top
level" repo while working in any descendant directory. That can be
distracting, so this patch helps one shut off that noise.
Signed-off-by: Jess Austin <jess.austin@gmail.com>
Signed-off-by: Richard Hansen <rhansen@bbn.com>
Reviewed-by: Richard Hansen <rhansen@bbn.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
At the beginning of __git_ps1, right after determining that the
function is running in pc mode, set PS1 to a plain (undecorated)
prompt. This makes it possible to simply return early without having
to set PS1 if the prompt should not be decorated.
Signed-off-by: Richard Hansen <rhansen@bbn.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
"git-prompt" (in contrib/) used a variable from the global scope,
possibly contaminating end-user's namespace.
* jg/prompt-localize-temporary:
git-prompt.sh: make $f local to __git_eread()
If you have a prompt which displays the command exit status,
__git_ps1 without this change corrupts it, although it has
the correct value in the parent shell:
~/src/git (master) 0 $ set | grep ^PS1
PS1='\w$(__git_ps1) $? \$ '
~/src/git (master) 0 $ false
~/src/git (master) 0 $ echo $?
1
~/src/git (master) 0 $
There is a slightly ugly workaround:
~/src/git (master) 0 $ set | grep ^PS1
PS1='\w$(x=$?; __git_ps1; exit $x) $? \$ '
~/src/git (master) 0 $ false
~/src/git (master) 1 $
This change makes the workaround unnecessary.
Signed-off-by: Tony Finch <dot@dotat.at>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This function uses (non-local) $f to store the value of its first parameter.
This can interfere with the user's environment.
Signed-off-by: Justin Guenther <jguenther@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Since dd0b72c (bash prompt: use bash builtins to check stash
state, 2011-04-01), git-prompt checks whether we have a
stash by looking for $GIT_DIR/refs/stash. Generally external
programs should never do this, because they would miss
packed-refs.
That commit claims that packed-refs does not pack
refs/stash, but that is not quite true. It does pack the
ref, but due to a bug, fails to prune the ref. When we fix
that bug, we would want to be doing the right thing here.
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu>
Reviewed-by: Ronnie Sahlberg <sahlberg@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Not all shells subject the prompt string to parameter expansion. Test
whether the shell will expand the value of PS1, and use the result to
control whether raw ref names are included directly in PS1.
This fixes a regression introduced in commit 8976500 ("git-prompt.sh:
don't put unsanitized branch names in $PS1"): zsh does not expand PS1
by default, but that commit assumed it did. The bug resulted in
prompts containing the literal string '${__git_ps1_branch_name}'
instead of the actual branch name.
Reported-by: Caleb Thompson <caleb@calebthompson.io>
Signed-off-by: Richard Hansen <rhansen@bbn.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Otherwise it might collide with a function of the same name in the
user's environment.
Suggested-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Both bash and zsh subject the value of PS1 to parameter expansion,
command substitution, and arithmetic expansion. Rather than include
the raw, unescaped branch name in PS1 when running in two- or
three-argument mode, construct PS1 to reference a variable that holds
the branch name. Because the shells do not recursively expand, this
avoids arbitrary code execution by specially-crafted branch names such
as '$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)'.
Signed-off-by: Richard Hansen <rhansen@bbn.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
zsh seems to have a bug while redirecting the stderr of the 'read'
command:
% read foo 2>/dev/null <foo
zsh: no such file or directory: foo
Which causes errors to be displayed when certain files are missing.
Let's add a convenience function to manually check if the file is
readable before calling "read".
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The '+=' operator is not supported by old Bash versions (3.0) we still
care about.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
When working with multiple remotes, it is common to switch the upstream
from a remote to another. Doing so, the prompt may not be the expected
one. Providing an option to display tracking information sounds useful.
Add a "name" option to GIT_PS1_SHOWUPSTREAM which will show the upstream
abbrev name. This option is ignored if "verbose" is false.
Signed-off-by: Julien Carsique <julien.carsique@gmail.com>
Improved-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Old Bash (3.0) which is distributed with RHEL 4.X and other ancient
platforms that are still in wide use, do not have a printf that
supports -v. Neither does Zsh (which is already handled in the code).
As suggested by Junio, let's test whether printf supports the -v
option and store the result. Then later, we can use it to
determine whether 'printf -v' can be used, or whether printf
must be called in a subshell.
Signed-off-by: Brandon Casey <drafnel@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Code clean-up for in-prompt status script (in contrib/).
* ed/color-prompt:
git-prompt.sh: add missing information in comments
git-prompt.sh: do not print duplicate clean color code
t9903: remove redundant tests
git-prompt.sh: refactor colored prompt code
t9903: add tests for git-prompt pcmode
Mention that the command below is needed for prompt
in ZSH with PS1:
setopt PROMPT_SUBST
Rephrase some parts that mention only the "current branch name"
being displayed in the prompt. Replace it by stating that
the "repository status" is displayed.
Make it clear that colored prompt is only available
in PROMPT_COMMAND/precmd mode.
With-suggestions-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Eduardo R. D'Avila <erdavila@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Do not print a duplicate clean color code when there
is no other indicators other than the current branch
in colored prompt.
Acked-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Eduardo R. D'Avila <erdavila@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
__git_ps1_colorize_gitstring() sets color codes and
builds the prompt gitstring. It has duplicated code
to handle color codes for bash and zsh shells.
__git_ps1() also has duplicated logic to build the
prompt gitstring.
Remove duplication of logic to build gitstring in
__git_ps1_colorize_gitstring() and __git_ps1().
Leave in __git_ps1_colorize_gitstring() only logic
to set color codes.
Signed-off-by: Eduardo R. D'Avila <erdavila@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
__git_ps1() is usually added to the prompt inside a command
substitution, imposing the overhead of fork()ing a subshell. Using
__git_ps1() for $PROMPT_COMMAND is slightly faster, because it avoids
that command substitution.
Mention this in the comments about setting up the git prompt.
The whole series speeds up the bash prompt on Windows/MSysGit
considerably. Here are some timing results in three scenarios, each
repeated 10 times:
At the top of the work tree, before:
$ time for i in {0..9} ; do prompt="$(__git_ps1)" ; done
real 0m1.716s
user 0m0.301s
sys 0m0.772s
After:
real 0m0.687s
user 0m0.075s
sys 0m0.396s
After, from $PROMPT_COMMAND:
$ time for i in {0..9} ; do __git_ps1 '\h:\w' '$ ' ; done
real 0m0.546s
user 0m0.075s
sys 0m0.181s
At the top of the work tree, detached head, before:
real 0m2.574s
user 0m0.376s
sys 0m1.207s
After:
real 0m1.139s
user 0m0.151s
sys 0m0.500s
After, from $PROMPT_COMMAND:
real 0m1.030s
user 0m0.245s
sys 0m0.336s
In a subdirectory, during rebase, stash status indicator enabled,
before:
real 0m3.557s
user 0m0.495s
sys 0m1.767s
After:
real 0m0.717s
user 0m0.120s
sys 0m0.300s
After, from $PROMPT_COMMAND:
real 0m0.577s
user 0m0.047s
sys 0m0.258s
On Linux the speedup ratio is comparable to Windows, but overall it
was about an order of magnitude faster to begin with. The last case
from above, repeated 100 times, before:
$ time for i in {0..99} ; do prompt="$(__git_ps1)" ; done
real 0m2.806s
user 0m0.180s
sys 0m0.264s
After:
real 0m0.857s
user 0m0.020s
sys 0m0.028s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Before setting $PS1, __git_ps1() uses a command substitution to
redirect the output from a printf into a variable. Spare the overhead
of fork()ing a subshell by using 'printf -v <var>' to directly assign
the output to that variable.
zsh's printf doesn't support the '-v <var>' option, so stick with the
command substitution when under zsh.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
When enabled, the bash prompt can indicate the presence of untracked
files with a '%' sign. __git_ps1() checks for untracked files by running the
'$(git ls-files --others --exclude-standard)' command substitution,
and displays the indicator when there is no output.
Avoid this command substitution by additionally passing
'--error-unmatch *', and checking the command's return value.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
When the environment variable $GIT_PS1_SHOWSTASHSTATE is set
__git_ps1() checks the presence of stashes by running 'git rev-parse
--verify refs/stash'. This command not only checks that the
'refs/stash' ref exists but also, well, verifies that it's a valid
ref.
However, we don't need to be that thorough for the bash prompt. We
can omit that verification and only check whether 'refs/stash' exists
or not. Since 'git pack-refs' never packs 'refs/stash', it's a matter
of checking the existence of a ref file. Perform this check using
only bash builtins to spare the overhead of fork()+exec()ing a git
process.
Also run 'git pack-refs --all' in the corresponding test to document
that the prompt script depends on 'git pack-refs' not packing
'refs/stash' and to catch possible breakages should this behavior ever
change.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
When the dirty work tree and index status indicator is enabled,
__git_ps1() checks for changes in the index by running 'git diff-index
--cached --quiet HEAD --' and looking at its exit code. However, that
makes sense only when HEAD points to a valid commit: on an unborn
branch the failure of said command would be caused by the invalid
HEAD, not by changes in the index. Therefore, __git_ps1() first
checks for a valid HEAD by running 'git rev-parse --quiet --verify
HEAD'.
Since the previous patch we implicitly check HEAD's validity by
running 'git rev-parse ... --short HEAD', making the dirty status
indicator's 'git rev-parse' check redundant. It's sufficient to check
for non-emptyness of the variable holding the abbreviated commit
object name, thereby sparing the overhead of fork()+exec()ing a git
process.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
When describing a detached HEAD according to the $GIT_PS1_DESCRIBE
environment variable fails, __git_ps1() now runs the '$(git rev-parse
--short HEAD)' command substitution to get the abbreviated detached
HEAD commit object name. This imposes the overhead of fork()ing a
subshell and fork()+exec()ing a git process.
Avoid this overhead by combining this command substitution with the
"main" 'git rev-parse' execution for getting the path to the .git
directory & co. This means that we'll look for the abbreviated commit
object name even when it's not necessary, because we're on a branch or
the detached HEAD can be described. It doesn't matter, however,
because once 'git rev-parse' is up and running to fulfill all those
other queries, the additional overhead of looking for the abbreviated
commit object name is not measurable because it's lost in the noise.
There is a caveat, however, when we are on an unborn branch, because
in that case HEAD doesn't point to a valid commit, hence the query for
the abbreviated commit object name fails. Therefore, '--short HEAD'
must be the last options to 'git rev-parse' in order to get all the
other necessary information for the prompt even on an unborn branch.
Furthermore, in that case, and in that case only, 'git rev-parse'
doesn't output the last line containing the abbreviated commit object
name, obviously, so we have to take care to only parse it if 'git
rev-parse' exited without any error.
Although there are tests already excercising __git_ps1() on unborn
branches, they all do so implicitly. Add a test that checks this
explicitly.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
There are a couple of '$(git rev-parse --<opt>)' command substitutions
in __git_ps1() and three of them are executed in the main code path:
- the first to get the path to the .git directory ('--git-dir'),
- the second to check whether we're inside the .git directory
('--is-inside-git-dir'),
- and the last, depending on the results of the second, either
* to check whether it's a bare repo ('--is-bare-repository'), or
* to check whether inside a work tree ('--is-inside-work-tree').
Naturally, this imposes the overhead of fork()ing three subshells and
fork()+exec()ing three git commands.
Combine these four 'git rev-parse' queries into a single one and use
bash parameter expansions to parse the combined output, i.e. to
separate the path to the .git directory from the true/false of
'--is-inside-git-dir', etc. This way we can eliminate two of the
three subshells and git commands.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
__git_ps1() runs the '$(git symbolic-ref HEAD)' command substitution
to find out whether we are on a branch and to find out the name of
that branch. This imposes the overhead of fork()ing a subshell and
fork()+exec()ing a git process.
Since HEAD is in most cases a single-line file and the symbolic ref
format is quite simple to recognize and parse, read and parse it using
only bash builtins, thereby sparing all that fork()+exec() overhead.
Don't display the git prompt if reading HEAD fails, because a readable
HEAD is required for a git repository. HEAD can also be a symlink
symbolic ref (due to 'core.preferSymlinkRefs'), so use bash builtins
for reading HEAD only when HEAD is not a symlink.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
During an ongoing interactive rebase __git_ps1() finds out the name of
the rebased branch, the total number of patches and the number of the
current patch by executing a '$(cat .git/rebase-merge/<FILE>)' command
substitution for each. That is not quite the most efficient way to
read single line single word files, because it imposes the overhead of
fork()ing a subshell and fork()+exec()ing 'cat' several times.
Use the 'read' bash builtin instead to avoid those overheads.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
__git_ps1() finds out the path to the repository by using the
__gitdir() helper function. __gitdir() is basically just a wrapper
around 'git rev-parse --git-dir', extended with support for
recognizing a remote repository given as argument, to use the path
given on the command line, and with a few shortcuts to recognize a git
repository in cwd or at $GIT_DIR quickly without actually running 'git
rev-parse'. However, the former two is only necessary for the
completion script but makes no sense for the bash prompt, while the
latter shortcuts are performance optimizations __git_ps1() can do
without (they just avoid the overhead of fork()+exec()ing a git
process).
Run 'git rev-parse --git-dir' directly in __git_ps1(), because it will
allow this patch series to combine several $(git rev-parse ...)
command substitutions in the main code path, and the overall
performance benefit will far outweigh the loss of those few shortcuts
in __gitdir(). Furthermore, since __gitdir() is not needed anymore
for the prompt, remove it from the prompt script finally eliminating
its duplication between the prompt and completion scripts. Also
remove the comment from the completion script warning about this code
duplication.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
... to gain one level of indentation for the bulk of the function.
(The patch looks quite unreadable, you'd better check it with 'git
diff -w'.)
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
When describing a detached HEAD according to the $GIT_PS1_DESCRIBE
environment variable fails, __git_ps1() runs 'cut -c1-7 .git/HEAD' to
show the 7 hexdigits abbreviated commit object name in the prompt.
Obviously, this neither respects core.abbrev nor produces a unique
object name.
Fix this by using 'git rev-parse --short HEAD' instead and adjust the
corresponding test to use non-standard number of hexdigits.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
The files $g/rebase-{merge,apply}/{head-name,msgnum,end} are not
guaranteed to exist. When attempting to cat them, squelch the error
output.
In addition to guarding against stray directories, this patch addresses
a real problem:
# on terminal 1
$ git rebase -i master
# ignore editor, and switch to terminal 2
cat: .git/rebase-merge/msgnum: No such file or directory
cat: .git/rebase-merge/end: No such file or directory
$
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The bash prompt code (in contrib/) displayed the name of the branch
being rebased when "rebase -i/-m/-p" modes are in use, but not the
plain vanilla "rebase".
* fc/show-branch-in-rebase-am:
prompt: fix for simple rebase