Git 入門 (三):分支 (branch)、下載遠端儲存庫 (clone)

為什麼要用分支?

多人協作時,不可能都在 master分支 上更動程式碼,通常會另外開分支來做測試或開發,藉此不影響正式主機分支。

branch 非常不佔空間。它們只是一個指向某個 commit 的 reference,就這麼簡單。使用 branch 其實就是在說:「我想要包含這一次的 commit 以及它的所有 parent 的 commit。」

分支常用指令:branch、checkout、reset

開發情境:我有一個正式主機 master 分支,有一個開發分支 develop。

  • 新增分支:git branch 分支名稱
  • 查看有哪些分支:git branch
  • 切換分支 (將 HEAD 指向分支):git checkout 分支名稱
  • 回頭觀看版本內容 (將 HEAD 指向 commit 版本):git checkout commit編號
  • 返回最新的版本:git checkout master(分支名稱)
  • 還原上個版本:git reset HEAD^
  • 將特定 commit 貼上新分支:git branch 新分支名稱 commit編號
  • 將特定 commit 貼上舊分支 (移動分支標籤):git branch -f 舊分支名稱 commit編號

checkout 與 reset 的差異

git checkout 將 HEAD 移動到特定位置,但是不對檔案做更動。也不移動分支標籤。

git reset 將 HEAD 移動到特定位置,但是依照 --soft --mixed --hard 指令,對檔案做更動:退回索引區、退回工作區、檔案都放棄。如果 HEAD 和分支黏在一起的時候,分支標籤會跟著 HEAD 一起移動。

checkout HEAD^

如下圖 HEAD 原本在 815b5bc(new branch) 這個 commit,當我下了 git checkout HEAD^,HEAD 會移動到 4e77317(add h1),並出現如下文字:

Previous HEAD position was 815b5bc new branch
HEAD is now at 4e77317 add h1


reset HEAD^ --hard

如果 HEAD 原本在 815b5bc(new branch) 這個 commit,當我下了 git reset HEAD^ --hard,HEAD 會移動到 4e77317(add h1),並出現如下文字:

HEAD is now at 4e77317 add h1

圖雖然看起來一樣,但是 git 背後做的動作並不一樣。因為 reset 是危險動作,git 會把 HEAD 的狀態存放在 ORIG_HEAD 的檔案夾,讓你隨時可以跳回危險動作之前的狀態。

reset HEAD^ (- -mixed)

如果 HEAD 原本在 815b5bc(new branch) 這個 commit,當我下了 git reset HEAD^,HEAD 會移動到 4e77317(add h1),並出現如下文字:

Unstaged changes after reset:
M index.html

圖中可以看到多了一個 uncommitted changes 的線,它是 815b5bc(new branch) 的工作區 (Working area) 版本。

modified index.html, index2.html and index3.html 還沒加入索引區。


reset HEAD^ --soft

如果 HEAD 原本在 815b5bc(new branch) 這個 commit,當我下了 git reset HEAD^ --soft,HEAD 會移動到 4e77317(add h1),沒有出現文字說明。

圖中可以看到多了一個 uncommitted changes 的線,它是 815b5bc(new branch) 的索引區 (Staging area) 版本。


合併分支、快轉機制

通常會以舊的 commit 為基底 (git checkout 分支名稱),去合併新的編輯過的 commit。(merge 新branch 到 master)

先輸入 git checkout master,再輸入 git merge dev

  • 合併分支 (快轉):git merge 分支名稱
  • 取消快轉:git merge 分支名稱 --no-ff
  • 觀看線圖:git log --oneline --graph
  • 還原合併前狀態:git reset ORIG_HEAD --hard
  • 刪除已經合併的分支:git branch -d 分支名稱
  • 強制刪除未合併的分支:git branch -D 分支名稱

還原到危險動作前的狀態

當你在做一些比較「危險」的操作 (例如像:merge、rebase 或 reset 之類的),Git 就會把 HEAD 的狀態存放在 ORIG_HEAD 的檔案夾,讓你隨時可以跳回危險動作之前的狀態。

  • 還原 reset 前狀態:git reset ORIG_HEAD --hardgit reset commit編號 --hard

雖然 git reflog 指令也可以查到相關資訊,但 reflog 的資料比較雜一點,這個 ORIG_HEAD 會更方便的讓你找到最近的一次危險動作之前的 SHA-1 值。

ORIG_HEAD 是什麼東西?
【狀況題】不小心使用 hard 模式 Reset 了某個 Commit,救得回來嗎?

下載遠端儲存庫 (clone)

  • 下載遠端儲存庫: git clone 儲存庫網址

clone 和 gitHub 上的 Download ZIP 是完全不同的東西,一開始不知道的時候,踩了一個大坑。

clone 會將檔案和遠端的儲存庫一並取下來。而 Download ZIP 只會將檔案取下來。

所以這時你想要 push 上遠端的儲存庫時,必須先在本地端初始化一個儲存庫,然後執行 commit,然而你的本地端儲存庫和遠端儲存庫裡面的 commit 歷史不同,因此會造成衝突,無法 push 上去。


參考資料:
六角學院 -「Git 分支 (branch)」線上講義
六角學院 -「Git 分支中階教學」線上講義

Git 入門 系列文

Git 入門 (一):介紹和基本指令
Git 入門 (二):遠端操作 (使用 GitHub 的伺服器)、檔案狀態與還原
Git 入門 (三):分支 (branch)、下載遠端儲存庫 (clone) ← 你在這~
Git 入門 (四):取得遠端新檔案並合併 (fetch + merge = pull)、衝突 (conflict)