I use git feature branches while working and when reviewing/integrating them into the main development branch I often need to quickly change between them a lot. Git offers a shortcut to jump to the last branch before the current one with:
$ git checkout -
That is certainly helpful, but what if I want to jump to the 2nd-last branch? Afaik there is no builtin function for that, but since git is really just a bunch of commandline utilities it is not that hard to write a wrapper with bash or Python that does what we want. All actions like switching branches are logged in a file named reflog; we can parse and analyze that file to detect the last n-branches.
alias gol=source ~/git_checkout_last_branches.sh
#!python
import re
import subprocess
import sys
REFLOG_LINES = 1000
MAX_RESULTS = 10
DEFAULT_CHECKOUT = 2 # AKA last branch before the current one.
regex = re.compile(r"checkout: moving from (?P<old>.+)? to (?P<new>.+)")
reflog = subprocess.check_output(["git", "reflog", "show", "-n",
str(REFLOG_LINES)])
last_branches = []
matches = regex.findall(reflog)
for origin, target in matches:
if origin not in last_branches:
last_branches.append(origin)
options = {}
for i, branch in enumerate(last_branches[:MAX_RESULTS]):
i += 1
options[i] = branch
print("{i}) {branch}".format(**locals()))
print("")
chosen = raw_input("Which branch do you want to checkout ({}): "
.format(DEFAULT_CHECKOUT))
if not chosen:
chosen = DEFAULT_CHECKOUT
try:
chosen = int(chosen)
except ValueError:
print("You must enter a number.")
sys.exit(1)
try:
branch = options[chosen]
except KeyError:
print("Incorrect index.")
sys.exit(1)
print(subprocess.check_output(["git", "checkout", branch]))
This will give us a simple prompt where we can select one of the last branches by specifying its index: The following script is a slightly more interactive version that uses a cool package named asker to choose an option with the arrow keys. It also supports filtering the list by typing some characters ($ pip install asker).
alias gol=source ~/git_checkout_last_branches_v2.sh
#!python
import re
import subprocess
import sys
from asker import ask
REFLOG_LINES = 1000
regex = re.compile(r"checkout: moving from (?P<old>.+)? to (?P<new>.+)")
reflog = subprocess.check_output(["git", "reflog", "show", "-n",
str(REFLOG_LINES)])
last_branches = []
matches = regex.findall(reflog)
for origin, target in matches:
if origin not in last_branches:
last_branches.append(origin)
options = {}
for i, branch in enumerate(last_branches[:10]):
i += 1
options[i] = branch
choice = ask("Which branch do you want to checkout? ",
choices=options.values(),
labels=options.values())
print(subprocess.check_output(["git", "checkout", choice]))
This is what we get: