01 / 06
repo
移動 / 選択zsh/repo.zsh依存: fzf
ABOUT
fzf でリポジトリを選んで一撃で cd する。worktree があればブランチまで選べる。
WORK_DIR(既定: ~/Documents)配下を最大 4 階層まで走査して Git リポジトリを列挙し、fzf で選んで cd する。候補は TTL 付き(既定 300 秒)でキャッシュされるので 2 回目以降は即座に開く。選んだリポジトリに複数の worktree がある場合は第 2 段階としてブランチ選択に進む。クエリを渡すと部分一致で絞り込み、1 件だけなら fzf を省略して直行する。移動履歴は ~/.repo_history に追記される。
USAGE
repo [--refresh] [work_dir] [query]
OPTIONS
- --refresh
- キャッシュ(TTL 300 秒)を破棄して WORK_DIR を再走査する
- work_dir
- 走査するディレクトリを一時的に切り替える
- query
- 候補を部分一致で絞り込む。1 件なら fzf をスキップ
EXAMPLES
$ repofzf でリポジトリを選んで cd
$ repo dot"dot" に一致する候補へ絞り込み。1 件なら即 cd
$ repo --refreshキャッシュを無視して再走査
DEMO
DEMO GIF SLOT
src/assets/gifs/repo.gif を追加するとここに表示されます
SOURCE
# 作業ディレクトリごとに衝突しないキャッシュファイル名を返す内部関数
_repo_cache_file() {
local work_dir="${1:-$WORK_DIR}"
local cache_key
cache_key=$(printf '%s' "$work_dir" | cksum | awk '{print $1}')
printf '%s/repos-%s.tsv\n' "$REPO_CACHE_DIR" "$cache_key"
}
# キャッシュが TTL 内なら成功を返す内部関数
_repo_cache_is_fresh() {
local cache_file="$1"
[[ -f "$cache_file" ]] || return 1
local modified_at
modified_at=$(stat -f '%m' "$cache_file" 2>/dev/null) || return 1
(( $(date +%s) - modified_at < REPO_CACHE_TTL ))
}
# Git リポジトリ候補をキャッシュ経由で出力する内部関数
# 第2引数が refresh の場合はキャッシュを使わず再走査する
_repo_choices() {
local work_dir="${1:-$WORK_DIR}"
local refresh="${2:-}"
local cache_file
cache_file=$(_repo_cache_file "$work_dir") || return 1
if [[ "$refresh" != "refresh" ]] && _repo_cache_is_fresh "$cache_file"; then
command cat "$cache_file"
return
fi
mkdir -p "$REPO_CACHE_DIR" || return 1
local cache_tmp="${cache_file}.tmp.$$"
if _scan_repo_choices "$work_dir" > "$cache_tmp"; then
mv "$cache_tmp" "$cache_file" || return 1
command cat "$cache_file"
else
rm -f "$cache_tmp"
return 1
fi
}
# fzf でリポジトリを選んで cd する
# usage: repo [--refresh] [work_dir] [query]
# --refresh は work_dir の直後でも指定できる
# example: repo dot
repo() {
local work_dir="$WORK_DIR"
local refresh=""
if [[ "${1:-}" == "--refresh" ]]; then
refresh="refresh"
shift
fi
# 既存の repo /path/to/work-dir 形式も維持する
if [[ -n "${1:-}" && -d "$1" ]]; then
work_dir="$1"
shift
fi
if [[ "${1:-}" == "--refresh" ]]; then
refresh="refresh"
shift
fi
local query="$*"
local selected_path
selected_path=$(_select_repo_or_worktree "$work_dir" "$query" "$refresh") || return 1
if [[ -n "$selected_path" ]]; then
cd "$selected_path"
echo "$selected_path" >> "$REPOHIST_FILE"
fi
}