Skip to content

Instantly share code, notes, and snippets.

@mgaitan
Last active February 7, 2024 05:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mgaitan/ba1e4e252b90a7fd4a4eb9e1742e94fb to your computer and use it in GitHub Desktop.
Save mgaitan/ba1e4e252b90a7fd4a4eb9e1742e94fb to your computer and use it in GitHub Desktop.
List or checkout recently used branches in git
#!/usr/bin/env python3
"""
List the most recent branches you have been working on, and switch any of them.
# Install
Put this file somewhere in your PATH, and set execution permissions.
Git will recognize it as the "recent-branches" subcommand.
# Usage
Without positional argument, it shows the 10 most recently used branches.
You can pass -n <number> to see more.
$ git recent-branches
1 - feature/EN-634
2 - feature/en-583_3
3 * master
4 - HOTFIX/spotify
5 - tests_factories
6 - feature/en-583_2
7 - _prod/workers/orders_py3
8 - prueba
9 - _prod/workers/products_py3
10 - staging
Passing a number will checkout the branch listed in that position.
$ git recent-branches 5
Switched to branch 'tests_factories'
Your branch is up to date with 'origin/tests_factories'.
If `git sw` ("smart switch" command) is available, it will be used. Otherwise, standard `git switch` will be tried.
See also https://gist.github.com/mgaitan/d9a3523d79cd5f9fbfd626f646f0560b
Note: In the list, the row with "*" (instead "-") is the current branch.
"""
import argparse
import re
import subprocess
from collections import OrderedDict
pattern = re.compile(r"checkout: moving from ([A-Za-z0-9_\/\-\.]+) to")
parser = argparse.ArgumentParser(prog="git recent-branches", description=__doc__.split("\n")[1])
parser.add_argument("index", type=int, nargs="?", help="Move to the i-th branch in the list")
parser.add_argument("command", nargs="*", help="If given, run commands after switching and return to the current branch")
parser.add_argument("--limit", "-n", type=int, default=10, help="Show until the n-th branch")
parser.add_argument("--force", "-f", action="store_true", help="Force checkout")
args = parser.parse_args()
output = subprocess.check_output(["git", "reflog"], text=True)
branches = list(OrderedDict.fromkeys(re.findall(pattern, output)).keys())
def switch_branch(branch_name, force=False):
use_sw = subprocess.call(["git", "sw"], stderr=subprocess.DEVNULL) == 2 and not force
cmd = ["git", "sw" if use_sw else "switch"]
if force:
cmd.append("-f")
cmd.append(branch_name)
subprocess.call(cmd)
current_branch = subprocess.check_output(["git", "branch", "--show-current"], text=True).strip()
if args.index:
target_branch = branches[args.index - 1]
# Switch to the target branch
switch_branch(target_branch, args.force)
# Execute the extra command if provided
if args.command:
subprocess.call(" ".join(args.command), shell=True)
# Switch back to the original branch
switch_branch(current_branch, args.force)
else:
for i, branch in enumerate(branches[: args.limit], 1):
print(f"{i} {'*' if current_branch == branch else '-'} {branch}")
@pzelnip
Copy link

pzelnip commented May 14, 2019

Love this idea, would be nice to have a way to say only show the top n branches. Ie something like:

git-recent-branches -n 5

to show the 5 most recent, rather than always show all. I have a few repos I interact with where there's a large number of branches, but only interact with a small handful.

@mgaitan
Copy link
Author

mgaitan commented Jul 24, 2019

@pzelnip, thanks for the idea. I've just implemented it, with a default to top 10 most recently used branches

@pzelnip
Copy link

pzelnip commented Jul 24, 2019

Nice!

@mgaitan
Copy link
Author

mgaitan commented May 12, 2022

@alvarmaciel
Copy link

I forked and added it to ask to switch branch
https://gist.github.com/alvarmaciel/884660733fdb7c6ad9603ceb23d239ca

@iamaamir
Copy link

iamaamir commented Feb 7, 2024

why not simply use fzf

git switch `git branch | fzf| tr -d '[:space:]'`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment