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 it faster using builtins #9

Open
jart opened this issue Aug 26, 2015 · 5 comments
Open

Make it faster using builtins #9

jart opened this issue Aug 26, 2015 · 5 comments

Comments

@jart
Copy link

jart commented Aug 26, 2015

Nice PS1 hack. This is definitely the fanciest one I've seen for git. So I want to help you improve it.

My question is this: do blank lines appear in the terminal if you hold down the enter key? That means the time to optimize is now. The name of the game is to drive down latency so that never happens.

Here's some code I wrote for mine own .bashrc file that you can use. It uses bash builtins to determine the git root and the current branch. This way you only need like 5 or so system calls, rather than the 182 you'd need to run the git command: strace -f git symbolic-ref --short HEAD |& wc -l

I've found that this is really helpful not only from the user experience standpoint (fast is better than slow) but also in situations where IO gets pwnd or you run out of processes. git might not run at all and you need builtins to save the system.

The only tradeoff with these functions is that it leaves garbage files behind in /tmp. It's assumed that a cron job exists to purge those occasionally. /etc/cron.daily/tmpreaper comes standard on Debian systems.

# Caches last directory for which `jartps1_gitdir_find` failed.
export JARTPS1_GITDIR_TMP="$(mktemp --suffix=-jartps1-gitdir)"

################################################################################
# Swiftly determine name of current Git branch.
#
# Arguments:
#   None
# Returns:
#   0 on success, storing result to ${jartps1_gitbranch}.
#   1 if ${PWD} isn't inside a Git repo.
# Globals:
#   jartps1_gitbranch      - Used to store result.
################################################################################
jartps1_gitbranch_find() {
  if jartps1_gitdir_find; then
    local head
    if read head <"${jartps1_gitdir}/.git/HEAD" &>/dev/null; then
      if [[ "${head}" =~ refs/heads/(.+) ]]; then
        jartps1_gitbranch="${BASH_REMATCH[1]}"
      else
        jartps1_gitbranch="${head##*/}"
      fi
      if [[ "${jartps1_gitbranch}" != "" ]]; then
        return 0
      fi
    fi
  fi
  return 1
}

################################################################################
# Swiftly locate root of current Git repository.
#
# This is the fastest possible solution. Rather than the naïve approach of
# executing the git command (which could take hundreds of milliseconds), this
# routine launches no processes and only requires a few stat() system calls. In
# some cases it can avoid lookup or cache the result.
#
# Arguments:
#   dir                 - Optional, defaults to ${PWD}
# Returns:
#   0 on success, storing result to ${jartps1_gitdir}.
#   1 if dir isn't inside a Git repo.
# Globals:
#   jartps1_gitdir      - Used to store result.
#   JARTPS1_GITDIR_TMP  - Temp file used to cache last failed search.
################################################################################
jartps1_gitdir_find() {
  local dir="$1"
  if [[ -z "${dir}" ]]; then
    dir="${PWD}"
    case "${dir}" in
      /)                              return 1 ;;
      /home/${USER})                  return 1 ;;
    esac
    if [[ -f "${JARTPS1_GITDIR_TMP}" ]]; then
      local notgit
      if read notgit <"${JARTPS1_GITDIR_TMP}" &>/dev/null; then
        if [[ "${dir}" == "${notgit}" ]]; then
          return 1
        fi
      fi
    fi
  fi
  if [[ -d "${dir}/.git" ]]; then
    jartps1_gitdir="${dir}"
  else
    local parent="${dir%/*}"
    if [[ -z "${parent}" ]]; then
      printf "%s" "$PWD" >"${JARTPS1_GITDIR_TMP}"
      return 1
    fi
    jartps1_gitdir_find "${parent}"
  fi
}
@sjaveed
Copy link

sjaveed commented Aug 26, 2015

Nice! I've been using git symbolic-ref in my own PS1 which is a lot dumber than git-radar so this should come in handy for me. Thanks @jart!

Edit: bonus points for the ï in naïve :-)

@zx8
Copy link

zx8 commented Aug 26, 2015

Disclaimer: I'm not a git-radar user nor do I have problems with the responsiveness of my prompt, I was just browsing the project's issues out of curiosity after following a link from a friend!

Anyway, this bit needs to be revised, because / is a valid character in a branch name:

jartps1_gitbranch="${head##*/}"

Example:

$ head=release/1.0
$ echo "${head##*/}"
1.0

@jart
Copy link
Author

jart commented Aug 27, 2015

@zx8 Wow thanks for finding that bug. I updated the code in my original comment. PTAL?

I'm not 100% sure what the best approach is, since I don't know everything that could be contained in that file. So I tried to pick the safest heuristic possible.

@zx8
Copy link

zx8 commented Aug 27, 2015

Hmm, think you've overcomplicated it a bit, how about something simple like this:

$ h=refs/heads/release/1/2/3
$ echo ${h##refs/heads/}
release/1/2/3

@jart
Copy link
Author

jart commented Aug 27, 2015

@zx8 The ## syntax wouldn't work since the HEAD file contains ref: refs/heads/branch on my end. I guess I could just say ${h##ref: refs/heads/} though. But that would be more fragile without the simpler fallback. I imagine that HEAD file can contain all sorts of things. Like if you checkout a SHA1 ID, it won't have the ref:blahblah prefix; it'll just contain the hash.

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

No branches or pull requests

3 participants