English ▾ 主題 ▾ 最新版本 ▾ git-checkout 最後更新於 2.55.0

名稱

git-checkout - 切換分支或還原工作目錄檔案

概要

git checkout [-q] [-f] [-m] [<branch>]
git checkout [-q] [-f] [-m] --detach [<branch>]
git checkout [-q] [-f] [-m] [--detach] <commit>
git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>]
git checkout <tree-ish> [--] <pathspec>…​
git checkout <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>…​
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]
git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>…​]

描述

git checkout 有兩種主要模式

  1. 切換分支,使用 git checkout <branch>

  2. 還原檔案的不同版本,例如使用 git checkout <commit> <filename>git checkout <filename>

關於 Git 如何決定執行哪種模式,請參閱下方的「參數消歧義」。

git checkout [<branch>]

切換至 <branch>。這會將目前分支設為 <branch> 並更新工作目錄中的檔案。如果 <branch> 與您目前提交內容在任何檔案上有未提交的差異,此 checkout 將會失敗。否則,未提交的變更將會被保留。

如果找不到 <branch>,但僅有一個遠端(稱為 <remote>)存在名稱相符的追蹤分支,且未指定 --no-guess,則視為等同於

$ git checkout -b <branch> --track <remote>/<branch>

執行 git checkout 而不指定分支,除了列印目前分支的追蹤資訊外,沒有任何效果。

git checkout -b <new-branch> [<start-point>]

建立一個名為 <new-branch> 的新分支,從 <start-point> 開始(預設為目前的 commit),並簽出該新分支。您可以使用 --track--no-track 選項來設定分支的上游追蹤資訊。

如果簽出 <new-branch> 時發生錯誤則會失敗,例如簽出 <start-point> commit 會覆寫您未提交的變更。

git checkout -B <branch> [<start-point>]

-b 相同,但如果該分支已存在,它會將 <branch> 重設至起始點,而不是失敗。

git checkout --detach [<branch>]
git checkout [--detach] <commit>

git checkout <branch> 相同,但它不是讓 HEAD 指向該分支,而是讓 HEAD 直接指向該 commit ID。詳情請參閱下方的「分離 HEAD (DETACHED HEAD)」章節。

省略 <branch> 會將 HEAD 分離在目前分支的頂端。

git checkout <tree-ish> [--] <pathspec>...
git checkout <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]

使用來自給定 commit 或樹的版本取代指定的檔案和/或目錄,並將其加入索引(又稱「暫存區」)。

例如,git checkout main file.txt 會用 main 中的版本取代 file.txt

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]

使用索引中的版本取代指定的檔案和/或目錄。

例如,如果您簽出一個 commit,編輯 file.txt,然後決定這些變更是錯誤的,git checkout file.txt 將會捨棄 file.txt 中所有未暫存的變更。

如果該檔案有合併衝突且您尚未執行 git add file.txt(或等效操作)將其標記為已解決,此操作會失敗。您可以使用 -f 忽略未合併的檔案而不失敗,使用 --ours--theirs 用特定一方的版本取代它們,或使用 -m 用原始衝突的合併結果取代它們。

git checkout (-p|--patch) [<tree-ish>] [--] [<pathspec>...]

這與前兩種模式類似,但允許您使用互動式介面來顯示「差異 (diff)」輸出,並選擇要應用到結果中的區塊 (hunks)。請參閱下方關於 --patch 選項的說明。

選項

-q
--quiet

安靜模式,抑制回饋訊息。

--progress
--no-progress

當標準錯誤串流連接到終端機時,預設會報告進度狀態,除非指定了 --quiet。無論是否指定 --quiet,此旗標都會啟用進度報告,即使未連接到終端機也是如此。

-f
--force

切換分支時,即使索引或工作樹與 HEAD 不同,即使有未追蹤的檔案阻礙,仍強制執行。這用於捨棄本地變更以及任何阻礙操作的未追蹤檔案或目錄。

當從索引簽出路徑時,遇到未合併的項目不會失敗;相反地,未合併的項目會被忽略。

--ours
--theirs

當從索引簽出路徑時,針對未合併的路徑簽出第 2 階段 (stage #2, ours) 或第 3 階段 (stage #3, theirs)。

請注意,在 git rebasegit pull --rebase 期間,ourstheirs 可能會互換;--ours 給出的是變更所重定基底 (rebased) 之分支的版本,而 --theirs 給出的是包含您正要重定基底之工作的分支版本。

這是因為 rebase 用於將遠端歷史視為共享的標準歷史的工作流程,並將您在分支上所做的工作視為要整合的第三方工作,而在重定基底期間,您暫時扮演了標準歷史守護者的角色。作為標準歷史的守護者,您需要將來自遠端的歷史視為 ours(即「我們的共享標準歷史」),而您在側分支上所做的事情視為 theirs(即「某位貢獻者在其之上的工作」)。

-b <new-branch>

建立一個名為 <new-branch> 的新分支,從 <start-point> 開始,並簽出產生的分支;詳情請參閱 git-branch[1]

-B <new-branch>

-b 相同,但如果該分支已存在,它會將 <branch> 重設至起始點,而不是失敗。

-t
--track[=(direct|inherit)]

建立新分支時,設定「上游 (upstream)」配置。詳情請參閱 git-branch[1] 中的 --track。作為便利,不帶 -b--track 暗示了分支的建立。

如果未給出 -b 選項,新分支的名稱將會從遠端追蹤分支衍生,方法是查看為對應遠端配置的 refspec 的本地部分,然後去除 "*" 之前的初始部分。這會告訴我們,在基於 origin/hack(或 remotes/origin/hack,甚至是 refs/remotes/origin/hack)建立分支時,將 hack 用作本地分支。如果給定的名稱沒有斜線,或者上述推測導致名稱為空,則中止推測。在此情況下,您可以使用 -b 明確給出名稱。

--no-track

即使 branch.autoSetupMerge 配置變數為真,也不要設定「上游 (upstream)」配置。

--guess
--no-guess

如果找不到 <branch>,但僅有一個遠端(稱為 <remote>)存在名稱相符的追蹤分支,則視為等同於

$ git checkout -b <branch> --track <remote>/<branch>

如果該分支存在於多個遠端中,且其中一個由 checkout.defaultRemote 配置變數命名,我們將使用該遠端進行消歧義,即使 <branch> 在所有遠端中並非唯一。設定例如 checkout.defaultRemote=origin,以便在 <branch> 有歧義但存在於 origin 遠端時,總是從那裡簽出遠端分支。另請參閱 git-config[1] 中的 checkout.defaultRemote

--guess 是預設行為。使用 --no-guess 停用它。

預設行為可以透過 checkout.guess 配置變數設定。

-l

建立新分支的引用紀錄 (reflog);詳情請參閱 git-branch[1]

-d
--detach

與其為了工作而簽出分支,不如為了檢查和進行可拋棄的實驗而簽出 commit。這是在 <commit> 不是分支名稱時,git checkout <commit> 的預設行為。詳情請參閱下方的「分離 HEAD (DETACHED HEAD)」章節。

--orphan <new-branch>

建立一個名為 <new-branch> 的新未生分支 (unborn branch),從 <start-point> 開始並切換至該分支。在此新分支上建立的第一個 commit 將沒有父 commit,且它將成為與所有其他分支和 commit 完全斷開連接的新歷史的根。

索引和工作樹的調整方式,如同您先前執行過 git checkout <start-point> 一樣。這允許您透過簡單執行 git commit -a 來建立根 commit,從而開始一個記錄了類似於 <start-point> 路徑集的新歷史。

當您想要發布來自某個 commit 的樹而不暴露其完整歷史時,這很有用。您可能會想要這樣做來發布專案的開源分支,其目前的樹是「乾淨」的,但其完整歷史包含專有或其他受限的程式碼片段。

如果您想開始一個斷開連接的歷史,記錄一組與 <start-point> 完全不同的路徑,那麼在建立孤兒分支 (orphan branch) 後,您應該立即從工作樹的頂層執行 git rm -rf . 來清除索引和工作樹。隨後,您就可以準備新的檔案,透過從他處複製、解壓縮 tarball 等方式,重新填滿工作樹。

--ignore-skip-worktree-bits

在稀疏簽出 (sparse checkout) 模式下,git checkout -- <path>... 只會更新與 <paths>$GIT_DIR/info/sparse-checkout 中的稀疏模式相符的項目。此選項會忽略稀疏模式,並將 <path>... 中的任何檔案加回。

-m
--merge

切換分支時,如果您對一個或多個檔案有本地修改,且這些檔案在目前分支和要切換到的分支之間存在差異,則命令會拒絕切換,以保留您的修改。使用此選項,衝突的本地變更會在切換前自動暫存 (stash),並在切換後重新應用。如果本地變更與分支間的差異不重疊,則切換將在不暫存的情況下進行。如果重新應用暫存導致衝突,該項目會被保存到暫存列表中。完成後解決衝突並執行 git stash drop,或者在稍後執行 git stash pop 重新應用您的變更之前,先清除工作樹(例如使用 git reset --hard)。

從索引簽出路徑時,此選項允許您在指定路徑中重新建立衝突的合併。此選項不能在從樹狀物件 (tree-ish) 簽出路徑時使用。

--conflict=<style>

與上面的 --merge 選項相同,但會更改衝突修改塊的呈現方式,覆蓋 merge.conflictStyle 配置變數。可能的值為 merge(預設)、diff3zdiff3

-p
--patch

互動式選擇 <tree-ish>(或索引,如果未指定)與工作樹之間差異中的區塊 (hunks)。所選區塊會反向應用到工作樹(如果指定了 <tree-ish>,則也會應用到索引)。

這意味著您可以使用 git checkout -p 選擇性地捨棄目前工作樹中的編輯。請參閱 git-add[1] 的「互動模式 (Interactive Mode)」章節,了解如何操作 --patch 模式。

請注意,此選項預設使用非重疊 (no overlay) 模式(另請參閱 --overlay),目前不支援重疊模式。

-U<n>
--unified=<n>

產生帶有 <n> 行前後內容的差異。前後內容行數預設為 diff.context,如果未設定配置變數則為 3。(由於歷史意外,不帶 <n>-U 會被默默接受為 -p 的同義詞)。

--inter-hunk-context=<n>

顯示差異修改塊之間的內容,最多到指定的 <n> 行,從而融合彼此接近的修改塊。預設為 diff.interHunkContext,如果未設定配置選項則為 0。

--ignore-other-worktrees

當目標分支已被簽出或被另一個工作樹 (worktree) 使用時,git checkout 會拒絕執行。此選項使其無論如何都強制簽出該分支。換句話說,該分支可以被多個工作樹使用。

--overwrite-ignore
--no-overwrite-ignore

切換分支時靜默覆寫被忽略的檔案。這是預設行為。使用 --no-overwrite-ignore 可以在新分支包含被忽略檔案時中止操作。

--recurse-submodules
--no-recurse-submodules

使用 --recurse-submodules 將根據超級專案 (superproject) 中記錄的 commit 更新所有活動子模組的內容。如果子模組中的本地修改會被覆寫,則 checkout 將會失敗,除非使用 -f。如果什麼都不用(或使用 --no-recurse-submodules),則不會更新子模組的工作樹。就像 git-submodule[1] 一樣,這會分離子模組的 HEAD

--overlay
--no-overlay

在預設的重疊模式中,git checkout 永遠不會從索引或工作樹中移除檔案。指定 --no-overlay 時,出現在索引和工作樹中,但不在 <tree-ish> 中的檔案會被移除,使其與 <tree-ish> 完全相符。

--pathspec-from-file=<file>

路徑規格(pathspec)透過 <file> 傳遞,而不是透過命令列參數。如果 <file> 正好是 -,則使用標準輸入。路徑規格元素由 LFCR/LF 分隔。路徑規格元素可以依照配置變數 core.quotePath 的說明進行引號處理(見 git-config[1])。另請參閱 --pathspec-file-nul 和全域的 --literal-pathspecs

--pathspec-file-nul

僅在使用 --pathspec-from-file 時有意義。路徑規格元素由 NUL 字元分隔,所有其他字元都按字面意思解釋(包括換行符和引號)。

<branch>

要簽出的分支;如果它指向一個分支(即一個前面加上 "refs/heads/" 後為有效引用的名稱),則簽出該分支。否則,如果它指向一個有效的 commit,您的 HEAD 就會變成「分離 (detached)」,您將不再位於任何分支上(詳情請參閱下文)。

您可以使用 @{-N} 語法來參考使用 "git checkout" 操作簽出的第 N 個上次分支/commit。您也可以指定 -,這與 @{-1} 同義。

作為特例,如果您想參考兩個 rev 的合併基礎 (merge base),可以使用 <rev-a>...<rev-b> 作為合併基礎的快捷方式。<rev-a><rev-b> 最多可以省略其中一個,在這種情況下預設為 HEAD

<new-branch>

新分支的名稱。

<start-point>

要開始新分支的 commit 名稱;詳情請參閱 git-branch[1]。預設為 HEAD

作為特例,如果您想參考兩個 rev 的合併基礎 (merge base),可以使用 <rev-a>...<rev-b> 作為合併基礎的快捷方式。<rev-a><rev-b> 最多可以省略其中一個,在這種情況下預設為 HEAD

<tree-ish>

要簽出的樹(當給定路徑時)。如果未指定,將使用索引。

作為特例,如果您想參考兩個 rev 的合併基礎 (merge base),可以使用 <rev-a>...<rev-b> 作為合併基礎的快捷方式。<rev-a><rev-b> 最多可以省略其中一個,在這種情況下預設為 HEAD

--

不要將後續的任何參數解釋為選項。

<pathspec>...

限制受操作影響的路徑。

更多詳情請參閱 gitglossary[7] 中的 pathspec 項目。

分離 HEAD (DETACHED HEAD)

HEAD 通常是指向一個具名分支(例如 master)。同時,每個分支都指向一個特定的 commit。讓我們看看一個包含三個 commit 的儲存庫,其中一個有標籤,並且簽出了 master 分支

           HEAD (refers to branch 'master')
            |
            v
a---b---c  branch 'master' (refers to commit 'c')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

當在此狀態下建立 commit 時,分支會更新以指向新的 commit。具體來說,git commit 會建立一個新的 commit d(其父 commit 為 c),然後更新 master 分支以指向新的 commit dHEAD 仍然指向 master 分支,因此現在間接地指向 commit d

$ edit; git add; git commit

               HEAD (refers to branch 'master')
                |
                v
a---b---c---d  branch 'master' (refers to commit 'd')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

有時能夠簽出一個不在任何具名分支頂端的 commit,甚至建立一個不被任何具名分支引用的新 commit 是很有用的。讓我們看看當我們簽出 commit b 時會發生什麼(這裡我們展示了兩種可能的操作方式)

$ git checkout v2.0  # or
$ git checkout master^^

   HEAD (refers to commit 'b')
    |
    v
a---b---c---d  branch 'master' (refers to commit 'd')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

請注意,無論使用哪種 checkout 命令,HEAD 現在都直接指向 commit b。這被稱為處於分離 HEAD 狀態。這僅表示 HEAD 指向一個特定的 commit,而不是指向一個具名分支。讓我們看看當我們建立一個 commit 時會發生什麼

$ edit; git add; git commit

     HEAD (refers to commit 'e')
      |
      v
      e
     /
a---b---c---d  branch 'master' (refers to commit 'd')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

現在有一個新的 commit e,但它僅由 HEAD 引用。當然,我們可以在此狀態下再新增另一個 commit

$ edit; git add; git commit

	 HEAD (refers to commit 'f')
	  |
	  v
      e---f
     /
a---b---c---d  branch 'master' (refers to commit 'd')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

事實上,我們可以執行所有正常的 Git 操作。但是,讓我們看看當我們隨後簽出 master 時會發生什麼

$ git checkout master

               HEAD (refers to branch 'master')
      e---f     |
     /          v
a---b---c---d  branch 'master' (refers to commit 'd')
    ^
    |
  tag 'v2.0' (refers to commit 'b')

必須意識到,此時沒有任何東西指向 commit f,這點很重要。最終,除非我們在此之前建立引用,否則 commit f(以及延伸的 commit e)將會被常規的 Git 垃圾回收程序刪除。如果我們尚未離開 commit f,執行以下任何操作都將建立對它的引用

$ git checkout -b foo  # or "git switch -c foo"  (1)
$ git branch foo                                 (2)
$ git tag foo                                    (3)
  1. 建立一個指向 commit f 的新分支 foo,然後更新 HEAD 指向 foo 分支。換句話說,在此命令後,我們將不再處於分離 HEAD 狀態。

  2. 同樣建立一個指向 commit f 的新分支 foo,但保持 HEAD 分離。

  3. 建立一個指向 commit f 的新標籤 foo,保持 HEAD 分離。

如果我們已經離開了 commit f,那麼我們必須先復原其物件名稱(通常使用 git reflog),然後我們才能建立對它的引用。例如,要查看 HEAD 曾經指向的最後兩個 commit,我們可以使用這些命令中的任何一個

$ git reflog -2 HEAD # or
$ git log -g -2 HEAD

參數消歧義 (ARGUMENT DISAMBIGUATION)

當您執行 git checkout <something> 時,Git 會嘗試猜測 <something> 是要作為分支、commit 還是檔案集,然後切換到該分支或 commit,或者還原指定的檔案。

如果存在任何歧義,Git 會將 <something> 視為分支或 commit,但您可以使用雙破折號 -- 強制 Git 將參數視為檔案和/或目錄列表,如下所示

git checkout -- file.txt

範例

1. 路徑 (Paths)

以下序列簽出 master 分支,將 Makefile 還原到兩個版本之前,錯誤地刪除了 hello.c,並從索引中將其找回。

$ git checkout master             (1)
$ git checkout master~2 Makefile  (2)
$ rm -f hello.c
$ git checkout hello.c            (3)
  1. 切換分支

  2. 從另一個 commit 取出檔案

  3. 從索引還原 hello.c

如果您想從索引中簽出 *所有* C 原始檔,您可以執行

$ git checkout -- '*.c'

注意 *.c 周圍的引號。即使 hello.c 不再存在於工作樹中,它也會被簽出,因為檔案通配符被用來匹配索引中的項目(而不是由 shell 匹配工作樹中的檔案)。

如果您恰巧有一個名為 hello.c 的不幸分支,此步驟會被誤解為切換到該分支的指令。您應該改寫為

$ git checkout -- hello.c

2. 合併 (Merge)

在錯誤的分支中工作後,切換到正確分支的操作將使用

$ git checkout mytopic

但是,您的「錯誤」分支和正確的 mytopic 分支在您本地修改過的檔案上可能存在差異,在這種情況下,上述 checkout 會像這樣失敗

$ git checkout mytopic
error: You have local changes to 'frotz'; not switching branches.

您可以為命令加上 -m 旗標,這會將您的本地變更帶到新分支

$ git checkout -m mytopic
Applied autostash.
Switched to branch 'mytopic'
The following paths have local changes:
M	frotz

切換後,本地修改會被重新應用且 *不會* 註冊在您的索引檔案中,所以 git diff 會顯示您自新分支頂端以來所做的變更。

3. 合併衝突 (Merge conflict)

當給出 --merge (-m) 選項且本地變更與我們正要切換到的分支中的變更重疊時,變更會被暫存並在切換後重新應用。如果此過程導致衝突,暫存項目會被儲存並會列印出一條訊息

$ git checkout -m mytopic
Your local changes are stashed, however applying them
resulted in conflicts.  You can either resolve the conflicts
and then discard the stash with "git stash drop", or, if you
do not want to resolve them now, run "git reset --hard" and
apply the local changes later by running "git stash pop".

組態設定 (CONFIGURATION)

本節中此行以下的內容是從 git-config[1] 文件中選擇性包含的。內容與該處找到的內容相同

checkout.defaultRemote

當您執行 git checkout <something>git switch <something> 且只有一個遠端時,它可能會隱含地回退到檢出並追蹤例如 origin/<something>。一旦您有多個具有 <something> 參照的遠端,這將不再起作用。此設定允許設定一個偏好的遠端名稱,在消除歧義時應始終勝出。典型的使用案例是將其設定為 origin

目前 git-switch[1]git-checkout[1] 會在執行 git checkout <something>git switch <something> 將檢出另一個遠端上的 <something> 分支時使用此設定;而 git-worktree[1] 會在 git worktree add 參照遠端分支時使用它。此設定未來可能會用於其他類似檢出的指令或功能。

checkout.guess

git checkoutgit switch 中的 --guess--no-guess 選項提供預設值。請參閱 git-switch[1]git-checkout[1]

checkout.workers

更新工作區時使用的平行工作執行緒數量。預設值為 1,即循序執行。如果設定為小於 1 的值,Git 將使用與可用邏輯核心數量相同的工作執行緒。此設定和 checkout.thresholdForParallelism 會影響所有執行檢出的指令。例如:checkout、clone、reset、sparse-checkout 等。

注意
平行檢出通常能為位於 SSD 或透過 NFS 存取的儲存庫提供更好的效能。對於位於傳統硬碟和/或核心數量較少的機器上的儲存庫,預設的循序檢出通常表現更好。儲存庫的大小和壓縮程度也可能影響平行版本的表現。
checkout.thresholdForParallelism

當執行檔案數量較少的平行檢出時,產生子程序和程序間通訊的成本可能會抵消平行化帶來的收益。此設定允許您定義嘗試平行檢出的最小檔案數量。預設值為 100。

GIT

git[1] 套件的一部分