Thread (4 messages) flat view 4 messages, 2 authors, 2016-06-15

Re: command prompt script for current branch

From: Jakub Narebski <hidden>
Date: 2016-06-15 22:44:11

"Stephen Sinclair" [off-list ref] writes:
Attached is a script I quickly wrote up yesterday.  Sometimes I've
found I started working only to realize I was on the wrong branch.
(Now that I'm accustomed to working with git, I make many small
branches, so it happens.)
First, it is much better to put such script inline, in the body of
your email.  This makes commenting about script body much easier.
And if you have to attach it, for example because your mailer mangles
whitespace (which is not the case here), make sure that attachement
uses "text/plain", and if possible "inline" disposition, to better
_view_ the code without need to save it to temporary file.

I would take an exeption and comment on your code, even though you
make it hard to do so.


Second, there are numerous examples on how to create git-aware
prompt.  Those include code in contrib/completion/git-completion.bash
in git sources:

#    4) Consider changing your PS1 to also show the current branch:
#        PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#
#       The argument to __git_ps1 will be displayed only if you
#       are currently in a git repository.  The %s token will be
#       the name of the current branch.

and the _git_ps1 file in sources of "Git In Nutshell", with git
repository at http://git.jonas.iki.fi/git_guides.git; this code
by yours truly is heavily commented to make it easier to understand.
I'm not sure if it is included in "Git In Nutshell" 
(http://jonas.iki.fi/git_guides).

I have put the _git_ps1 code at the end of this post.
So I made this small script to simply write the name of the currently
checked out branch, as well as information on how many commits it
differs from the remote tracking branch, if any.
It also appends an exclamation mark if I have uncommitted changes.  I
stuck it in my PS1 environment variable, so that it would be part of
my command prompt.
Third, the information on how many commits it differes from coupled
remote tracking branch is not that fast to get; additionally you don't
always _have_ coupled remote tracking branch.  For me the number of
commits current branch differs from origin repo, and "dirtiness" of
branch are not important, while working with detached HEAD and marking
branches which are StGit controlled is.
-- >8 --
#!/bin/bash

# exit if not a git repo
if ! (git branch >/dev/null 2>&1); then
    exit
fi
There are much better ways to do this; it is usually much better to
use plumbing (engine) commands in scripts, not porcelain, which is
meant for user interaction. See code in _git_ps1

Besides, why do you run git-branch _twice_?
 
BRANCH=$(git branch | grep \* | sed s,\*\ ,, )
There is much better way to do this with plumbing.
REMOTE=$(git config --list | grep branch.$BRANCH.remote 2>/dev/null | cut -f2 -d=)
MERGE=$(git config --list | grep branch.$BRANCH.merge 2>/dev/null | sed s,^.*=refs/heads/,,)
Why do you use "git config --list" then grep for key, instead of
asking git-config to return results for given key with 
"git config --get" or "git config --get-all"?

By the way, when you use grep you should quote '.', as '.' means any
character in regular expression. You do not need put regular
expression (parameter to grep) in double quotes _only_ because
refnames (and branchnames) cannot contain spaces.

Your code wouldn't be able to deal with being on detached HEAD.
# exit if no branch found
if [ "${BRANCH}"x == x ]; then
    exit
fi
This is mixture of coding for portability with bash-isms; either use
'test' instead of '[', or use '-z' operator.
echo -n ' '[$BRANCH

# dirty state
if [ "$(git-diff-index --name-only HEAD)"x != x ]; then
    echo -n \!
fi
Err... if you want to check if there are differences, it would be
better to use '--quiet' (which implies '--exit-code') and check for
exit code instead of checking if there was any output.

BTW. there is slight inconsistency in using dashed (git-diff-index)
and dashless (git branch) of diff commands.  In "external" script
which does not source git shell script "library", it is better to use
dashless form.
 
# exit if no remote tracking branch found
if [ ${REMOTE}x == x -a ${MERGE}x == x ]; then
    echo ]
    exit
fi

# Uncomment this line to ignore remote tracking branches
# echo ]; exit

# calc number of revs between remote and local
FWDREVS=$(git rev-list $REMOTE/$MERGE..$BRANCH 2>/dev/null 2>&1 | wc -l)

# and the other way, in case it is not up to date
BACKREVS=$(git rev-list $BRANCH..$REMOTE/$MERGE 2>/dev/null 2>&1 | wc -l)

echo -n ' '-\> $REMOTE/$MERGE

if [ $FWDREVS -gt 0 ]; then
    echo -n +$FWDREVS
fi

if [ $BACKREVS -gt 0 ]; then
    echo -n -$BACKREVS
fi

echo ]
Why do you use sequence of "echo -n", instead of setting variables,
perhaps with the help of some more advanced constructs like in example
below, then using one "echo" to output it all?

-- >8 --
function _git_ps1()
{
	# 'git_dir' is absolute path to git repository
	# 'rel' is path relative to top dir in repository
	# 'br' is current branch name, or 'HEAD' if we are on detached HEAD
	local git_dir rel br

	# first call to git-rev-parse also checks if we are inside git
	# repository; if we are not in git repository, use default prompt,
	# provided as an argument
	rel=$(git rev-parse --show-prefix 2>/dev/null) || \
		{ echo "$@" ; return; }
	rel=${rel%\/}

	# get branch name, strip 'refs/heads/' prefix,
	# and use 'HEAD' for detached HEAD (no branch name)
	br=$(git symbolic-ref HEAD 2>/dev/null)
	br=${br#refs/heads/}
	br=${br:-HEAD}

	# path to top dir of git repository
	loc=${PWD%/$rel}

	# the following code is important only if you use StGit,
	# to note if you are on StGit controlled branch;
	# use second part of conditional if you don't use StGit
	git_dir=$(git rev-parse --git-dir)
	if [ "$br" -a -e "$git_dir/patches/$br" ]; then
		echo "$br:${loc/*\/}${rel:+/$rel}# "
	else 
		echo "$br:${loc/*\/}${rel:+/$rel}> "
	fi
}

## bash:
## set PS1 only if we are in interactive shell (PS1 is set)
#    [ "$PS1" ] && PS1='$(_git_ps1 "\u@\h:\w> ")'

## zsh:
#	function precmd() {
#		PS1=`_git_ps1 '%m:%~%# '`
#	}
# vim:filetype=sh

 
-- 
Jakub Narebski
Poland
ShadeHawk on #git
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help