簡體中文 ▾ 主題 ▾ 最新版本 ▾ git-checkout 上次更新於 2.52.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>和當前提交的內容不同,並且存在任何未提交的更改,則簽出將失敗。否則,未提交的更改將被保留。

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

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

執行git checkout而不指定分支不會產生任何效果,除了列印當前分支的跟蹤資訊。

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

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

如果檢出<new-branch>時發生錯誤,例如檢出<start-point>提交會覆蓋您的未提交更改,則此操作將失敗。

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

-b相同,但如果分支已存在,則將<branch>重置為起始點,而不是失敗。

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

git checkout <branch>相同,但不同的是,它將HEAD指向提交ID,而不是指向分支。更多資訊請參閱下文的“分離 HEAD”部分。

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

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

將指定的檔案和/或目錄替換為給定提交或樹的版本,並將其新增到索引(也稱為“暫存區”)。

例如,git checkout main file.txt會將file.txt替換為來自main的版本。

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

將指定的檔案和/或目錄替換為索引中的版本。

例如,如果您檢出一個提交,編輯了file.txt,然後決定那些更改是錯誤的,git checkout file.txt將丟棄對file.txt的所有未暫存的更改。

如果檔案存在合併衝突,並且您尚未執行git add file.txt(或等效命令)來標記它已解決,則此操作將失敗。您可以使用-f來忽略未合併的檔案而不是失敗,使用--ours--theirs來用合併的特定一側的版本替換它們,或者使用-m來用原始的合併衝突結果替換它們。

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

這與前兩種模式類似,但允許您使用互動式介面顯示“diff”輸出並選擇要在結果中使用哪些塊。有關--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>

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

-B <new-branch>

-b相同,但如果分支已存在,則將<branch>重置為起始點,而不是失敗。

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

建立新分支時,設定“上游”配置。有關詳細資訊,請參閱git-branch[1]中的--track。為了方便起見,不帶-b的--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

不是檢出一個分支來對其進行操作,而是檢出一個提交以供檢查和可丟棄的實驗。這是git checkout <commit><commit>不是分支名時的預設行為。有關詳細資訊,請參閱“分離 HEAD”部分。

--orphan <new-branch>

建立一個名為<new-branch>的新無父分支,從<start-point>開始並切換到它。在此新分支上進行的第一個提交將沒有父提交,並且將是全新歷史的根,與所有其他分支和提交完全斷開連線。

索引和工作樹將被調整,就好像您之前運行了git checkout <start-point>一樣。這允許您透過方便地執行git commit -a來建立一個記錄一組與<start-point>相似的路徑的新歷史,從而進行根提交。

當您想釋出提交中的樹而不暴露其完整歷史時,此功能很有用。您可能希望這樣做是為了釋出專案的開源分支,該分支的當前樹是“乾淨的”,但其完整歷史包含專有的或受其他限制的程式碼。

如果您想開始一個記錄與<start-point>的路徑集完全不同的歷史,那麼您應該在建立孤兒分支後立即清空索引和工作樹,方法是從工作樹的頂層執行git rm -rf .。之後,您就可以準備新的檔案,透過從其他地方複製、提取tarball等方式來重新填充工作樹。

--ignore-skip-worktree-bits

在稀疏檢出模式下,git checkout -- <path>... 將僅更新與<paths>$GIT_DIR/info/sparse-checkout中的稀疏模式匹配的條目。此選項將忽略稀疏模式,並重新新增<path>...中的任何檔案。

-m
--merge

切換分支時,如果您對當前分支和要切換到的分支之間存在差異的一個或多個檔案有本地修改,則命令將拒絕切換分支以在上下文中保留您的修改。但是,使用此選項,將在當前分支、您的工作樹內容和新分支之間執行三向合併,然後您將位於新分支上。

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

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

使用--merge切換分支時,暫存的更改可能會丟失。

--conflict=<style>

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

-p
--patch

互動式地選擇<tree-ish>(或未指定時為索引)與工作樹之間的差異中的塊。然後,選定的塊將以相反的方式應用於工作樹(如果指定了<tree-ish>,則應用於索引)。

這意味著您可以使用git checkout -p選擇性地丟棄當前工作樹中的編輯。有關如何操作--patch模式,請參閱git-add[1]的“互動模式”部分。

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

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

生成具有 <n> 行上下文的 diff。如果配置選項未設定,則預設為 diff.context 或 3。

--inter-hunk-context=<n>

在差異塊之間顯示上下文,最多達指定行數 <number>,從而合併彼此接近的塊。預設為 diff.interHunkContext,如果未設定配置選項則為 0。

--ignore-other-worktrees

git checkout在要檢出的分支已被檢出或被另一個工作樹使用時拒絕。此選項使其無論如何都檢出該分支。換句話說,一個分支可以被多個工作樹使用。

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

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

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

使用--recurse-submodules將根據父專案記錄的提交更新所有活動子模組的內容。如果子模組中的本地修改將被覆蓋,則簽出將失敗,除非使用-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 元素由 LFCR/LF 分隔。Pathspec 元素可以按 core.quotePath 配置變數的解釋進行引用(參見 git-config[1])。另請參見 --pathspec-file-nul 和全域性 --literal-pathspecs

--pathspec-file-nul

僅在與 --pathspec-from-file 一起使用時有意義。路徑規範元素由 NUL 字元分隔,所有其他字元都被視為字面值(包括換行符和引號)。

<branch>

要檢出的分支;如果它指向一個分支(即,一個在前面加上“refs/heads/”後是有效引用名稱),則檢出該分支。否則,如果它指向一個有效的提交,您的HEAD將變為“分離”,並且您將不再處於任何分支上(有關詳細資訊,請參閱下文)。

您可以使用@{-N}語法來引用使用“git checkout”操作簽出的第N個最後分支/提交。您還可以指定-,它與@{-1}同義。

作為特殊情況,您可以將<rev-a>...<rev-b>用作<rev-a><rev-b>的合併基的快捷方式,前提是隻有一個合併基。您可以省略<rev-a><rev-b>中的最多一個,在這種情況下,它預設為HEAD

<new-branch>

新分支的名稱。

<start-point>

作為新分支起點的提交的名稱;有關詳細資訊,請參閱git-branch[1]。預設為HEAD

作為特殊情況,您可以將<rev-a>...<rev-b>用作<rev-a><rev-b>的合併基的快捷方式,前提是隻有一個合併基。您可以省略<rev-a><rev-b>中的最多一個,在這種情況下,它預設為HEAD

<tree-ish>

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

作為特殊情況,您可以將<rev-a>...<rev-b>用作<rev-a><rev-b>的合併基的快捷方式,前提是隻有一個合併基。您可以省略<rev-a><rev-b>中的最多一個,在這種情況下,它預設為HEAD

--

不再將任何後續引數解釋為選項。

<pathspec>...

限制受操作影響的路徑。

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

分離 HEAD

HEAD通常指向一個命名分支(例如master)。同時,每個分支指向一個特定的提交。讓我們看一個包含三個提交的倉庫,其中一個已標記,並且master分支已被檢出

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

在此狀態下建立提交時,分支將被更新以指向新提交。具體來說,git commit建立一個新的提交d,其父提交是c,然後更新master分支以指向新的提交dHEAD仍然指向master分支,因此間接指向提交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')

有時能夠檢出一個不屬於任何命名分支尖端的提交,甚至建立一個不被命名分支引用的新提交是有用的。讓我們看看當我們檢出提交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')

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

$ 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')

現在有一個新的提交e,但它只被HEAD引用。當然,我們可以在這種狀態下再新增一個提交

$ 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')

重要的是要認識到,在這一點上,沒有任何東西指向提交f。最終,提交f(以及因此的提交e)將被常規的Git垃圾回收過程刪除,除非我們在此之前建立了一個引用。如果我們還沒有離開提交f,那麼任何這些命令都會建立一個引用指向它

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

  2. 類似地建立了一個名為foo的新分支,它指向提交f,但使HEAD處於分離狀態。

  3. 建立一個名為foo的新標籤,它指向提交f,使HEAD處於分離狀態。

如果我們已經離開了提交f,那麼我們必須先恢復它的物件名稱(通常透過使用git reflog),然後我們才能建立一個引用指向它。例如,要檢視HEAD指向的最後兩個提交,我們可以使用以下任一命令

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

引數歧義

當您執行git checkout <something>時,Git會嘗試猜測<something>是打算作為分支、提交還是檔案集,然後切換到該分支或提交,或恢復指定的檔案。

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

git checkout -- file.txt

示例

1. 路徑

以下序列檢出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. 從另一個提交中取出檔案

  3. 從索引中恢復hello.c

如果要從索引中檢出所有 C 原始檔,您可以這樣做

$ git checkout -- '*.c'

請注意*.c周圍的引號。檔案hello.c也將被檢出,儘管它不再在工作樹中,因為檔案萬用字元用於匹配索引中的條目(而不是shell在工作樹中的匹配)。

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

$ git checkout -- hello.c

2. 合併

在錯誤的分支上工作後,切換到正確的分支將透過以下方式完成

$ git checkout mytopic

但是,您的“錯誤”分支和正確mytopic分支可能在您本地修改過的檔案中有所不同,在這種情況下,上述檢出將像這樣失敗

$ 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> 且只有一個遠端時,它可能會隱式地回退到簽出和跟蹤 e.g. origin/<something>。一旦您有多個具有 *<something>* 引用的遠端,這種情況就會停止工作。此設定允許設定一個首選遠端的名稱,該名稱在歧義化時應始終優先。典型用例是將其設定為 origin

目前,它由 git-switch[1]git-checkout[1] 使用,當 git checkout <something>git switch <something> 會簽出另一個遠端上的 *<something>* 分支時,以及由 git-worktree[1] 使用,當 git worktree add 指的是遠端分支時。此設定將來可能會用於其他類似 checkout 的命令或功能。

checkout.guess

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

checkout.workers

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

注意
並行 checkout 通常可以提高位於 SSD 或 NFS 上的儲存庫的效能。對於旋轉硬碟和/或核心數較少的機器上的儲存庫,預設的順序 checkout 通常效能更好。儲存庫的大小和壓縮級別也可能影響並行版本的效能。
checkout.thresholdForParallelism

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

GIT

Git[1] 套件的一部分