Git
English ▾ 主題 ▾ 最新版本 ▾ git-checkout 最後更新於 2.44.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 [-f] <tree-ish> [--] <pathspec>…​
git checkout [-f] <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>…​]

描述

更新工作目錄中的檔案以符合索引或指定樹中的版本。如果沒有給定路徑規格(pathspec),git checkout 也會更新 HEAD 以將指定的分支設定為目前分支。

git checkout [<分支>]

為了準備在 <branch> 上工作,切換到它會更新索引和工作目錄中的檔案,並將 HEAD 指向該分支。對工作目錄中檔案的本地修改會被保留,以便將它們提交到 <branch>

如果找不到 <branch>,但在剛好一個遠端 (稱之為 <remote>) 中存在一個具有匹配名稱的追蹤分支,並且未指定 --no-guess,則將其視為等同於

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

你可以省略 <branch>,在這種情況下,命令會簡化為「檢出目前分支」,這是一個帶有相當昂貴副作用的無操作,僅用於顯示目前分支的追蹤資訊(如果存在)。

git checkout -b|-B <新分支> [<起始點>]

指定 -b 會建立一個新分支,如同呼叫 git-branch[1] 然後檢出它一樣。在這種情況下,你可以使用 --track--no-track 選項,這些選項將傳遞給 git branch。為了方便起見,沒有 -b--track 意味著建立分支;請參閱下方對 --track 的描述。

如果給定 -B,則會建立 <new-branch>(如果它不存在);否則,會重設它。這是事務等效的

$ git branch -f <branch> [<start-point>]
$ git checkout <branch>

也就是說,除非 "git checkout" 成功,否則不會重設/建立分支(例如,當分支在另一個工作樹中使用時,不僅目前分支保持不變,而且分支也不會重設為起始點)。

git checkout --detach [<分支>]
git checkout [--detach] <提交>

準備在 <commit> 之上工作,方法是將 HEAD 分離到該處 (請參閱「分離 HEAD」章節),並更新索引和工作目錄中的檔案。對工作目錄中檔案的本地修改會被保留,因此產生的工作目錄將會是提交中記錄的狀態加上本地修改。

<commit> 參數是分支名稱時,可以使用 --detach 選項將 HEAD 分離到該分支的頂端 (git checkout <branch> 將會檢出該分支而不會分離 HEAD)。

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

git checkout [-f|--ours|--theirs|-m|--conflict=<樣式>] [<樹狀物件>] [--] <路徑規格>…​
git checkout [-f|--ours|--theirs|-m|--conflict=<樣式>] [<樹狀物件>] --pathspec-from-file=<檔案> [--pathspec-file-nul]

覆寫符合路徑規格的檔案內容。當未給定 <tree-ish> (最常見的是提交) 時,使用索引中的內容覆寫工作目錄。當給定 <tree-ish> 時,使用 <tree-ish> 中的內容覆寫索引和工作目錄。

索引可能包含由於先前合併失敗而產生的未合併條目。預設情況下,如果你嘗試從索引中檢出這樣的條目,則檢出操作將會失敗,並且不會檢出任何內容。使用 -f 會忽略這些未合併的條目。可以使用 --ours--theirs 從索引中檢出合併的特定邊的內容。使用 -m 時,可以捨棄對工作目錄檔案所做的變更,以重新建立原始衝突的合併結果。

git checkout (-p|--patch) [<樹狀物件>] [--] [<路徑規格>…​]

這與先前的模式相似,但允許你使用互動式介面來顯示「差異」輸出,並選擇要在結果中使用哪些區塊。有關 --patch 選項的描述,請參閱下方。

選項

-q
--quiet

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

--progress
--no-progress

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

-f
--force

切換分支時,即使索引或工作目錄與 HEAD 不同,甚至有未追蹤的檔案在途中,也會繼續進行。這用於丟棄本地變更和任何在途中的未追蹤檔案或目錄。

從索引中檢出路徑時,不要在未合併的條目上失敗;相反地,會忽略未合併的條目。

--ours
--theirs

從索引中檢出路徑時,檢出未合併路徑的第 2 階段 (ours) 或第 3 階段 (theirs)。

請注意,在 git rebasegit pull --rebase 期間,ourstheirs 可能會交換;--ours 提供將變更重新基底到其上的分支版本,而 --theirs 提供保留您正在重新基底的工作的分支版本。

這是因為 rebase 用於將遠端的歷史記錄視為共用的標準歷史記錄,並將您正在重新基底的分支上完成的工作視為要整合的第三方工作,並且您在重新基底期間暫時承擔標準歷史記錄的保管人角色。作為標準歷史記錄的保管人,您需要將遠端的歷史記錄視為 ours (即「我們共用的標準歷史記錄」),而您在分支上所做的內容視為 theirs (即「一個貢獻者在它之上所做的工作」)。

-b <新分支>

建立一個名為 <new-branch> 的新分支,從 <start-point> 開始,並檢出結果分支;詳細資訊請參閱 git-branch[1]

-B <新分支>

建立分支 <new-branch>,從 <start-point> 開始;如果它已存在,則將它重設為 <start-point>。然後檢出結果分支。這等同於執行帶有 "-f" 的 "git branch",然後檢出該分支;詳細資訊請參閱 git-branch[1]

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

建立新分支時,設定「上游」組態。詳細資訊請參閱 git-branch[1] 中的「--track」。

如果沒有給定 -b 選項,新分支的名稱將會從遠端追蹤分支推導而來。方法是檢視為對應遠端設定的 refspec 的本地部分,然後去除開頭直到「*」的部分。這會告訴我們,當從 origin/hack(或 remotes/origin/hack,甚至是 refs/remotes/origin/hack)分支出來時,應該使用 hack 作為本地分支。如果給定的名稱沒有斜線,或上述推測產生空的名稱,則會中止推測。在這種情況下,你可以使用 -b 明確地給定名稱。

--no-track

即使 branch.autoSetupMerge 設定變數為 true,也不要設定「上游」設定。

--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」章節。

--orphan <new-branch>

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

索引和工作目錄會被調整,如同您先前執行了 git checkout <start-point>。這讓您能夠開始一個新的歷史,記錄一組與 <start-point> 相似的路徑,方法是輕鬆執行 git commit -a 來建立根 commit。

當您想要發佈一個 commit 中的樹狀結構,而不公開其完整歷史時,這會很有用。您可能想要這樣做來發佈一個專案的開源分支,該專案的當前樹狀結構是「乾淨的」,但其完整歷史包含專有或以其他方式受限的程式碼片段。

如果您想要開始一個斷開連接的歷史,記錄一組與 <start-point> 完全不同的路徑,那麼您應該在建立孤立分支後立即清除索引和工作目錄,方法是從工作目錄的頂層執行 git rm -rf .。之後,您將可以準備您的新檔案,透過從其他地方複製它們、解壓縮 tarball 等方式重新填充工作目錄。

--ignore-skip-worktree-bits

在稀疏檢出模式下,git checkout -- <paths> 將只更新 <paths>$GIT_DIR/info/sparse-checkout 中的稀疏模式所匹配的條目。此選項會忽略稀疏模式,並將 <paths> 中的任何檔案加回。

-m
--merge

當切換分支時,如果您對一個或多個檔案有本地修改,而這些檔案在當前分支和您要切換到的分支之間有所不同,則命令會拒絕切換分支,以保留您的上下文修改。但是,使用此選項,將會完成當前分支、您的工作目錄內容和新分支之間的三向合併,並且您將會位於新分支上。

當發生合併衝突時,衝突路徑的索引條目將保持未合併狀態,您需要解決衝突並使用 git add(或如果合併應導致刪除路徑,則使用 git rm)標記已解決的路徑。

當從索引檢出路徑時,此選項可讓您在指定路徑中重新建立衝突的合併。當從 tree-ish 檢出路徑時,無法使用此選項。

使用 --merge 切換分支時,已暫存的變更可能會遺失。

--conflict=<style>

與上面的 --merge 選項相同,但會變更呈現衝突區塊的方式,覆寫 merge.conflictStyle 設定變數。可能的值為「merge」(預設值)、「diff3」和「zdiff3」。

-p
--patch

互動式地選擇 <tree-ish>(如果未指定,則為索引)和工作目錄之間差異中的區塊。然後,所選的區塊會以相反的順序應用於工作目錄(如果指定了 <tree-ish>,則也會應用於索引)。

這表示您可以使用 git checkout -p 來選擇性地從目前的工作目錄中捨棄編輯。請參閱 git-add[1] 的「互動式模式」章節,以了解如何操作 --patch 模式。

請注意,此選項預設使用無覆蓋模式(另請參閱 --overlay),並且目前不支援覆蓋模式。

--ignore-other-worktrees

當所需 ref 已由另一個工作目錄檢出時,git checkout 會拒絕。此選項會讓它無論如何都檢出 ref。換句話說,該 ref 可以由多個工作目錄持有。

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

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

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

使用 --recurse-submodules 將會根據超專案中記錄的 commit 更新所有作用中子模組的內容。如果子模組中的本地修改會被覆寫,則除非使用 -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> 剛好是 -,則會使用標準輸入。Pathspec 元素以 LF 或 CR/LF 分隔。Pathspec 元素可以按照配置變數 core.quotePath 的說明進行引用(請參閱 git-config[1])。另請參閱 --pathspec-file-nul 和全域 --literal-pathspecs

--pathspec-file-nul

僅在 --pathspec-from-file 時有意義。Pathspec 元素以 NUL 字元分隔,並且所有其他字元都按字面意義解讀(包括換行符號和引號)。

<branch>

要檢出的分支;如果它指的是一個分支(也就是說,一個名稱,當在前面加上「refs/heads/」時,是一個有效的 ref),則會檢出該分支。否則,如果它指的是一個有效的 commit,則您的 HEAD 會變成「分離的」,並且您不再位於任何分支上(詳情請參閱下方)。

您可以使用 @{-N} 語法來參考使用「git checkout」操作檢出的第 N 個最後的分支/commit。您也可以指定 -,它與 @{-1} 同義。

作為一個特例,如果恰好有一個合併基礎,您可以使用 A...B 作為 AB 的合併基礎的快捷方式。您最多可以省略 AB 中的一個,在這種情況下,它會預設為 HEAD

<new-branch>

新分支的名稱。

<start-point>

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

作為一個特例,如果恰好有一個合併基礎,您可以使用 "A...B" 作為 AB 的合併基礎的快捷方式。您最多可以省略 AB 中的一個,在這種情況下,它會預設為 HEAD

<tree-ish>

要從中檢出的樹狀結構(當給定路徑時)。如果未指定,將使用索引。

作為一個特例,如果恰好有一個合併基礎,您可以使用 "A...B" 作為 AB 的合併基礎的快捷方式。您最多可以省略 AB 中的一個,在這種情況下,它會預設為 HEAD

--

不要將任何其他參數解讀為選項。

<pathspec>…​

限制受操作影響的路徑。

有關更多詳細資訊,請參閱 gitglossary[7] 中的 _pathspec_ 條目。

分離 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 是 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 操作。但是,讓我們看看當我們接著 checkout 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. 建立一個新的分支 foo,它指向 commit f,然後更新 HEAD 以指向分支 foo。換句話說,在此指令之後,我們將不再處於分離 HEAD 狀態。

  2. 類似地,建立一個新的分支 foo,它指向 commit f,但讓 HEAD 保持分離狀態。

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

如果我們已經從 commit f 移開,那麼我們必須首先恢復它的物件名稱(通常使用 git reflog),然後我們才能建立對它的參考。例如,要查看 HEAD 指向的最後兩個 commit,我們可以使用以下任一指令

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

引數消除歧義

當只給定一個引數且不是 --(例如 git checkout abc)時,並且當該引數既是有效的 <tree-ish>(例如,存在分支 abc)又是有效的 <pathspec>(例如,存在名稱為 "abc" 的檔案或目錄)時,Git 通常會要求您消除歧義。然而,由於 checkout 分支是非常常見的操作,因此 git checkout abc 在這種情況下會將 "abc" 視為 <tree-ish>。如果您想從索引中 checkout 這些路徑,請使用 git checkout -- <pathspec>

範例

1. 路徑

以下序列會 checkout 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

如果您想從索引中 checkout *所有* C 原始碼檔案,您可以這樣說

$ git checkout -- '*.c'

請注意 *.c 周圍的引號。即使 hello.c 不再位於工作樹中,它也會被 checkout,因為檔案 globbing 用於匹配索引中的條目(而不是 shell 在工作樹中)。

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

$ git checkout -- hello.c

2. 合併

在錯誤的分支上工作後,切換到正確的分支可以使用以下方式完成

$ git checkout mytopic

然而,您的「錯誤」分支和正確的 mytopic 分支可能在您已在本機修改的檔案中有所不同,在這種情況下,上述 checkout 會失敗,如下所示

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

您可以將 -m 標記給指令,這將嘗試三向合併

$ git checkout -m mytopic
Auto-merging frotz

在這種三向合併之後,本機修改 *不會* 註冊到您的索引檔案中,因此 git diff 會顯示自新分支頂端以來您所做的變更。

3. 合併衝突

當在使用 -m 選項切換分支時發生合併衝突時,您會看到類似這樣的訊息

$ git checkout -m mytopic
Auto-merging frotz
ERROR: Merge conflict in frotz
fatal: merge program failed

此時,git diff 會顯示如先前範例中乾淨地合併的變更,以及發生衝突的檔案中的變更。編輯並解決衝突,並使用 git add 像往常一樣將其標記為已解決。

$ edit frotz
$ git add frotz

組態

此區段中此行以下的所有內容都是從 git-config[1] 文件中選擇性加入的。內容與該處的內容相同

checkout.defaultRemote

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

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

checkout.guess

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

checkout.workers

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

注意:對於位於 SSD 或透過 NFS 的儲存庫,並行 checkout 通常可以提供更好的效能。對於位於旋轉磁碟和/或具有少量核心的機器上的儲存庫,預設的循序 checkout 通常效能更好。儲存庫的大小和壓縮等級也可能會影響並行版本的效能。

checkout.thresholdForParallelism

當使用少量檔案執行並行 checkout 時,子程序產生和程序間通訊的成本可能會超過並行化的收益。此設定允許您定義嘗試並行 checkout 的最小檔案數量。預設值為 100。

GIT

屬於 git[1] 套件的一部分

scroll-to-top