接上篇:Git Worktree 高階使用,這樣清爽多了

日拱一兵發表於2021-11-26

前言

上一篇文章 Git Worktree 大法真香 帶大家瞭解了 git worktree 是如何幫助我同時在多個分支工作,並且互不影響的。但是建立 worktree 的目錄位置不是在當前專案下,總感覺建立好的這些 worktree 不屬於當前專案,這對於磁碟管理強迫症的我來說是十分難受的,今天就帶大家瞭解一種高階用法來解決這個痛點

準備知識

在使用高階用法之前,你需要知道一點 bare repo 知識,我們先從你熟悉的命令開始

git init
git clone https://github.com/FraserYu/amend-crash-demo.git

這兩個命令就會生成一個 non-bare repo,我們通常都在這樣的 repo 中進行日常工作, 你可以在這裡面 add/commit/pull/push

要想生成一個 bare repo 也很簡單, 只需在上面兩個命令的基礎上加上 --bare 引數即可

git init --bare
git clone --bare https://github.com/FraserYu/amend-crash-demo.git

來執行這兩個 clone 命令,並檢視檔案內容你就會看出差別了

  1. bare repo 僅僅包含 Git 相關資訊,並不包含我們的實際專案檔案(.java/.js/.py), 而 non-bare repo 卻包含我們的全部資訊
  2. bare repo 名稱預設是帶有 .git 字尾的,這也恰恰證明了第一點
  3. bare repo 中是不存在 .git 資料夾的,這也就導致它不能像 non-bare repo 那樣 add/commit/pull/push

看到這,你可能感覺 bare repo 就是一個 Git 空殼資料夾,一無是處。其實不然,正因為 bare repo 的這些特性(不能對它進行更改),也就避免 repo 裡面的內容被弄的一團糟,所以可以被用來做私有的中心化 repo,一張圖解釋,其實就是這樣的:

如果你有興趣,可以按照下面的命令在本地實驗一下整個過程:

user@server:$~  git init --bare name_to_repo.git

user@machine1:$~ git clone user@server:/path/to/repo/name_to_repo.git .
user@machine1:$~ cd name_to_repo
user@machine1:$~ touch README
user@machine1:$~ echo "Hello world" >> README
user@machine1:$~ git add README
user@machine1:$~ git commit -m "Adding a README"
user@machine1:$~ git push origin master

user@server:$~ ls /path/to/repo/name_to_repo.git/
branches/ config description HEAD hooks/ info/ objects/ refs/

user@machine2:$~ git clone user@server:/path/to/repo/name_to_repo.git .
user@machine2:$~ ls name_to_repo.git/
README
user@machine2:$~ cat README
Hello world

實驗結果就是:無論在 machine1 下怎麼 push 檔案,bare repo 中都不會存在你 push 的檔案,只有 Git 相關資訊。但是 machine2 clone 最新的 repo 時,卻能看到machine1 push 的檔案,這正是 Git 的魔法所在

到這裡,bare repo 就解釋完了。接下來,接上一篇 Git Worktree 大法真香 內容,藉助 bare repo 的特性,來優化同時在多個分支工作的做法吧

Git Worktree 高階用法

首先,在你選定的目錄下為你的專案(比如這裡叫 amend-crash-demo)單獨建立一個資料夾, 並 cd 進去

mkdir amend-crash-demo
cd amend-crash-demo

接下來以 bare 的形式 clone 專案程式碼, 並將內容 clone 到 .bare 資料夾內:

git clone --bare git@github.com:FraserYu/amend-crash-demo.git .bare

我們還要在當前目錄下建立一個 .git 檔案,檔案內容是以 gitdir 的形式指向我們的 .bare 資料夾 (如果不理解 gitdir 的含義,請回看 Git Worktree 大法真香

echo "gitdir: ./.bare" > .git

然後我們要編輯 .bare/config 檔案,並修改 [remote "origin"]內容,和下面內容保持一致(也就是新增第 6 行內容),這確保我們建立 worktree 切換分支,可以顯示正確的分支名稱

vim .bare/config

# -----------------------------------------------
 [remote "origin"]
       url = git@github.com:FraserYu/amend-crash-demo.git
       fetch = +refs/heads/*:refs/remotes/origin/*

接下來我們就可以建立 worktree 了,首先我們要為 main 分支建立 worktree,因為 main 分支 HEAD 的指向的 commit-ish 就是你建立其他 worktree 的 commit-ish

git worktree add main

# --------------------------------
Preparing worktree (checking out 'main')
HEAD is now at 82b8711 add main file

通常我們不會直接在 main 分支上直接工作,而是建立其它型別的分支,繼續建立名為 feature/JIRA234-feature3 的 worktree

git worktree add -b "feature/JIRA234-feature3" feature3

# ------------------------------------------------
Preparing worktree (new branch 'feature/JIRA234-feature3')
HEAD is now at 82b8711 add main file

檢視當前資料夾的內容,你會發現只有 mainfeature3 兩個資料夾(因為 .bare.git 是隱藏資料夾/檔案),這樣是不是相當清爽呢?

ls -l

# -------------------------------------------
total 0
drwxr-xr-x  10  rgyb  staff  320 Nov 23 21:44 feature3
drwxr-xr-x  10  rgyb  staff  320 Nov 23 21:36 main


ls -al
# -------------------------------------------
total 8
drwxr-xr-x   6  rgyb  staff  192 Nov 23 21:44  .
drwxr-xr-x   3  rgyb  staff   96 Nov 23 21:14   ..
drwxr-xr-x  12  rgyb  staff  384 Nov 23 21:36  .bare
-rw-r--r--   1  rgyb  staff   16 Nov 23 21:29   .git
drwxr-xr-x  10  rgyb  staff  320 Nov 23 21:44  feature3
drwxr-xr-x  10  rgyb  staff  320 Nov 23 21:36  main

接下來就可以盡情的在我們的各種分支上,彼此互不影響的進行 add/commit/pull/push 操作了

echo "feature3 development" > feature3.yaml
git add feature3.yaml

git commit -m "feat: [JIRA234-feature3] feature3 development"
# ------------------------------------------------------------------
[feature/JIRA234-feature3 aeaac94] feat: [JIRA234-feature3] feature3 development
 1 file changed, 1 insertion(+)
 create mode 100644 feature3.yaml

git push --set-upstream origin feature/JIRA234-feature3

通過上一篇文章 worktree 的四個命令,多分支協同開發不再是問題:

git worktree add
git worktree list
# ------------------------------------------------------------------------------------------------
/Users/rgyb/Documents/projects/amend-crash-demo/.bare        (bare)
/Users/rgyb/Documents/projects/amend-crash-demo/feature3   aeaac94 [feature/JIRA234-feature3]
/Users/rgyb/Documents/projects/amend-crash-demo/main        82b8711 [main]

git worktree remove
git worktree prune

總結

通過藉助 bare repo 的特性,我們可以非常整潔的將所有 worktree 只管理在當前專案目錄下,多分支協同開發,就像這樣:

.
└── amend-crash-demo
    ├── feature3
    │   ├── README.md
    │   ├── config.yaml
    │   ├── feat1.txt
    │   ├── feature3.yaml
    │   ├── file1.yaml
    │   ├── hotfix.yaml
    │   ├── main.properties
    │   └── main.yaml
    └── main
        ├── README.md
        ├── config.yaml
        ├── feat1.txt
        ├── file1.yaml
        ├── hotfix.yaml
        ├── main.properties
        └── main.yaml

3 directories, 15 files

如果你有磁碟管理強迫症,這絕對是個好辦法。

如果你想更好的理解整個過程,你需要在操作本文命令的同時,檢視 Git 相關的檔案資訊

有什麼問題,留言區交流

參考

  1. https://www.blopig.com/blog/2017/06/using-bare-git-repos/
  2. https://lists.mcs.anl.gov/pipermail/petsc-dev/2021-May/027448.html
  3. https://www.saintsjd.com/2011/01/what-is-a-bare-git-repository/
  4. https://infrequently.org/2021/07/worktrees-step-by-step/
  5. https://morgan.cugerone.com/blog/how-to-use-git-worktree-and-in-a-clean-way/
    個人部落格:https://dayarch.top
    加我微信好友, 進群娛樂學習交流,備註「進群」

歡迎持續關注公眾號:「日拱一兵」

  • 前沿 Java 技術乾貨分享
  • 高效工具彙總 | 回覆「工具」
  • 面試問題分析與解答
  • 技術資料領取 | 回覆「資料」

以讀偵探小說思維輕鬆趣味學習 Java 技術棧相關知識,本著將複雜問題簡單化,抽象問題具體化和圖形化原則逐步分解技術問題,技術持續更新,請持續關注......


相關文章