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

名稱

git-push - 更新遠端參照及相關物件

概要

git push [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
	 [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose]
	 [-u | --set-upstream] [-o <string> | --push-option=<string>]
	 [--[no-]signed | --signed=(true|false|if-asked)]
	 [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]
	 [--no-verify] [<repository> [<refspec>…​]]

描述

將本地儲存庫中的一個或多個分支、標籤或其他參照更新到一個或多個遠端儲存庫,並傳送所有遠端尚未擁有的必要資料。

最簡單的推送方式是 git push <remote> <branch>git push origin main 會將本地 main 分支推送至名為 origin 之遠端上的 main 分支。

您也可以透過使用「遠端群組」同時推送到多個遠端。遠端群組是透過 git 設定檔中的 remotes.<name> 配置的遠端命名清單。

$ git config remotes.all-remotes "origin gitlab backup"

那麼 git push all-remotes 將會依序推送到 origingitlabbackup,就像您分別對每個遠端執行 git push 一樣。每個遠端都使用其各自的推送映射配置獨立進行推送。設定檔中會有一個 remotes.<group> 項目。(請參閱 git-config[1])。

<repository> 參數預設為目前分支的上游(upstream),若未配置上游則預設為 origin

Git 使用以下優先順序決定要推送哪些分支、標籤或其他參照:

  1. <refspec> 參數(例如 git push origin main 中的 main)或 --all--mirror--tags 選項。

  2. 針對所推送儲存庫的 remote.<name>.push 設定。

  3. push.default 設定。預設值為 push.default=simple,它會推送到與目前分支同名的分支。有關 push.default 的更多資訊,請參閱下方的 配置 (CONFIGURATION) 章節。

根據 push.default 的設定,若您未設定目前分支的上游,git push 可能會失敗。有關如何設定與使用上游分支的更多資訊,請參閱下方的 上游分支 (UPSTREAM BRANCHES) 章節。

您可以透過在儲存庫中設定「掛鉤」(hooks),使每次推送到儲存庫時觸發特定動作。請參閱 git-receive-pack[1] 的說明文件。

選項 (OPTIONS)

<repository>

作為推送操作目的地的「遠端」儲存庫。此參數可以是 URL(請參閱下方的 GIT URLS 章節)、遠端名稱(請參閱下方的 REMOTES 章節),或遠端群組名稱(請參閱下方的 遠端群組 (REMOTE GROUPS) 章節)。

<refspec>...

指定要以什麼來源物件更新什麼目的參照。

參照規格 (refspec) 的格式為 [+]<src>[:<dst>],例如 mainmain:otherHEAD^:refs/heads/main

<src> 通常是要推送的本地分支名稱,但也可以是任何任意的「SHA-1 表達式」(請參閱 gitrevisions[7])。

<dst> 決定遠端要更新哪個參照。它必須是分支、標籤或其他參照的名稱,不能是任意表達式。

+ 是選擇性的,其作用與 --force 相同。

您可以使用完全展開的形式撰寫參照規格(例如 refs/heads/main:refs/heads/main)來明確指定來源與目的地,或是使用簡短形式(例如 mainmain:other)。以下是參照規格展開的規則,以及各種其他的特殊參照規格形式:

  • <src> 若不含 :<dst>,表示更新與 <src> 相同的參照,除非 remote.<repository>.push 設定指定了不同的 <dst>。例如,若 main 是一個分支,則參照規格 main 會展開為 main:refs/heads/main

  • <dst> 明確指向 <repository> 遠端上的一個參照,則將其展開為該參照。例如,若 v1.0 是遠端上的一個標籤,則 HEAD:v1.0 會展開為 HEAD:refs/tags/v1.0

  • <src> 解析為以 refs/heads/refs/tags/ 開頭的參照,則將其前綴加到 <dst> 之前。例如,若 main 是一個分支,則 main:other 會展開為 main:refs/heads/other

  • 特殊的參照規格 :(或 +: 以允許非快轉更新)指示 Git 推送「匹配的」分支:對於本地端存在的每個分支,若遠端也存在同名分支,則更新該遠端分支。

  • <src> 可能包含 * 以表示簡單的模式匹配。這就像一個 glob,匹配任何符合該模式的參照。在 <src><dst> 中必須只有一個 *。它會將從來源匹配到的內容替換掉 *,藉此映射參照到目的地。例如,refs/heads/*:refs/heads/* 將會推送所有分支。

  • ^ 開頭的參照規格是負向參照規格,用於指定要排除的參照。如果一個參照至少匹配一個正向參照規格,且不匹配任何負向參照規格,則視為匹配。負向參照規格可以是模式參照規格,且必須只包含一個 <src>。不支援完整拼寫的十六進制物件名稱。例如,git push origin refs/heads/*' ^refs/heads/dev-*' 將會推送所有分支,但排除以 dev- 開頭的分支。

  • <src> 為空,則從遠端儲存庫中刪除 <dst> 參照。例如,git push origin :dev 將會刪除 dev 分支。

  • tag <tag> 會展開為 refs/tags/<tag>:refs/tags/<tag>。技術上,這對於 git push 來說是一種特殊語法,而非參照規格,因為在 git push origin tag v1.0 中,tagv1.0 是獨立的參數。

  • 若參照規格無法明確展開,則會報錯,指出嘗試了哪些操作,並根據 advice.pushUnqualifiedRefname 設定(參閱 git-config[1])建議您可能想要推送到的 refs/ 命名空間。

並非所有更新都允許:詳情請參閱下方的「推送規則 (PUSH RULES)」。

--all
--branches

推送所有分支(即 refs/heads/ 下的參照);不可與其他 <refspec> 一起使用。

--prune

移除本地不存在對應分支的遠端分支。例如,若本地已不存在名為 tmp 的分支,則遠端的 tmp 分支將被移除。此選項也遵循參照規格,例如 git push --prune remote refs/heads/*:refs/tmp/* 將確保若 refs/heads/foo 不存在,則遠端的 refs/tmp/foo 也會被移除。

--mirror

不指定要推送的每個參照,而是指定將 refs/ 下的所有參照(包含但不限於 refs/heads/refs/remotes/refs/tags/)鏡像到遠端儲存庫。新建立的本地參照會推送到遠端,本地更新的參照會強制更新遠端,被刪除的參照也會從遠端移除。若設定了設定選項 remote.<remote>.mirror,此選項為預設行為。

-n
--dry-run

執行除了實際發送更新之外的所有操作(模擬測試)。

--porcelain

產生機器可讀的輸出。每個參照的輸出狀態行將以定位字元 (tab) 分隔,並傳送到標準輸出 (stdout) 而非標準錯誤 (stderr)。會提供參照的完整符號名稱。

-d
--delete

所有列出的參照都將從遠端儲存庫刪除。這與在所有參照前面加上冒號效果相同。

--tags

除了命令列上明確列出的參照規格外,還會推送 refs/tags 下的所有參照。

--follow-tags

推送在沒有此選項時會推送的所有參照,同時也會推送 refs/tags 中遠端缺失的註釋標籤 (annotated tags),前提是該標籤指向可從被推送參照到達的提交 (commit-ish)。此選項也可透過設定變數 push.followTags 指定。有關更多資訊,請參閱 git-config[1] 中的 push.followTags

--signed
--no-signed
--signed=(true|false|if-asked)

對推送請求進行 GPG 簽署以更新接收端的參照,以便供掛鉤進行檢查或記錄。可能的值為:

false
--no-signed

不嘗試任何簽署。

true
--signed

若伺服器不支援簽署推送,則推送將會失敗。

if-asked

僅在伺服器支援簽署推送時才進行簽署。如果呼叫 gpg --sign 本身失敗,推送也會失敗。請參閱 git-receive-pack[1] 以了解接收端的詳細資訊。

--atomic
--no-atomic

若支援,則在遠端使用原子交易。要麼更新所有參照,要麼在出錯時完全不更新。若伺服器不支援原子推送,則推送將會失敗。

-o <option>
--push-option=<option>

將指定的字串傳輸給伺服器,伺服器會將其傳遞給 pre-receive 及 post-receive 掛鉤。指定的字串不得包含 NULLF 字元。當給定多個 --push-option=<option> 時,它們會按照命令列中列出的順序全部傳送到另一端。當命令列沒有給定 --push-option=<option> 時,則會改用設定變數 push.pushOption 的值。

--receive-pack=<git-receive-pack>
--exec=<git-receive-pack>

遠端 git-receive-pack 程式的路徑。在透過 SSH 推送到遠端儲存庫,且該程式不在預設 $PATH 的目錄中時很有用。

--force-with-lease
--no-force-with-lease
--force-with-lease=<refname>
--force-with-lease=<refname>:<expect>

通常,git push 會拒絕更新非本地參照祖先的遠端參照。

若遠端參照的目前值符合預期值,此選項會覆寫該限制。否則 git push 將失敗。

想像一下您必須重寫(rebase)已經發布的內容。您必須繞過「必須快轉 (must fast-forward)」的規則,以用重寫後的歷史記錄取代您原本發布的歷史記錄。如果您在重寫時,其他人基於您的原始歷史記錄進行了開發,遠端分支頂端可能已推進到他們的提交,盲目地使用 --force 推送將會丟失他們的工作。

此選項允許您聲明您預期的更新歷史記錄正是您重寫並想取代的內容。如果遠端參照仍然指向您指定的提交,您可以確信沒有其他人對該參照進行了任何變更。這就像是在參照上設定一個「租約 (lease)」而無需明確鎖定,且只有在「租約」仍然有效時,遠端參照才會被更新。

單獨使用 --force-with-lease(不指定細節)將透過要求所有即將更新的遠端參照其目前值必須與我們本地持有的遠端追蹤分支相同,來保護這些參照。

--force-with-lease=<refname>(不指定預期值)將保護 <refname>(僅該參照),如果它即將被更新,它要求其目前值必須與我們本地持有的遠端追蹤分支相同。

--force-with-lease=<refname>:<expect> 將保護 <refname>(僅該參照),如果它即將被更新,它要求其目前值必須與指定的 <expect> 值相同(該值允許與我們持有的遠端追蹤分支不同,甚至在這種形式下,我們根本不必持有該參照的遠端追蹤分支)。若 <expect> 為空字串,則指定的參照必須尚不存在。

請注意,除了明確指定參照預期目前值的 --force-with-lease=<refname>:<expect> 之外,所有其他形式仍處於實驗階段,且其語義可能會隨著我們在此功能的經驗累積而改變。

--no-force-with-lease 將取消命令列上所有之前的 --force-with-lease 選項。

關於安全性的一般說明:在沒有提供預期值的情況下使用此選項(即 --force-with-lease--force-with-lease=<refname>),會與任何在後台隱式執行 git fetch 的操作(例如您的儲存庫在 cron 排程中執行的 git fetch origin)產生嚴重的衝突。

它相比 --force 提供的保護是確保您的工作所依據之外的後續變更不會被覆蓋,但若有後台程序在背景更新參照,這很容易失效。我們除了遠端追蹤資訊外,沒有其他資訊可以作為您預期已見過且願意覆蓋的參照之啟發式依據。

如果您的編輯器或其他系統在背景為您執行 git fetch,緩解此問題的方法是簡單地設定另一個遠端:

git remote add origin-push $(git config remote.origin.url)
git fetch origin-push

現在,當後台程序執行 git fetch origin 時,origin-push 上的參照將不會被更新,因此如下的命令:

git push --force-with-lease origin-push

將會失敗,除非您手動執行 git fetch origin-push。當然,執行 git fetch --all 的程序會完全使此方法失效,在這種情況下,您需要停用該程序或採取更繁瑣的做法:

git fetch              # update 'master' from remote
git tag base master    # mark our base point
git rebase -i master   # rewrite some commits
git push --force-with-lease=master:base master:master

即為您已見過且願意覆蓋的上游程式碼版本建立一個 base 標籤,然後重寫歷史記錄,最後在遠端版本仍處於 base 時強制推送變更到 master,而不論您的本地 remotes/origin/master 在後台被更新成了什麼。

或者,在「推送」時將 --force-if-includes 作為輔助選項與 --force-with-lease[=<refname>](即不說明遠端參照必須指向哪個確切提交,或哪些遠端參照正受到保護)一起指定,將會在允許強制更新之前,驗證那些可能已在背景隱式更新的遠端追蹤參照是否已整合到本地。

-f
--force

通常,git push 會拒絕更新並非所推送提交之祖先的分支。

此旗標會停用該檢查、下方「推送規則 (PUSH RULES)」中的其他安全檢查,以及 --force-with-lease 中的檢查。它可能導致遠端儲存庫丟失提交;請小心使用。

請注意,--force 適用於所有被推送的參照,因此將其與設為 matchingpush.default,或與配置了多個推送目的地的 remote.<name>.push 一起使用時,可能會覆蓋目前分支以外的參照(包括落後於遠端對應項的本地參照)。若要強制推送至單一分支,請在參照規格前加上 +(例如 git push origin +master 以強制推送至 master 分支)。詳情請參閱上方的 <refspec>... 章節。

--force-if-includes
--no-force-if-includes

僅在遠端追蹤參照的頂端已整合到本地時,才強制進行更新。

此選項啟用一項檢查,驗證遠端追蹤參照的頂端是否可從重寫的分支所基於的本地分支的「reflog」條目中到達。該檢查確保了來自遠端的任何更新已整合到本地,若非如此則拒絕強制更新。

若在未指定 --force-with-lease 的情況下傳遞此選項,或與 --force-with-lease=<refname>:<expect> 一起指定,則該選項為「空操作 (no-op)」。

指定 --no-force-if-includes 會停用此行為。

--repo=<repository>

此選項等同於 <repository> 參數。若兩者皆指定,則以命令列參數為準。

-u
--set-upstream

對於每個已更新或成功推送的分支,新增上游(追蹤)參照,供不帶參數的 git-pull[1] 及其他命令使用。有關更多資訊,請參閱 git-config[1] 中的 branch.<name>.merge

--thin
--no-thin

這些選項會傳遞給 git-send-pack[1]。當傳送方和接收方共用許多相同物件時,薄傳輸 (thin transfer) 會顯著減少傳送的資料量。預設值為 --thin

-q
--quiet

除非發生錯誤,否則隱藏所有輸出,包括已更新參照的清單。進度不會報告到標準錯誤串流。

-v
--verbose

詳細執行模式。

--progress

當標準錯誤串流連接到終端時,預設會報告進度狀態,除非指定了 -q。即使標準錯誤串流未導向終端,此標記也會強制顯示進度狀態。

--no-recurse-submodules
--recurse-submodules=(check|on-demand|only|no)

可用於確保所有被推送修訂版本所使用的子模組提交在遠端追蹤分支上均可用。可能的值為:

check

Git 將會驗證在被推送修訂版本中變更的所有子模組提交,是否至少在子模組的一個遠端上可用。若有任何提交遺失,推送將被中止並以非零狀態退出。

on-demand

所有在被推送修訂版本中變更的子模組都將被推送。若 on-demand 無法推送所有必要的修訂版本,它也會被中止並以非零狀態退出。

only

所有子模組都將被推送,而超級專案(superproject)保持不推送狀態。

no

當不需要子模組遞迴時,覆寫 push.recurseSubmodules 設定變數。類似於使用 --no-recurse-submodules

當使用 on-demandonly 時,若子模組具有 push.recurseSubmodules=(on-demand|only)submodule.recurse 設定,將會發生進一步的遞迴。在此情況下,only 被視為 on-demand

--verify
--no-verify

切換 pre-push 掛鉤(參閱 githooks[5])。預設值為 --verify,讓掛鉤有機會防止推送。使用 --no-verify 時,掛鉤將被完全繞過。

-4
--ipv4

僅使用 IPv4 位址,忽略 IPv6 位址。

-6
--ipv6

僅使用 IPv6 位址,忽略 IPv4 位址。

GIT URL

通常,URL 包含有關傳輸協定、遠端伺服器位址以及儲存庫路徑的資訊。根據傳輸協定的不同,其中一些資訊可能會缺失。

Git 支援 ssh、git、http 和 https 協定(此外,ftp 和 ftps 可用於擷取,但效率低下且已棄用;請勿使用它們)。

原生傳輸(即 git:// URL)不進行身份驗證,在不安全的網路上應謹慎使用。

可以與它們一起使用以下語法:

  • ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>

  • git://<host>[:<port>]/<path-to-git-repo>

  • http[s]://<host>[:<port>]/<path-to-git-repo>

  • ftp[s]://<host>[:<port>]/<path-to-git-repo>

類似 scp 的替代語法也可以與 ssh 協定一起使用:

  • [<user>@]<host>:/<path-to-git-repo>

只有在第一個冒號之前沒有斜線時,才能識別此語法。這有助於區分包含冒號的本地路徑。例如,本地路徑 foo:bar 可以指定為絕對路徑或 ./foo:bar 以避免被誤解為 ssh url。

ssh 和 git 協定另外支援 ~<username> 展開:

  • ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo>

  • git://<host>[:<port>]/~<user>/<path-to-git-repo>

  • [<user>@]<host>:~<user>/<path-to-git-repo>

對於 Git 原生支援的本地儲存庫,可以使用以下語法:

  • /path/to/repo.git/

  • file:///path/to/repo.git/

這兩種語法基本等價,除了在複製時,前者隱含了 --local 選項。詳情請參閱 git-clone[1]

git clonegit fetchgit pull(但不是 git push)也接受適當的 bundle 檔案。請參閱 git-bundle[1]

當 Git 不知道如何處理某種傳輸協定時,它會嘗試使用 remote-<transport> 遠端輔助程式(如果存在)。要顯式請求遠端輔助程式,可以使用以下語法:

  • <transport>::<address>

其中 <address> 可以是路徑、伺服器和路徑,或被調用的特定遠端輔助程式識別的任意類 URL 字串。詳情請參閱 gitremote-helpers[7]

如果有大量名稱相似的遠端儲存庫,並且您想為它們使用不同的格式(以便您使用的 URL 會被重寫為可用的 URL),您可以建立如下形式的設定區段:

	[url "<actual-url-base>"]
		insteadOf = <other-url-base>

例如,有了這個:

	[url "git://git.host.xz/"]
		insteadOf = host.xz:/path/to/
		insteadOf = work:

像 "work:repo.git" 或 "host.xz:/path/to/repo.git" 這樣的 URL 在任何接受 URL 的情境下都會被重寫為 "git://git.host.xz/repo.git"。

如果您只想重寫用於推送的 URL,您可以建立如下形式的設定區段:

	[url "<actual-url-base>"]
		pushInsteadOf = <other-url-base>

例如,有了這個:

	[url "ssh://example.org/"]
		pushInsteadOf = git://example.org/

像 "git://example.org/path/to/repo.git" 這樣的 URL 在推送時會被重寫為 "ssh://example.org/path/to/repo.git",但拉取時仍會使用原始 URL。

遠端 (REMOTES)

下列各項之一的名稱可用於代替 <repository> 參數:

  • Git 設定檔中的一個遠端: $GIT_DIR/config

  • $GIT_DIR/remotes 目錄中的一個檔案,或

  • $GIT_DIR/branches 目錄中的一個檔案。

所有這些都允許您在命令列中省略 refspec,因為它們各包含一個 git 預設使用的 refspec。

設定檔中的命名遠端

您可以選擇提供您之前使用 git-remote[1]git-config[1] 甚至手動編輯 $GIT_DIR/config 檔案設定的遠端名稱。該遠端的 URL 將用於存取儲存庫。當您在命令列中未提供 refspec 時,預設會使用該遠端的 refspec。設定檔中的項目如下所示:

	[remote "<name>"]
		url = <URL>
		pushurl = <pushurl>
		push = <refspec>
		fetch = <refspec>

<pushurl> 僅用於推送。它是選用的,預設為 <URL>。推送到遠端會影響所有定義的 pushurl,如果沒有定義 pushurl,則影響所有定義的 url。然而,如果定義了多個 url,擷取 (fetch) 僅會從第一個定義的 url 擷取。

$GIT_DIR/remotes 中的命名檔案

您可以選擇提供 $GIT_DIR/remotes 中檔案的名稱。此檔案中的 URL 將用於存取儲存庫。當您在命令列中未提供 refspec 時,此檔案中的 refspec 將作為預設值。此檔案應具有以下格式:

	URL: one of the above URL formats
	Push: <refspec>
	Pull: <refspec>

Push: 行由 git push 使用,而 Pull: 行由 git pullgit fetch 使用。可以指定多個 Push:Pull: 行以用於額外的分支對應。

$GIT_DIR/branches 中的命名檔案

您可以選擇提供 $GIT_DIR/branches 中檔案的名稱。此檔案中的 URL 將用於存取儲存庫。此檔案應具有以下格式:

	<URL>#<head>

<URL> 是必需的; #<head> 是選用的。

根據操作,如果您未在命令列提供 refspec,git 將使用以下 refspec 之一。 <branch> 是此檔案在 $GIT_DIR/branches 中的名稱,且 <head> 預設為 master

git fetch 使用:

	refs/heads/<head>:refs/heads/<branch>

git push 使用:

	HEAD:refs/heads/<head>

上游分支

Git 中的分支可以選擇性地擁有一個上游遠端分支。Git 預設在遠端操作中使用上游分支,例如:

  • 它是無參數 git pullgit fetch 的預設值。

  • 它是無參數 git push 的預設值(有一些例外)。例如,您可以使用 branch.<name>.pushRemote 選項推送到與拉取來源不同的遠端,而且預設情況下在 push.default=simple 時,您設定的上游分支必須具有相同名稱。

  • 各種命令(包括 git checkoutgit status)將顯示自從您分叉以來,目前分支和上游分支各自增加了多少個提交,例如 "Your branch and origin/main have diverged, and have 2 and 3 different commits each respectively"(您的分支與 origin/main 已分叉,且分別有 2 個和 3 個不同的提交)。

上游儲存在 .git/config 的 "remote" 和 "merge" 欄位中。例如,如果 main 的上游是 origin/main

[branch "main"]
   remote = origin
   merge = refs/heads/main

您可以透過 git push --set-upstream <remote> <branch> 顯式設定上游分支,但 Git 通常會自動為您設定上游,例如:

  • 當您複製儲存庫時,Git 會自動為預設分支設定上游。

  • 如果您設定了 push.autoSetupRemote 設定選項,git push 會在您第一次推送分支時自動設定上游。

  • 使用 git checkout <branch> 切換到一個遠端追蹤分支,會自動建立一個同名的本地分支並將其上游設定為該遠端分支。

注意
上游分支有時被稱為「追蹤資訊」,如「設定分支的追蹤資訊」。

遠端群組 (REMOTE GROUPS)

遠端群組是透過 git 設定檔中的 remotes.<name> 配置的遠端命名清單。

$ git config remotes.all-remotes "r1 r2 r3"

當群組名稱作為 <repository> 參數給出時,推送會依序執行到每個成員遠端。定義原則是:

git push <options> all-remotes <args>

完全等同於:

git push <options> r1 <args>
git push <options> r2 <args>
...
git push <options> rN <args>

其中 r1, r2, …​, rN 是 all-remotes 的成員。沒有增加或刪除任何特殊行為——群組純粹是針對每個成員遠端單獨執行相同推送命令的簡寫。

當推送到多個遠端的群組時,Git 會為每個成員遠端按順序啟動一個單獨的 git push 子程序。每個子程序接收與原始呼叫相同的旗標和參照規格。這意味著透過 remote.<name>.push 配置的每個遠端推送映射和鏡像模式 (remote.<name>.mirror) 都會針對每個遠端獨立評估,並且群組中的鏡像遠端不會影響群組中其他非鏡像遠端的推送行為。

--atomic 選項不支援群組推送,因為原子性只能在單一傳輸連線到單一遠端時得到保證。若將 --atomic 與群組名稱結合使用,Git 將拒絕執行並報錯。

如果任何成員遠端失敗(無論是因為推送被拒絕,例如非快轉更新、伺服器端掛鉤拒絕參照,還是因為連線錯誤,例如儲存庫不存在、身份驗證失敗或網路不可達),Git 會報告錯誤並繼續推送到群組中的其餘遠端。若有任何成員推送失敗,整體退出代碼將為非零值。

這意味著使用者有責任確保個別推送的順序合理。如果對於給定的選項和參數,git push r1 會失敗,那麼 git push all-remotes 在到達 r1 時也會以同樣方式失敗。群組推送不會執行任何特殊操作來使個別失敗的推送成功。

輸出

"git push" 的輸出取決於所使用的傳輸方法;此章節描述透過 Git 協定(本地或透過 SSH)推送時的輸出。

推送的狀態以表格形式輸出,每一行代表單個參照的狀態。每一行的形式為:

 <flag> <summary> <from> -> <to> (<reason>)

若使用 --porcelain,則輸出行的形式為:

 <flag> \t <from>:<to> \t <summary> (<reason>)

僅當使用 --porcelain--verbose 選項時,才會顯示已保持最新參照的狀態。

<flag>

一個單一字元,指示參照的狀態:

(空格)

表示成功推送快轉;

+

表示成功強制更新;

-

表示成功刪除參照;

*

表示成功推送新參照;

!

表示參照被拒絕或推送失敗;以及

=

表示參照已保持最新,無需推送。

<summary>

對於成功推送的參照,摘要會以適合用作 git log 參數的形式顯示參照的新舊值(多數情況下為 <old>..<new>,強制非快轉更新則為 <old>...<new>)。

對於失敗的更新,會提供更多細節:

rejected

Git 完全沒有嘗試傳送該參照,通常是因為它不是快轉更新,且您沒有強制執行更新。

remote rejected

遠端拒絕了該更新。通常是由於遠端的掛鉤導致,或是因為遠端儲存庫啟用了以下安全選項之一:receive.denyCurrentBranch(針對推送到已檢出的分支)、receive.denyNonFastForwards(針對強制非快轉更新)、receive.denyDeletesreceive.denyDeleteCurrent。請參閱 git-config[1]

remote failure

遠端未回報參照更新成功,可能是由於遠端的臨時錯誤、網路連線中斷或其他瞬態錯誤所致。

from

正在被推送的本地參照名稱,減去其 refs/<type>/ 前綴。若為刪除操作,則省略本地參照名稱。

to

正在被更新的遠端參照名稱,減去其 refs/<type>/ 前綴。

reason

人類可讀的解釋。對於成功推送的參照,不需要解釋。對於失敗的參照,會描述失敗的原因。

推送規則 (PUSH RULES)

作為一項安全功能,git push 命令僅允許特定類型的更新,以防止您意外丟失遠端資料。

由於分支和標籤的使用方式不同,推送到分支的安全規則與推送到標籤的規則不同。在以下規則中,「更新」指除刪除和建立之外的任何修改。刪除和建立始終被允許,除非被配置或掛鉤禁止。

  1. 若推送目的地為分支 (refs/heads/*):僅允許快轉更新,這意味著目的地必須是來源提交的祖先。來源必須是提交。

  2. 若推送目的地為標籤 (refs/tags/*):所有更新將被拒絕。來源可以是任何物件。

  3. 若推送目的地既不是分支也不是標籤:

    • 若來源是樹狀物件 (tree) 或二進位大物件 (blob),任何更新都將被拒絕。

    • 若來源是標籤物件或提交物件,則允許任何快轉更新,即使快轉的目標不是提交,而是正好指向一個新提交的標籤物件(該新提交是其所取代之最後標籤/提交的快轉)。若標籤指向相同的提交,也允許用完全不同的標籤替換該標籤,此外也允許推送被剝離的標籤 (peeled tag),即推送現有標籤物件指向的提交,或是現有提交指向的新標籤物件。

您可以透過傳遞 --force 或在參照規格前添加選用的 + 來覆寫這些規則。唯一的例外是,無論如何強制,分支都不會接受非提交物件,且強制執行也不會使遠端儲存庫接受其配置為拒絕的推送。

掛鉤和配置也可以覆寫或修訂這些規則,例如請參閱 git-config[1] 中的 receive.denyNonFastForwardsreceive.denyDeletes,以及 githooks[5] 中的 pre-receiveupdate

關於快轉 (FAST-FORWARDS) 的說明

當更新將一個分支(或更一般地說,一個參照)從原本指向提交 A 改為指向另一個提交 B 時,若且唯若 B 是 A 的後代,則稱為快轉更新。

在從 A 到 B 的快轉更新中,原始提交 A 所基於的提交集,是新提交 B 所基於提交集的子集。因此,它不會丟失任何歷史記錄。

相反,非快轉更新會丟失歷史記錄。例如,假設您和其他人從同一個提交 X 開始,您建立了一個導致提交 B 的歷史記錄,而對方建立了一個導致提交 A 的歷史記錄。歷史記錄看起來像這樣:

      B
     /
 ---X---A

進一步假設對方已經將導致 A 的變更推回了你們兩人都取得原始提交 X 的原始儲存庫。

對方的推送更新了原本指向提交 X 的分支,使其現在指向提交 A。這是一次快轉。

但如果您嘗試推送,您將嘗試用提交 B 更新該分支(現在指向 A)。這不是快轉。如果您這樣做了,提交 A 所引入的變更將會丟失,因為每個人現在都會開始基於 B 進行建構。

為了防止這種歷史記錄的丟失,該命令預設不允許非快轉的更新。

如果您不想丟失自己的工作(從 X 到 B 的歷史記錄)或對方的工作(從 X 到 A 的歷史記錄),您需要先從儲存庫抓取 (fetch) 歷史記錄,建立一個包含雙方變更的歷史記錄,然後將結果推回。

您可以執行 "git pull",解決潛在衝突,然後 "git push" 結果。一個 "git pull" 會在提交 A 和 B 之間建立一個合併提交 C。

      B---C
     /   /
 ---X---A

用結果的合併提交更新 A 將會進行快轉,並且您的推送將會被接受。

或者,您可以使用 git pull --rebase 將您在 X 和 B 之間的變更重寫到 A 之上,並將結果推回。Rebase 將建立一個新的提交 D,該提交將 X 和 B 之間的變更建構在 A 之上。

      B   D
     /   /
 ---X---A

同樣,用此提交更新 A 將會進行快轉,並且您的推送將會被接受。

還有另一種常見情況是,當您嘗試推送時會遇到非快轉拒絕,即使是在推送到沒有其他人推送的儲存庫時也是可能的。在您自己推送提交 A 後(本節的第一張圖),使用 git commit --amend 取代它以產生提交 B,然後您嘗試將其推送出去,因為忘了您已經推送了 A。在這種情況下,且僅當您確定沒有人在此期間抓取了您較早的提交 A(並基於它開始建構)時,您可以執行 git push --force 來覆蓋它。換句話說,git push --force 是一種保留給您確實打算丟失歷史記錄的情況下的方法。

範例

git push

運作方式類似 git push <remote>,其中 <remote> 是目前分支的遠端(若目前分支未配置遠端,則預設為 origin)。

git push origin

在沒有額外配置的情況下,如果目前分支與配置的上游(branch.<name>.merge 設定變數)同名,則將目前分支推送到該上游,否則報錯並不進行推送。

此命令在未給定 <refspec> 時的預設行為,可以透過設定遠端的 push 選項或 push.default 設定變數來配置。

例如,若要預設僅推送目前分支到 origin,請使用 git config remote.origin.push HEAD。任何有效的 <refspec>(如下面的範例)都可以設定為 git push origin 的預設值。

git push origin :

推送「匹配的」分支到 origin。有關「匹配的」分支的描述,請參閱上方「選項 (OPTIONS)」章節中的 <refspec>

git push origin master

在來源儲存庫中尋找與 master 匹配的參照(極可能找到 refs/heads/master),並用它更新 origin 儲存庫中的相同參照(例如 refs/heads/master)。若遠端原本不存在 master,則會建立它。

git push origin HEAD

一種方便將目前分支推送到遠端同名分支的方式。

git push mothership master:satellite/master dev:satellite/dev

使用匹配 master 的來源參照(例如 refs/heads/master)來更新 mothership 儲存庫中匹配 satellite/master 的參照(極可能是 refs/remotes/satellite/master);對 devsatellite/dev 也執行相同操作。

有關匹配語義的討論,請參閱上方描述 <refspec>... 的章節。

這是為了模擬在 mothership 上使用 git push 執行的 git fetch,該命令以相反方向執行,以便整合在 satellite 上完成的工作。當您只能以一種方式進行連線(即 satellite 可以 SSH 進入 mothership,但 mothership 因防火牆或未執行 sshd 而無法主動發起連線到 satellite)時,這通常是必要的。

satellite 電腦上執行此 git push 後,您將 SSH 進入 mothership 並在那裡執行 git merge,以完成在 mothership 上 pull 在 satellite 所做變更的 git pull 模擬。

git push origin HEAD:master

將目前分支推送到 origin 儲存庫中匹配 master 的遠端參照。此形式便於推送目前分支,而無需考慮其本地名稱。

git push origin master:refs/heads/experimental

透過複製目前的 master 分支,在 origin 儲存庫中建立 experimental 分支。僅在需要於遠端儲存庫中建立新分支或標籤且本地名稱與遠端名稱不同時,才需要此形式;否則直接使用參照名稱即可。

git push origin :experimental

origin 儲存庫中尋找與 experimental 匹配的參照(例如 refs/heads/experimental),並將其刪除。

git push origin +dev:master

使用 dev 分支更新 origin 儲存庫的 master 分支,並允許非快轉更新。這可能會導致 origin 儲存庫中留下懸空的未引用提交。 考慮以下無法進行快轉的情況:

	    o---o---o---A---B  origin/master
		     \
		      X---Y---Z  dev

上述命令會將 origin 儲存庫更改為:

		      A---B  (unnamed branch)
		     /
	    o---o---o---X---Y---Z  master

提交 A 和 B 將不再屬於任何具有符號名稱的分支,因此將無法到達。因此,這些提交將會被 origin 儲存庫上的 git gc 命令移除。

安全性

擷取 (fetch) 和推送協並非設計用於防止一側從另一儲存庫竊取不打算共享的數據。如果您有需要保護免受惡意同行侵害的私有數據,最好的選擇是將其儲存在另一個儲存庫中。這適用於客戶端和伺服器。特別是,伺服器上的命名空間對於讀取存取控制無效;您只應向信任其具有整個儲存庫讀取權限的客戶端授予對命名空間的讀取權限。

已知的攻擊向量如下:

  1. 受害者發送 "have" 行,宣傳其擁有的、並非明確打算共享但如果同行也擁有則可用於優化傳輸的物件 ID。攻擊者選擇一個要竊取的物件 ID X 並發送一個指向 X 的參照,但不需要發送 X 的內容,因為受害者已經擁有它。現在受害者相信攻擊者擁有 X,稍後它會將 X 的內容發送回給攻擊者。(這種攻擊對於客戶端在伺服器上執行最為直接,即在客戶端有權存取的命名空間中建立一個指向 X 的參照,然後擷取它。伺服器在客戶端上執行此操作的最可能方式是將 X「合併」到公共分支中,並希望使用者在該分支上進行額外工作並將其推回伺服器而未察覺合併。)

  2. 與第 1 點相同,攻擊者選擇一個要竊取的物件 ID X。受害者發送一個攻擊者已經擁有的物件 Y,而攻擊者虛假聲稱擁有 X 而不擁有 Y,因此受害者將 Y 作為針對 X 的差異 (delta) 發送。該差異向攻擊者揭示了 X 中與 Y 相似的區域。

配置 (CONFIGURATION)

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

push.autoSetupRemote

若設定為 true,則在目前分支沒有上游追蹤時,預設推送會假設有 --set-upstream;此選項對 push.defaultsimpleupstreamcurrent 選項生效。若您希望預設情況下將新分支推送到預設遠端(如同 push.default=current 的行為),並且希望同時設定上游追蹤,此選項非常有用。此選項最適合預期所有分支在遠端皆擁有相同名稱的 simple 中央工作流程。

push.default

定義若未給定參照規格(無論是從命令列、設定或其他地方),git push 應採取的動作。不同的值適用於特定的工作流程;例如,在純粹的中央工作流程(即抓取來源等於推送目的地)中,upstream 可能正是您想要的。可能的值為:

nothing

除非給定參照規格,否則不推送任何內容(報錯)。這主要是為了希望透過總是明確操作來避免錯誤的使用者所設計。

current

推送目前分支以更新接收端同名的分支。適用於中央和非中央工作流程。

upstream

將目前分支推回至通常會將變更整合到目前分支的分支(稱為 @{upstream})。此模式僅在您推送到通常會從那裡抓取的相同儲存庫時才有意義(即中央工作流程)。

tracking

這是 upstream 已棄用的同義詞。

simple

推送目前分支至遠端的同名分支。

此模式要求必須已知要推送到的遠端儲存庫。當推回至您抓取時的相同遠端時,目前分支還必須擁有同名的上游追蹤分支。

此模式是 Git 2.0 以來的預設值,也是適合初學者的最安全選項。

matching

推送兩端具有相同名稱的所有分支。這使得您推送到的儲存庫會記住將會推送出去的分支集合(例如,如果您總是將 maintmaster 推送到那裡而沒有其他分支,您推送到的儲存庫將會有這兩個分支,且您的本地 maintmaster 將會被推送到那裡)。

要有效地使用此模式,您必須確保在執行 git push 之前,所有您打算推送出去的分支都已準備好,因為此模式的全部目的就是允許您一次推送所有分支。如果您通常只完成一個分支的工作並推送結果,而其他分支尚未完成,則此模式不適合您。此外,此模式也不適合推送到共用的中央儲存庫,因為其他人可能會在那裡添加新分支,或是在您的控制之外更新現有分支的頂端。

這曾經是預設值,但自 Git 2.0 以來不再是(simple 是新的預設值)。

push.followTags

若設定為 true,則預設啟用 --follow-tags 選項。您可以在推送時透過指定 --no-follow-tags 來覆寫此配置。

push.gpgSign

可設定為布林值或字串 if-asked。設定為 true 值會導致所有推送皆進行 GPG 簽署,如同向 git-push[1] 傳遞了 --signed。字串 if-asked 會在伺服器支援時簽署推送,如同向 git push 傳遞了 --signed=if-asked。false 值可能會覆寫低優先權設定檔中的值。明確的命令列旗標總是會覆寫此設定選項。

push.pushOption

當命令列中沒有給定 --push-option=<option> 參數時,git push 的行為就好像此變數的每個 <option> 都作為 --push-option=<option> 給出了一樣。

這是一個多值變數,且可以在高優先權設定檔(例如儲存庫中的 .git/config)中使用空值,以清除從低優先權設定檔(例如 $HOME/.gitconfig)繼承的值。

Example:

/etc/gitconfig
  push.pushoption = a
  push.pushoption = b

~/.gitconfig
  push.pushoption = c

repo/.git/config
  push.pushoption =
  push.pushoption = b

This will result in only b (a and c are cleared).
push.recurseSubmodules

可能是 checkon-demandonlyno,其行為與 push --recurse-submodules 相同。若未設定,則預設使用 no,除非設定了 submodule.recurse(在此情況下,true 值意味著 on-demand)。

push.useForceIfIncludes

若設定為 true,則等同於在命令列向 git-push[1] 指定 --force-if-includes 選項。在推送時添加 --no-force-if-includes 會覆寫此設定。

push.negotiate

若設定為 true,則嘗試透過客戶端與伺服器嘗試尋找共同提交的談判輪次,來縮減傳送的 packfile 大小。若為 false,Git 將僅依賴伺服器的參照廣告來尋找共同提交。

push.useBitmaps

若設定為 false,則停用 git push 使用 bitmaps,即使 pack.useBitmapstrue,且不會阻止其他 git 操作使用 bitmaps。預設值為 true

GIT

git[1] 套件的一部分