Compare commits

...

46 commits

Author SHA1 Message Date
Paul Irish 3f6b498667
ci: set up npm trusted publishing (OIDC) 2026-04-27 08:42:46 -07:00
Paul Irish aa19c34401
2.2.0 2026-04-27 08:40:57 -07:00
Paul Irish 3b429ea804
Merge branch 'master' of github.com:paulirish/git-recent 2026-04-27 08:40:25 -07:00
Paul Irish d23d325693
easy worktree switching (#37) 2026-04-27 08:39:26 -07:00
Paul Irish 724f48ca79
cleaner diff base cmd 2026-03-29 12:05:27 -07:00
Paul Irish cdffe4c40a 2.1.0 2025-10-25 11:59:25 -07:00
Paul Irish bd0ad4207d
commit listing should include full commit message body (#35) 2025-10-25 11:58:11 -07:00
Paul Irish 2e5e69fe30
Merge remote-tracking branch 'refs/remotes/origin/master' 2025-07-04 12:28:51 -07:00
Paul Irish 6b98834931
todo 2025-07-04 12:27:46 -07:00
Paul Irish 6322cde317 2.0.4 2025-07-04 11:26:14 -07:00
Paul Irish 479bc17a4a adapt cmds to be more cross-shell compatible 2025-07-01 11:50:28 -07:00
Paul Irish d892c4bbf2
2.0.3 2025-06-27 14:06:22 -07:00
Paul Irish 73e40691c6
chromium cl status integration (#33) 2025-06-27 14:05:51 -07:00
Paul Irish d5f63cf328
early exit if not in repo. thx @pickx. closes #32 2025-06-14 12:52:41 -07:00
Paul Irish 34af71aef0
readme update 2025-06-14 12:49:02 -07:00
Paul Irish 5af5ff70c8
homebrew formula 2025-06-14 12:10:05 -07:00
Paul Irish 959e8343da
2.0.2 2025-06-14 12:08:53 -07:00
Paul Irish 6b628b190c
add GIT_RECENT_QUERY env for testing 2025-06-14 12:01:37 -07:00
Paul Irish fbb93ae381
diff_base note. #28 2025-04-15 10:58:09 -07:00
Paul Irish aa46ef3070
ctrl-y to copy branch name to clipboard (#30) 2025-04-15 10:32:14 -07:00
Paul Irish 1bf0581139 extra arg for listing a remote's branches. still not sure about this 2025-02-13 16:18:14 -08:00
Paul Irish 6bd7ff3fdf
grab HEAD branch of origin (main, master) more reliably 2025-02-11 07:59:29 -08:00
Paul Irish bfda73056b
2.0.1 2025-02-06 19:34:47 -08:00
Paul Irish 1c233e995c
Drop fzf-tmux for plain fzf. The popup just complicated it, so I never used it 2025-02-06 19:34:40 -08:00
Paul Irish b324fc2e4a
2.0.0 2025-02-06 17:41:37 -08:00
Paul Irish 8237f19b10
package.json for npm publish 2025-02-06 17:39:04 -08:00
Paul Irish e8a0560e05
Merge pull request #26 from paulirish/two-oh-prep
git recent 2.0
2025-02-06 17:32:41 -08:00
Paul Irish de576427fa
update readme for 2.0. use progressive enhancement for diff pager util 2025-02-06 17:29:27 -08:00
Paul Irish b55a2e4217
rename new to git-recent 2025-02-06 13:27:08 -08:00
Paul Irish 8d19748426
Move git-recent-og 2025-02-06 13:24:41 -08:00
Paul Irish fd0275f148
update summary 2025-02-06 11:46:45 -08:00
Paul Irish 938db7514f
authordate preferred 2025-02-06 11:22:18 -08:00
Paul Irish d2e08436da standalone and checkout works great now 2024-06-07 12:25:20 -07:00
Paul Irish 9d13948f50 recent with fzf tweak 2024-04-25 09:19:34 -07:00
Paul Irish 03cf5a320e rename. invoking this with a git alias now 2024-02-27 15:44:13 -08:00
Paul Irish cfd00de858 add fzf powered git browse. incl all of git recent and trigger for diffbranch 2024-02-22 11:18:33 -08:00
Paul Irish 8d67039988 denser 2024-02-22 11:07:14 -08:00
Paul Irish 1985391134 v1.1.1 2019-06-20 20:20:30 -07:00
Tim 09848b42e5 Handle new git behavior requiring count parameter (#19) 2019-06-20 20:19:17 -07:00
Paul Irish a7ae3198bd v1.1.0 2018-10-11 11:35:28 -07:00
Kevin Ramsunder 514bf95d27 Add count parameter (-n) (#12) 2018-10-11 11:34:55 -07:00
Paul Irish 8beb4ddc42
readme: install with homebrew 2018-04-20 09:48:18 -07:00
Daniel Liuzzi 68acec4862 Target both 32-bit & 64-bit MinGW (#17) 2018-04-20 09:29:24 -07:00
Paul Irish 89e81a1437 v1.0.4 2018-03-02 17:51:00 -08:00
Paul Irish 8c06e77f56 force color on. 2018-03-02 17:50:46 -08:00
Amila Welihinda a2ab14c618 Added MIT LICENSE (#14) 2017-04-20 02:26:59 -07:00
9 changed files with 533 additions and 57 deletions

24
.github/workflows/publish.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Publish to npm
on:
workflow_dispatch: # Allow manual triggering
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read # Required for checkout
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22.14.0
registry-url: 'https://registry.npmjs.org'
- name: Publish to npm
run: |
npm install -g npm@latest
npm publish --provenance --access public --registry https://registry.npmjs.org/

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Paul Irish
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,47 +1,147 @@
#!/bin/bash
##
## git-recent
##
## list all local branches, sorted by last commit, formatted reall purdy
##
#
# git recent 2.0 - switching branches, but so fancy
#
# - view recently edited local branches
# - see unique commits to that branch, and optionally the branch diff (against the main/master/primary branch) with Ctrl-o
# - hit Enter to checkout the selected branch.
# - text filtering against branch names, too.
#
# Windows needs more basic format (#8, git-for-windows/git#865)
case $(uname -s) in
CYGWIN*|MINGW32*|MSYS*)
branch='%(refname:short)'
spacer=' '
;;
*)
branch='%(color:yellow)%(refname:short)%(color:reset)'
spacer='%(color:black) %(color:reset)'
;;
esac
if ! command -v fzf >/dev/null 2>&1; then
echo "Error: fzf is not installed. Please install fzf to use git-recent." >&2
exit 1
fi
[ "$(git rev-parse --is-inside-work-tree)" = "true" ] || exit
format="\
%(HEAD) \
$branch|\
%(color:bold red)%(objectname:short)%(color:reset) \
%(color:bold green)(%(committerdate:relative))%(color:reset) \
%(color:bold blue)%(authorname)%(color:reset) \
%(color:yellow)%(upstream:track)%(color:reset)
$spacer|\
%(contents:subject)
$spacer|"
if [[ "$1" == "--help" ]]; then
echo "git-recent: Browse and checkout recently used Git branches."
echo
echo "Keybindings:"
echo " Enter: Checkout the selected branch (or jump to its worktree if open elsewhere)"
echo " Ctrl-O: Show the diff of the selected branch against the main/master branch"
echo " Ctrl-C: Exit"
exit 0
fi
lessopts="--tabs=4 --quit-if-one-screen --RAW-CONTROL-CHARS --no-init"
# ---------------------------------------------------------------------------------------
git for-each-ref \
--sort=-committerdate \
"refs/heads/" \
--format="$format" \
| column -ts '|' \
| less "$lessopts"
# The HEAD of the primary branch (eg main or master or w/e), for diffing.
# TODO: some branch mgmt approaches don't work well with this. And may prefer `git log --pretty=format:%H --merges -n 1`. See https://github.com/paulirish/git-recent/issues/28
diff_base=$(git symbolic-ref refs/remotes/origin/HEAD)
# The above command:
# for all known branches,
# sort descending by last commit
# show local branches (change to "" to include both local + remote branches)
# apply the formatting template above
# break into columns
# use the pager only if there's not enough space
# Extract branch name (without any trailing text, like the Chromium link)
define_branchname="branchname=\\\$(echo {1} | cut -d' ' -f1)"
# Colorized hash, author, date, then commit subject followed by commit message body (wrapped and indented).
commits_format="%C(red bold)%h %C(bold blue)%an %C(bold green)%ad %Creset%s%w(0,4,4)%+b%w(0,0,0)"
uniqcommits_cmd="sh -c \"$define_branchname; git log --date=human --color=always --format='$commits_format' --no-merges $diff_base..\\\$branchname\""
# Progressive enhancement if you have delta or diff-so-fancy
diff_pager_cmd=$(command -v delta || command -v diff-so-fancy)
pipe_to_pager=${diff_pager_cmd:+" | $diff_pager_cmd"}
diffbranch_cmd="sh -c \"$define_branchname; git diff --color=always $diff_base...\\\$branchname $pipe_to_pager\""
# Copy to clipboard, variants for mac/linux
copy_cmd="echo 'Could not copy {} to clipboard.'"
if command -v pbcopy >/dev/null; then
copy_cmd="printf '%s' {} | pbcopy"
elif command -v wl-copy >/dev/null; then
copy_cmd="printf '%s' {} | wl-copy"
elif command -v xclip >/dev/null; then
copy_cmd="printf '%s' {} | xclip -selection clipboard"
elif command -v xsel >/dev/null; then
copy_cmd="printf '%s' {} | xsel --clipboard"
fi
_get_worktree_for_branch() {
local branch="$1"
local current_toplevel
current_toplevel=$(git rev-parse --show-toplevel 2>/dev/null)
# Find the worktree path for the given branch, excluding the current one.
# Using substr to handle paths with spaces correctly.
git worktree list --porcelain | awk -v target="refs/heads/$branch" -v current="$current_toplevel" '
/^worktree / { wt = substr($0, 10) }
/^branch / && $2 == target {
if (wt != current) {
print wt
exit
}
}
'
}
YELLOW='\033[0;33m'
DIM='\033[2m'
NC='\033[0m' # No Color
# if show_cl passed then also run git cl status. (chromium repos)
[[ "$1" == "--cl" || "$1" == "-cl" ]] && show_cl=true || show_cl=false
# if extra arg passed (eg `git recent remotename`), then list those remote branches, rather than local ones
[[ -n "$1" && "$show_cl" != true ]] && heads="refs/remotes/$1" || heads="refs/heads"
# fzf git inspiration:
# - https://github.com/junegunn/fzf/wiki/Examples#git
# - https://github.com/junegunn/fzf/wiki/Examples-(fish)#git
# - https://github.com/junegunn/fzf-git.sh (intense.)
# If there's a GIT_RECENT_QUERY environment variable, use it for non-interactive filtering. (Primarily added for testing: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/g/git-recent.rb#L41-L46)
filterarg=${GIT_RECENT_QUERY:+"--filter=$GIT_RECENT_QUERY"}
# Chromium hackers may want reference to their relevant CL.
CL_STATUS=$([ "$show_cl" = true ] && git cl status --fast --no-branch-color | grep 'https://' | sed 's| (.*||')
# List of branches currently checked out in any worktree (including the current one)
WT_BRANCHES=$(git worktree list --porcelain | grep "^branch " | sed 's|^branch refs/heads/||')
_browse_branches() {
git for-each-ref --sort=-authordate "$heads" --format="%(refname:short)" \
| while read -r branch_name; do
wt_symbol=""
if echo "$WT_BRANCHES" | grep -qFx "$branch_name"; then
wt_symbol=" ⇶"
fi
if [ "$show_cl" != true ]; then
printf "$YELLOW%s$DIM%s$NC\n" "$branch_name" "$wt_symbol"
continue
fi
review_url=$(echo "$CL_STATUS" | grep -E "\b${branch_name} :" | grep -o -E 'https://.*' | sed 's|https://||')
# Using fancy integrated hyperlinks: https://iterm2.com/feature-reporting/Hyperlinks_in_Terminal_Emulators.html
# TODO: maybe get rid of the crrev.com/c/ text as the link?
# TODO: use `git config branch.$(git rev-parse --abbrev-ref HEAD).gerritissue` and gerritserver to avoid using `git cl status`
printf "$YELLOW%s$DIM%s \033]8;;%s\a%s\033]8;;\a$NC\n" "$branch_name" "$wt_symbol" "https://$review_url" "$review_url"
done \
| fzf \
$filterarg --ansi -- --layout=reverse --multi --height=90% --min-height=20 \
--border-label-pos=2 --border-label '🌲 Branches' --border \
--no-hscroll --no-multi \
--preview-window='right,70%,border-left,border-rounded' --preview="$uniqcommits_cmd" --preview-label="Commits unique to branch" \
--header $'ENTER (checkout)\nCTRL-O (show branch diff)\nCTRL-Y (copy name to clipboard)' \
--bind 'preview-scroll-up:preview-up+preview-up+preview-up' \
--bind 'preview-scroll-down:preview-down+preview-down+preview-down' \
--bind "ctrl-y:execute-silent($copy_cmd)" \
--bind "ctrl-o:preview:$diffbranch_cmd"
}
output="$(_browse_branches)"
line_count=$(printf "%s" "$output" | wc -l)
if [[ -n "$output" ]] && (( line_count == 0 )); then
chosen_branch=$(echo "$output" | cut -d' ' -f1)
wt_path=$(_get_worktree_for_branch "$chosen_branch")
if [[ -n "$wt_path" ]]; then
echo "Branch '$chosen_branch' is open in worktree: $wt_path" >&2
echo "$wt_path"
else
echo "git checkout $chosen_branch" >&2
git checkout "$chosen_branch"
fi
else
echo "$output"
fi

62
git-recent-og Executable file
View file

@ -0,0 +1,62 @@
#!/bin/bash
##
## git-recent
##
## list all local branches, sorted by last commit, formatted reall purdy
##
# Windows needs more basic format (#8, git-for-windows/git#865)
case $(uname -s) in
CYGWIN*|MINGW*|MSYS*)
branch='%(refname:short)'
;;
*)
branch='%(color:yellow)%(refname:short)%(color:reset)'
;;
esac
COUNT=0
while getopts "n:" opt; do
case ${opt} in
n )
if ! [[ $OPTARG =~ ^[0-9]{1,}$ ]]; then
echo "-n should be an integer."
exit 1
fi
COUNT=${OPTARG}
shift
;;
esac
done
shift $((OPTIND-1))
format="\
%(HEAD) \
$branch|\
%(color:bold red)%(objectname:short)%(color:reset) \
%(color:bold green)(%(committerdate:relative))%(color:reset) \
%(color:bold blue)%(authorname)%(color:reset) \
%(color:yellow)%(upstream:track)%(color:reset) \
%(contents:subject)"
lessopts="--tabs=4 --quit-if-one-screen --RAW-CONTROL-CHARS --no-init"
git for-each-ref \
--color=always \
--count=$COUNT \
--sort=-committerdate \
"refs/heads/" \
--format="$format" \
| column -ts '|' \
| less "$lessopts"
# The above command:
# for all known branches,
# (force coloring on this, especially since it's being piped)
# optionally, specify the number of branches you want to display
# sort descending by last commit
# show local branches (change to "" to include both local + remote branches)
# apply the formatting template above
# break into columns
# use the pager only if there's not enough space

144
git-watch Executable file
View file

@ -0,0 +1,144 @@
#!/bin/bash
#
# git-watch: A streaming perspective of git changes and commits.
#
# Monitors the current repository for:
# - New commits (displays 'git show')
# - Working directory & index changes (displays 'git diff HEAD' and untracked files)
#
# Requires 'watchexec' for responsiveness.
#
# Check if we're in a git repo
[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = "true" ] || {
echo "Error: Not a git repository." >&2
exit 1
}
# Check for dependencies
if ! command -v watchexec >/dev/null 2>&1; then
echo "Error: 'watchexec' is required for git-watch. Please install it (e.g., 'brew install watchexec')." >&2
exit 1
fi
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
echo "git-watch: A streaming perspective of git changes and commits."
echo
echo "Usage: git-watch [--debug]"
echo
echo "Options:"
echo " --debug Log what would be run instead of running it"
echo
echo "Features:"
echo " - Shows 'git show' on new commits"
echo " - Shows 'git diff HEAD' on working tree/index changes"
echo " - Uses 'watchexec' for high-speed responsiveness"
echo " - Uses your fancy pager (delta/diff-so-fancy) without blocking"
exit 0
fi
DEBUG_MODE=false
if [[ "$1" == "--debug" || "$2" == "--debug" ]]; then
DEBUG_MODE=true
fi
# Pager detection (compatible with delta, diff-so-fancy, etc.)
pager_cmd=$(command -v delta || command -v diff-so-fancy)
if [ -n "$pager_cmd" ]; then
if [[ "$pager_cmd" == *"delta"* ]]; then
pager_cmd="$pager_cmd --paging=never"
fi
pipe_to_pager=" | $pager_cmd"
fi
git_run() {
if [ "$DEBUG_MODE" = true ]; then
echo -e "\033[0;35m[DEBUG] Would run: git --no-pager \"$@\" --color=always$pipe_to_pager\033[0m"
return
fi
eval "git --no-pager \"\$@\" --color=always$pipe_to_pager"
}
# Cross-platform hashing for change detection
hash_cmd=$(command -v shasum || command -v sha1sum || echo "cksum")
update() {
local mode="$1"
local git_dir state_file
git_dir=$(git rev-parse --git-dir 2>/dev/null)
[ -n "$git_dir" ] || return
state_file="$git_dir/watch-state"
local current_head last_head current_state_hash last_state_hash
current_head=$(git rev-parse HEAD 2>/dev/null)
# Capture status and diff for hashing (ignoring untracked files for now)
local status_output=$(git status --porcelain --untracked-files=no)
local diff_output=$(git diff HEAD 2>/dev/null)
# TODO: Re-evaluate untracked file support later.
current_state_hash=$( (echo "$status_output"; echo "$diff_output") | $hash_cmd | cut -d' ' -f1)
if [[ -f "$state_file" && "$mode" != "--initial" ]]; then
read -r last_head last_state_hash < "$state_file"
fi
if [ "$DEBUG_MODE" = true ]; then
echo -e "\033[0;35m[DEBUG] Mode: $mode\033[0m"
echo -e "\033[0;35m[DEBUG] HEAD: $current_head (Last: ${last_head:-NONE})\033[0m"
echo -e "\033[0;35m[DEBUG] State Hash: $current_state_hash (Last: ${last_state_hash:-NONE})\033[0m"
fi
local did_something=false
# 1. Commit detection
if [[ "$current_head" != "$last_head" || "$mode" == "--initial" ]]; then
echo -e "\n\033[1;34m=== Current Commit: $(git log -1 --format='%h %s' 2>/dev/null) ===\033[0m"
git_run show --summary --stat -p
did_something=true
fi
# 2. Working directory detection
if [[ "$current_state_hash" != "$last_state_hash" || "$mode" == "--initial" ]]; then
if [[ -n "$status_output" ]]; then
echo -e "\n\033[1;32m=== Changes ===\033[0m"
# Show diff of tracked changes
if [[ -n "$diff_output" ]]; then
git_run diff HEAD
fi
# TODO: Implement surgical untracked file support here if needed.
did_something=true
fi
fi
# Update state so we don't repeat this in the next --step
if [[ "$did_something" == "true" ]]; then
if [ "$DEBUG_MODE" = true ]; then
echo -e "\033[0;35m[DEBUG] Would update state file: $current_head $current_state_hash\033[0m"
else
echo "$current_head $current_state_hash" > "$state_file"
fi
fi
}
# Internal flag for watchexec to call back into the script
if [[ "$1" == "--step" ]]; then
update "--step"
exit 0
fi
# Main execution loop
update "--initial"
pass_debug=""
if [ "$DEBUG_MODE" = true ]; then
pass_debug="--debug"
fi
echo -e "\033[0;32mWatching with watchexec...\033[0m"
# --postpone: don't run immediately on start (we already did update --initial)
# --quiet: suppress watchexec status messages
# exec is used so that Ctrl-C goes directly to watchexec and terminates the session
exec watchexec --quiet --postpone -i .git -w . -w "$(git rev-parse --git-dir)/HEAD" -- "$0" --step $pass_debug

41
man/man1/git-recent.1 Normal file
View file

@ -0,0 +1,41 @@
.TH GIT-RECENT 1 "February 8, 2025" "git-recent 2.0"
.SH NAME
git recent \- Browse and checkout recently used Git branches.
.SH SYNOPSIS
.B git recent
.SH DESCRIPTION
.B git recent
provides an interactive interface (using
.I fzf
) to browse your latest local git branches. It displays a list of branches sorted by recency, shows the unique commits for each branch, and allows you to checkout a branch with
.B Enter\fR.
You can also view the diff of a branch against the main/master branch.
.SH OPTIONS
.TP
.B --help
Display a help message.
.SH KEYBINDINGS
.TP
.B Enter
Checkout the selected branch. If the branch is already open in a separate git worktree, the script will output the path to jump there. (See README for automatic switching via a small shell wrapper).
.TP
.B Up/Down arrow keys
Navigate the branch list.
.TP
.B Type
Filter branch list with fuzzy text matching
.TP
.B Ctrl-o
Show the diff of the selected branch against the main/master branch.
.TP
.B Ctrl-C
Exit.
.SH INSTALLATION
.I fzf
is required. https://junegunn.github.io/fzf/installation/
.SH SEE ALSO
.I fzf(1), git(1), git-open(1), diff-so-fancy(1), delta(1)
.br
.I git-recent-og
(for the non-fzf version)

17
package-lock.json generated Normal file
View file

@ -0,0 +1,17 @@
{
"name": "git-recent",
"version": "2.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "git-recent",
"version": "2.2.0",
"license": "MIT",
"bin": {
"git-recent": "git-recent",
"git-recent-og": "git-recent-og"
}
}
}
}

View file

@ -1,16 +1,18 @@
{
"name": "git-recent",
"version": "1.0.3",
"description": "List recent git branches, formatted so fancy",
"version": "2.2.0",
"description": "List recent git branches, select one for checkout. See branch commits and diffs, all formatted so fancy",
"bin": {
"git-recent": "git-recent"
"git-recent": "git-recent",
"git-recent-og": "git-recent-og",
"git-watch": "git-watch"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/paulirish/git-recent.git"
"url": "https://github.com/paulirish/git-recent"
},
"keywords": [
"git",

View file

@ -1,24 +1,87 @@
# git-recent
# git recent
Type `git recent` to see your latest local git branches
Speedily browse your latest local git branches, `checkout` with Enter. Also view branches unique commits, and optionally the diff against main.
## Usage
[Demo video of git recent 2.0](https://github.com/user-attachments/assets/441f0b9b-8469-41bd-a826-0bb0cd7c7de8)
`git recent` now offers an interactive UI (thx to [fzf](https://github.com/junegunn/fzf)) for browsing recent branches, seeing differences, and `checkout`'ing your selection.
See a diff of your branch vs main with `ctrl-o`. If you have [delta](https://dandavison.github.io/delta//) it'll use that for formatting, but will fallback, too.
If you're like me, mostly using classic git commands, then `git recent` provides a nice upgrade for browsing/selecting recent branches. But if you're a TUI fan using [git-fuzzy](https://github.com/bigH/git-fuzzy), [`lazygit`](https://github.com/jesseduffield/lazygit) or [`tig`](https://jonas.github.io/tig/) or [`fzf-git`](https://github.com/junegunn/fzf-git.sh), well… this probably isn't an upgrade. :p (But you can certainly [read the source](/git-recent) quickly!)
### Installation
`fzf` is required for 2.0. TBH, it's a fantastic tool; those [shell key bindings](https://junegunn.github.io/fzf/shell-integration/) are _delightful_. That said, if you're dependency-averse, the older version below, [`git recent-og`](#git-recent-og), may be for you.
* Mac: `brew install fzf`
* Linux: `sudo apt-get install fzf`
* Windows: `choco install fzf`
Then, do one of these:
* Manual: Grab the `git-recent` script from this repo and put it anywhere in your `$PATH`. Run `chmod +x git-recent`.
* Via NPM: `npm install --global git-recent`
* Homebrew: `brew install git-recent`
<!-- homebrew formula: https://github.com/Homebrew/homebrew-core/blob/master/Formula/g/git-recent.rb -->
### Usage
git recent
Hit `Enter` to checkout the selected branch.
![git-recent screenshot](https://cloud.githubusercontent.com/assets/39191/17446638/039d4cee-5aff-11e6-9e11-4294f0020513.png)
Type or use arrow keys to navigate your list of branches.
Hit `ctrl-o` to see the branch diff.
#### Worktree Support
If a branch is already open in a separate git worktree, `git recent` will detect it and provide instructions to `cd` there. To enable **automatic** directory switching, add one of these wrapper functions to your shell config:
##### Bash / Zsh (in `.bashrc` or `.zshrc`)
```bash
recent() {
local o=$(command git-recent "$@")
[ -d "$o" ] && cd "$o" || [ -n "$o" ] && echo "$o"
}
```
##### Fish (in `~/.config/fish/config.fish`)
```fish
function recent
set -l o (command git-recent $argv)
if test -d "$o"
cd $o
else if test -n "$o"
echo $o
end
end
```
--------------------------------
# `git recent-og`
`git recent-og` is the [OG](https://www.urbandictionary.com/define.php?term=OG) `git recent`, released back in 2016. Now it's been renamed to `git recent-og`.
git recent-og
Optionally, add `-n<int>` to see the most recent `<n>` branches
git recent-og -n5
![git-recent-og screenshot](https://cloud.githubusercontent.com/assets/39191/17446638/039d4cee-5aff-11e6-9e11-4294f0020513.png)
If you're a Windows user, you need to use [Git Bash](https://git-scm.com/downloads) or similar shell in order to effectively use this utility.
### Installation
You can add the `git-recent` location to your path (e.g. add the directory to your `PATH` environment
or copy `git-recent` into an existing included path like `/usr/local/bin` or `~/bin/`).
Install with `npm` or `brew` as above, or copy `git-recent-og` script into an existing path like `/usr/local/bin` or `~/bin/`.
You can use also `npm` to install the global binary:
npm install --global git-recent
----------
## If you like this you may also be interested in...
@ -29,8 +92,10 @@ You can use also `npm` to install the global binary:
Copyright Paul Irish. Licensed under MIT.
## Changelog
- **2016-05-16** - added to [paulirish/dotfiles](https://github.com/paulirish/dotfiles/commit/1ca1ff760832af558447145fa2a367046b1829d2)
- **2016-08-05** - released in standalone repo and published to npm
- **2025-02** - 2.0 upgrade with fzf integration. 1.0 binary is now available as `git recent-og`.
- **2019-06** - Last bugfix for 1.0 landed. Been stable since then.
- **2018-10** - Added count `-n` parameter
- **2016-08** - released in standalone repo and published to npm
- **2016-05** - added to [paulirish/dotfiles](https://github.com/paulirish/dotfiles/commit/1ca1ff760832af558447145fa2a367046b1829d2)