git worktree
的出現成功取代了 git stash
的功能 (處理臨時出現問題時, 開一個 linked working directory 就好).
git worktree
也可以讓使用者免於同時 clone 好幾份相同的 project 在單一電腦上, 以及免除在不同 cloned project 間 cherry-pick 的麻煩.
不過 git worktree add
有一個限制: 要建立 linked working directory 的資料夾需要是 empty 或資料夾尚未建立, 否則指令會 failed.
這造成使用 git-repo
開啟 worktree 功能時 (repo init --worktree
), 若有 project 是 checkout 在 root directory (i.e. 與 .repo/
在同一層), 則會因 .repo/
資料夾的存在而 failed.
要解決這個問題, 只好參考 git worktree 的原始版本, 利用 git 的 low-level commands 來達成 git worktree add
的效果了.
Worktree 的操作與下列三個資料夾有關
$GIT_DIR
: 一般是放在 main working directory 下的 .git/
資料夾. 若是 bare repository, 則為 clone 後產生的 project_name.git
.git worktree add
指令 checkout 的資料夾) 下的 .git
檔案, 其內容指向下面第三個資料夾$GIT_DIR/worktress/ID/
: 保管 linked working directory 的 HEAD
, index
, logs/
等資訊的檔案與資料, 也包含 commondir
指向 $GIT_DIR
, 以及 gitdir
指向 linked working directory 下的 .git
檔案.要注意的是 $GIT_DIR
與 $GIT_COMMON_DIR
的內容是會根據現在是在 main working directory 還是 linked working directory 而不同
假設 main working directory 的位置是在 /path/to/repos/
的話
Working Directory | $GIT_DIR |
$GIT_COMMON_DIR |
---|---|---|
Main | /path/to/repos/.git/ |
N/A |
Linked | /path/to/repos/.git/worktrees/ID/ |
/path/to/repos/.git/ |
假設 main working directory 的路徑是 /path/to/main
, 欲建立的 linked working directory 的路徑是 /path/to/linkedwt
先建立 linked working directory 的 $GIT_DIR
, 以及其內容
mkdir /path/to/main/.git/worktrees/linkedwt/
mkdir /path/to/main/.git/worktrees/linkedwt/logs
# Commit prefer to checkout in linked working directory
echo COMMIT_SHA1 > /path/to/main/.git/worktrees/linkedwt/HEAD
echo COMMIT_SHA1 > /path/to/main/.git/worktrees/linkedwt/ORIG_HEAD
# commondir usually stores relative path
echo "../.." > /path/to/main/.git/worktrees/linkedwt/commondir
echo "/path/to/linkedwt/.git" > /path/to/main/.git/worktrees/linkedwt/gitdir
# If we want to locked the linked working directory
echo "added with --lock" > locked
如果要 checkout 到 linked working directory 的是 branch 的話, 則 HEAD
和 ORIG_HEAD
需改成
echo `ref: refs/heads/BRANCH_NAME` > /path/to/main/.git/worktrees/linkedwt/HEAD
echo `ref: refs/heads/BRANCH_NAME` > /path/to/main/.git/worktrees/linkedwt/ORIG_HEAD
接著先建立 linked working directory
# Create linked working directory if not existed
mkdir /path/to/linkedwt
# Add path to GIT_DIR
echo "gitdir: /path/to/main/.git/worktrees/linkedwt" > /path/to/linkedwt/.git
最後再 checkout working directory 就完成了
要注意的是, 如果 /path/to/linkedwt 在 git checkout -f HEAD
前就存在一些在 working directory 中被 tracking 的檔案, 則 checkout 會把這些檔案覆蓋過去.
cd /path/to/linkedwt/
git checkout -f HEAD
Linked working directory 的 $GIT_DIR
不一定需要放在 main working directory 下的 .git/worktrees
中, 也可以正常運作.
假設把 Linked working directory 的 $GIT_DIR
放在 /path/to/wtstore/
只要做下列修改 linked working directory 仍可正常運作
# Update linked working directory's .git
mv /path/to/main/.git/worktrees/linkedwt /path/to/wtstore
echo "gitdir: /path/to/wtstore/" > /path/to/linkedwt/.git
echo "/path/to/main" > /path/to/wtstore/commondir
Git
Written on
October
21st
,
2022
by
Borting