Created
November 20, 2025 05:44
-
-
Save githubhjs/36814052eb4d43a55e8ffe8bd75309b1 to your computer and use it in GitHub Desktop.
git-teleporter.sh:讓你在任何目錄下,用「檔案路徑」當參數執行 git 指令。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # ----------------------------------------------------------------------------- | |
| # git-teleporter | |
| # | |
| # 功能: | |
| # 讓你在任何目錄下,用「檔案路徑」當參數執行 git 指令。 | |
| # 腳本會自動偵測參數裡哪一個是實際存在的路徑,cd 到該檔案所在的目錄, | |
| # 然後在那個目錄裡執行指定的 git 指令。 | |
| # | |
| # 典型用法: | |
| # git-teleporter blame repos/ip/isp/units/cfc/v1/l_rtl/cfc.sv | |
| # git-teleporter log -n 5 repos/ip/isp/units/cfc/v1/l_rtl/cfc.sv | |
| # | |
| # 限制與假設: | |
| # - 主要設計給「單一檔案/目錄」使用,會使用「第一個」找到的存在路徑來 teleport。 | |
| # - 其他在該路徑「之前」出現的引數會被視為 git 的一般參數(flags、數值等)。 | |
| # ----------------------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| # Step 1: 參數檢查 | |
| # 需要至少一個參數:git 指令本身(如 log、blame、diff...)。 | |
| # $#: 目前輸入參數的數量。 | |
| # ----------------------------------------------------------------------------- | |
| if [ $# -lt 1 ]; then | |
| echo "Usage: $0 <git-command> [args...] <file-path>" | |
| echo "Example: $0 blame repos/ip/isp/units/cfc/v1/l_rtl/cfc.sv" | |
| echo "Example: $0 log -n 5 repos/ip/isp/units/cfc/v1/l_rtl/cfc.sv" | |
| exit 1 | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # Step 2: 基本變數設定 | |
| # 把第一個參數當成 git 指令 (GIT_CMD),例如 "log"、"blame"、"diff"。 | |
| # 然後用 shift 把它從參數列表移除,之後 $@ 就是不含指令本身的其餘參數。 | |
| # ----------------------------------------------------------------------------- | |
| GIT_CMD="$1" | |
| shift | |
| # FILE_PATH 會用來記錄「找到的第一個存在路徑(檔案或目錄)」的完整路徑 | |
| FILE_PATH="" | |
| # ARGS 是一個陣列,用來存放在「遇到檔案/目錄之前」的 git 參數(例如 -n, 5 等) | |
| ARGS=() | |
| # ----------------------------------------------------------------------------- | |
| # Step 3: 逐一解析剩下的參數,嘗試找出實際存在的路徑 | |
| # 迴圈走過目前所有的 "$@"。 | |
| # 對每個 arg: | |
| # 1. 若是絕對路徑 (以 / 開頭),直接當成測試路徑。 | |
| # 2. 若是相對路徑,則以目前工作目錄 (pwd) 為基準組成完整路徑。 | |
| # 3. 用 [ -e ] 測試這個路徑是否存在(可視需要改成 -f 只接受檔案)。 | |
| # 4. 第一個存在的路徑就視為目標 FILE_PATH,並結束迴圈。 | |
| # 5. 若不存在,就把它視為一般的 git 參數,存進 ARGS。 | |
| # ----------------------------------------------------------------------------- | |
| for arg in "$@"; do | |
| # 判斷是否為絕對路徑:以 "/" 開頭 | |
| if [[ "$arg" == /* ]]; then | |
| TEST_PATH="$arg" | |
| else | |
| # 否則視為相對路徑:用目前工作目錄組成完整路徑 | |
| TEST_PATH="$(pwd)/$arg" | |
| fi | |
| # 測試該路徑是否存在: | |
| # -e:檔案或目錄存在即為 true;若只想接受檔案,可改成 -f。 | |
| if [ -e "$TEST_PATH" ]; then | |
| # 找到第一個存在的路徑,記錄下來並立即跳出迴圈 | |
| FILE_PATH="$TEST_PATH" | |
| break | |
| else | |
| # 若該參數不是一個存在的路徑, | |
| # 便假定它是 git 的一般參數(例如 "-n"、"5"、"--since" 等), | |
| # 收集到 ARGS 陣列,之後會一併傳給 git。 | |
| ARGS+=("$arg") | |
| fi | |
| done | |
| # ----------------------------------------------------------------------------- | |
| # Step 4: 如果完全沒有找到任何存在的路徑 | |
| # | |
| # 情境說明: | |
| # - 使用者可能只是想要在目前目錄直接跑: | |
| # git log -n 10 | |
| # - 這種情況底下,$@ 其實全都是 flags 或一般參數,沒有實際的檔案/目錄。 | |
| # | |
| # 行為: | |
| # - 直接在目前目錄執行:git <GIT_CMD> <全部原參數> | |
| # - 這裡只用 "$@",不再用 ARGS,避免重複帶入同一批參數。 | |
| # ----------------------------------------------------------------------------- | |
| if [ -z "$FILE_PATH" ]; then | |
| git "$GIT_CMD" "$@" | |
| exit $? | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # Step 5: Teleportation 核心邏輯 | |
| # | |
| # 1. 從 FILE_PATH 抽出「目錄路徑」與「檔名 (或最後一層目錄名)」 | |
| # - dirname:給 /a/b/c.sv → 傳回 /a/b | |
| # - basename:給 /a/b/c.sv → 傳回 c.sv | |
| # | |
| # 2. cd 到該目錄底下,等同於手動走到該檔案背後的 git repo 目錄結構。 | |
| # | |
| # 3. 在該目錄中執行 git 指令: | |
| # git <GIT_CMD> <前面收集的 ARGS...> <FILE_NAME> | |
| # | |
| # 這樣一來,在執行時 git 看到的檔案路徑就只是單純的檔名, | |
| # 而不會是從頂層開始的長長路徑,體感就像你本來就 cd 到那裡一樣。 | |
| # ----------------------------------------------------------------------------- | |
| DIR_PATH="$(dirname "$FILE_PATH")" # 檔案/目錄所在的父層目錄 | |
| FILE_NAME="$(basename "$FILE_PATH")" # 檔案名或最後一層目錄名 | |
| # 先切換目錄到 DIR_PATH;若 cd 成功,再執行 git 指令。 | |
| # "${ARGS[@]}" 會展開成先前收集的所有 flags/參數(不含檔案路徑)。 | |
| cd "$DIR_PATH" && git "$GIT_CMD" "${ARGS[@]}" "$FILE_NAME" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment