My day job requires working across multiple repositories. Often more than one repository needs to be on the same branch when I’m working on a feature.
Tangentially, I use tmux and tmuxinator to have a window for each repository and some for monitoring, etc. I often jump between windows (i.e. repositories) and see the active git branch from the command line (I use ohmyzsh with the ys theme).
Install on Mac:
brew install newt
Script (step by step)
1
2
3
4
# list of repository rootspaths=(# todo: add your repositories here)
Here you should add absolute path to repository roots, i.e. "/home/ally/development/ac-website".
6
7
# from the repository roots we will get the branch namedeclare -A branches=()
The declare will create a variable named branches, the -A designates this as an associative array/hashmap. We will use this to store the active branch for the repository root.
9
10
11
12
13
# populate repository roots branchesfor p in "${paths[@]}"; do k="$(basename "$p")" branches[$k]="$(git -C "$p" branch --show-current)"done
Next we will do some calculations to determine size of the whipatail radio list.
Note: this has zshisms, ${(@k)branches[*]} is different to bash syntax (to list the keys of the array, in bash I believe you would substitute with ${!branches[*]}).
Highlighted lines will (not in a bulletproof manner):
split words (i.e. branches or repository root) into separate lines
print the length of each word
sort the lines (word lengths) in reverse numeric order, i.e. descending (the highest first, the lowest last)
get the first line, i.e. the highest number
23
24
25
26
27
28
29
30
# make the command (trailing space for concatenating tag item status tuplescmd="whiptail \
--title=\"Repository branches\" \
--backtitle=\"Relevant repository branches\" \
--ok-button=\"Change Window\" \
--cancel-button=\"Ok\" \
--radiolist \"Repository branches\" \
$height$width$items "
The above might not be syntactically correct (I split across lines for readability).
We will concatenate the tuples for the radio list items.
These come in the format: "tag" "item" status.
32
33
34
35
36
37
38
39
for p in "${(k)paths[@]}"; do tag="$(basename "$p")" item="${branches[$tag]}" cmd+="\"$tag\" " cmd+="\"$item\" " cmd+="OFF "done
Note: this has zshisms, ${(@k)paths[@]} is different to bash syntax (to list the keys of the array, in bash I believe you would substitute with ${!paths[@]}).
I tried to iterate through $branches instead of $paths, but for some reason they were in some random order.
41
42
43
# finish the commandcmd+="3>&1 1>&2 2>&3"answer=$(eval "$cmd")
The 3>&1 1>&2 2>&3 is to grab stderr where the answer if chosen (the tag of the radio list item tuple) is outputted from whiptail without printing to screen.
Using eval is not ideal, but I found it was required.
The following is tmux specific things based on the answer to switch windows.
45
46
47
48
49
50
51
52
53
54
55
if[[ $TERM_PROGRAM =="tmux"]]; thenif[["$answer"=="ac-website"]]; then tmux select-window -t 0elif[["$answer"=="ac-skills"]]; then tmux select-window -t 1else echo "not sure how to handle this answer in tmux"fielse echo "not in tmux, not changing window"fi
Screenshots
With tmux
List of all repositories in your list and the active branch:
Select a branch (or choose Ok to close):
Will change to defined window if in tmux (trust me it does it):
#!/usr/bin/env zsh
# list of repository rootspaths=(# todo: add your repositories here)# from the repository roots we will get the branch namedeclare -A branches=()# populate repository roots branchesfor p in "${paths[@]}"; do k="$(basename "$p")" branches[$k]="$(git -C "$p" branch --show-current)"doneitems="${#paths[@]}"height=$((items *2))# calculate width of box depending on repository and branch namesw_repo=$(echo "${(@k)branches[*]}" | tr " ""\n" | awk '{ print length($0) }' - | sort -rn | head -n1)w_branch=$(echo "${branches[*]}" | tr " ""\n" | awk '{ print length($0) }' - | sort -rn | head -n1)width=$((w_repo + w_branch +15))# make the command (trailing space for concatenating tag item status tuplescmd="whiptail \
--title=\"Repository branches\" \
--backtitle=\"Relevant repository branches\" \
--ok-button=\"Change Window\" \
--cancel-button=\"Ok\" \
--radiolist \"Repository branches\" \
$height$width$items "# https://unix.stackexchange.com/a/150041/265713for p in "${(k)paths[@]}"; do tag="$(basename "$p")" item="${branches[$tag]}" cmd+="\"$tag\" " cmd+="\"$item\" " cmd+="OFF "done# finish the commandcmd+="3>&1 1>&2 2>&3"answer=$(eval "$cmd")if[[ $TERM_PROGRAM =="tmux"]]; thenif[["$answer"=="ac-website"]]; then tmux select-window -t 0elif[["$answer"=="ac-skills"]]; then tmux select-window -t 1else echo "not sure how to handle this answer in tmux"fielse echo "not in tmux, not changing window"fi