簡體中文 ▾ 主題 ▾ 最新版本 ▾ git-checkout 上次更新於 2.50.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>…​]

描述

更新工作區中的檔案,使其與索引或指定樹中的版本匹配。如果未指定路徑,git checkout 還會更新 HEAD 以將指定分支設定為當前分支。

git checkout [<branch>]

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

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

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

你可以省略 <branch>,在這種情況下,該命令會退化為“檢出當前分支”,這實際上是一個花哨的空操作,但會產生相當昂貴的副作用,即僅顯示當前分支的跟蹤資訊(如果存在)。

git checkout (-b|-B) <new-branch> [<start-point>]

指定 -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 [<branch>]
git checkout [--detach] <commit>

透過將 HEAD 分離到 <commit> 上(參見“分離 HEAD”章節),並更新索引和工作區中的檔案,準備在 <commit> 之上工作。工作區中檔案的本地修改會保留,因此最終的工作區將是提交中記錄的狀態加上本地修改。

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

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

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

覆蓋與路徑匹配的檔案內容。如果未指定 <tree-ish>(通常是一個提交),則用索引中的內容覆蓋工作區。如果指定了 <tree-ish>,則用 <tree-ish> 中的內容覆蓋索引和工作區。

索引可能包含由於之前失敗的合併而產生的未合併條目。預設情況下,如果你嘗試從索引中檢出此類條目,檢出操作將失敗,並且不會檢出任何內容。使用 -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 (ours) 或 #3 (theirs)。

請注意,在執行 git rebasegit pull --rebase 時,ourstheirs 可能會互換;--ours 提供更改被 rebase 到其上的分支的版本,而 --theirs 提供包含你正在 rebase 的工作的分支的版本。

這是因為 rebase 在一個工作流中使用,該工作流將遠端倉庫的歷史視為共享的規範歷史,並將你在正在 rebase 的分支上所做的工作視為要整合的第三方工作,並且你在 rebase 期間暫時承擔著規範歷史維護者的角色。作為規範歷史的維護者,你需要將來自遠端倉庫的歷史視為 ours(即“我們共享的規範歷史”),而將你在旁支上所做的工作視為 theirs(即“一位貢獻者在其上所做的工作”)。

-b <new-branch>

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

-B <new-branch>

建立分支 <new-branch>,從 <start-point> 開始;如果它已經存在,則將其重置到 <start-point>。然後檢出生成的分支。這等同於執行帶有 -fgit branch,然後檢出該分支;有關詳細資訊,請參見 git-branch[1]

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

建立新分支時,設定“upstream”配置。有關詳細資訊,請參見 git-branch[1] 中的 --track

如果沒有給出 -b 選項,新分支的名稱將從遠端跟蹤分支派生,方法是檢視為相應遠端配置的引用規範的本地部分,然後剝離直到“*”的初始部分。這將告訴我們在從 origin/hack(或 remotes/origin/hack,甚至 refs/remotes/origin/hack)分支時,使用 hack 作為本地分支名稱。如果給定的名稱沒有斜槓,或者上述猜測導致名稱為空,則猜測中止。在這種情況下,你可以使用 -b 顯式指定名稱。

--no-track

不設定“upstream”配置,即使 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

建立新分支的引用日誌;有關詳細資訊,請參見 git-branch[1]

-d
--detach

不是檢出一個分支來在其上工作,而是檢出一個提交用於檢查和可丟棄的實驗。這是當 <commit> 不是分支名稱時,git checkout <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>(如果未指定,則為索引)與工作區之間差異中的程式碼塊(hunks)。然後將選定的程式碼塊反向應用於工作區(如果指定了 <tree-ish>,則也應用於索引)。

這意味著你可以使用 git checkout -p 從當前工作區中選擇性地丟棄編輯。有關如何操作 --patch 模式的詳細資訊,請參見 git-add[1] 的“互動模式”章節。

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

--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>

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

--pathspec-file-nul

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

<分支>

要檢出的分支;如果它指向一個分支(即,一個加上“refs/heads/”字首後是有效引用的名稱),那麼將檢出該分支。否則,如果它指向一個有效的提交,你的 HEAD 將變為“分離”狀態,你將不再位於任何分支上(詳見下文)。

你可以使用 @{-N} 語法來引用使用“git checkout”操作檢出的倒數第 N 個分支/提交。你也可以指定 -,它等同於 @{-1}

作為特例,如果 <rev-a><rev-b> 只有一個合併基準,你可以使用 <rev-a>...<rev-b> 作為它們的合併基準的快捷方式。你可以最多省略 <rev-a><rev-b> 中的一個,在這種情況下它預設為 HEAD

<新分支>

新分支的名稱。

<起始點>

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

作為特例,如果 <rev-a><rev-b> 只有一個合併基準,你可以使用 <rev-a>...<rev-b> 作為它們的合併基準的快捷方式。你可以最多省略 <rev-a><rev-b> 中的一個,在這種情況下它預設為 HEAD

<樹物件>

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

作為特例,如果 <rev-a><rev-b> 只有一個合併基準,你可以使用 <rev-a>...<rev-b> 作為它們的合併基準的快捷方式。你可以最多省略 <rev-a><rev-b> 中的一個,在這種情況下它預設為 HEAD

--

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

<路徑規範>...

限制受操作影響的路徑。

有關更多詳細資訊,請參閱 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. 類似地,建立了一個指向提交 f 的新分支 foo,但保留了分離的 HEAD

  3. 建立了一個指向提交 f 的新標籤 foo,保留了分離的 HEAD

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

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

引數消歧

當只給定一個引數且不是 --(例如 git checkout abc),並且該引數既是一個有效的 <樹物件>(例如,分支 abc 存在)又是一個有效的 <路徑規範>(例如,名為“abc”的檔案或目錄存在)時,Git 通常會要求你進行消歧。然而,由於檢出分支是一個非常常見的操作,在這種情況下,git checkout abc 將“abc”視為一個 <樹物件>。如果你想從索引中檢出這些路徑,請使用 git checkout -- <路徑規範>

示例

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> 並且只有一個遠端倉庫時,它可能會隱式地回退到檢出和跟蹤例如 origin/<something>。一旦你有多個包含 <something> 引用的遠端倉庫,這將停止工作。此設定允許指定一個首選遠端倉庫的名稱,該遠端倉庫在消歧時應始終優先。典型的用例是將其設定為 origin

目前,當 git checkout <something>git switch <something> 將檢出另一個遠端倉庫上的 <something> 分支時,此設定被 git-switch[1]git-checkout[1] 使用;當 git worktree add 引用遠端分支時,此設定被 git-worktree[1] 使用。將來,此設定可能會用於其他類似檢出命令或功能。

checkout.guess

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

checkout.workers

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

注意
並行檢出通常對於位於 SSD 或透過 NFS 的倉庫提供更好的效能。對於位於旋轉磁碟和/或核心數量較少的機器上的倉庫,預設的順序檢出通常表現更好。倉庫的大小和壓縮級別也可能影響並行版本的效能。
checkout.thresholdForParallelism

當並行檢出少量檔案時,子程序生成和程序間通訊的開銷可能超過並行化帶來的收益。此設定允許你定義應嘗試並行檢出的最小檔案數量。預設值為 100。

GIT

Git[1] 套件的一部分

scroll-to-top