簡體   English   中英

為什么我不能從淺克隆推?

[英]Why can't I push from a shallow clone?

git clone --depth命令選項說

--depth <depth> 
Create a shallow clone with a history truncated to the specified number of revisions. 
A shallow repository has a number of limitations 
(you cannot clone or fetch from it, nor push from nor into it),
 but is adequate if you are only interested in the recent history of a large project with a long history,
 and would want to send in fixes as patches. 

為什么淺克隆有這個限制? 為什么它只是補丁工作流程?

對於某些項目工作流,我只需要將來自單個分支的最新提交傳遞給編碼器,然后讓他們能夠push他們的(快進)開發push送到主服務器。 這部分是為了安全、IP 保護和 repo 大小,部分是為了減少大型 repo 會給天真的編碼員帶來的混亂。 是否有允許這樣做的 git 工作流程?


更新:根據 Karl Bielefeldt 的回答, git checkout --orphan應該是正確的答案。 但是仍然需要將該分支單獨“克隆”給新用戶,並能夠有效地推送它。

手冊頁指出:

git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>] --orphan

創建一個新的孤立分支,名為<new_branch> ,從<start_point>開始並切換到它。 在這個新分支上進行的第一次提交將沒有父級,它將成為與所有其他分支和提交完全斷開的新歷史的根。

索引和工作樹的調整就像您之前運行過git checkout <start_point> 這允許您通過輕松運行git commit -a進行根提交來開始記錄一組類似於<start_point>的路徑的新歷史記錄。

當您想從提交中發布樹而不公開其完整歷史記錄時,這會很有用。 您可能希望這樣做以發布當前樹是“干凈”的項目的開源分支,但其完整歷史包含專有或其他阻礙的代碼位。

如果要開始記錄一組與<start_point>路徑完全不同的路徑的斷開連接歷史記錄,那么您應該在創建孤立分支后立即通過運行git rm -rf .清除索引和工作樹git rm -rf . 從工作樹的頂層。 之后,您將准備好准備新文件、重新填充工作樹、從其他地方復制它們、提取 tarball 等。

VonC 指向 Junio 評論的鏈接很有趣。 我認為手冊應該在這種情況下提供指導,並允許正確的命令 [例如clone <branch> --options ] 僅提取 repo 的相關部分。 顯然,通過在歷史底部有一些鏈接提交和 SHA1 來鎖定 repo 匹配, push成功的可能性會增加。


更新 Git 1.9.0:2014 年 2 月 14 日發行說明。

“過去禁止從淺克隆存儲庫中獲取,主要是因為所涉及的代碼路徑沒有經過仔細審查,我們也沒有費心支持這種用法。此版本試圖以更可控的方式允許對象從淺克隆存儲庫中傳輸出來(即接收器變成了一個歷史被截斷的淺層存儲庫)。”

這對淺層克隆人來說是個好消息。 下一步 - 可能是窄克隆。

正如 Junio C. Hamano(主要 Git 維護者) 所說

規則是不是或多或少像:

如果您的淺層存儲庫的歷史擴展不夠長,並且另一個存儲庫在您截斷的歷史記錄之前分叉,則您無法計算共同祖先,也無法推出。

2014 年更新:請參閱“ git clone --depth 1(淺克隆)是否比它看起來更有用? ”:Git 1.9 將取消該限制!

2015 年更新:使用 Git 2.5+,您甚至可以獲取單個提交 請參閱“從遠程 git 存儲庫中提取特定提交


原始答案(2011 年 8 月):

其實仔細想想,比“不能算公”強多了。

歷史可能是這樣的:

          R---R---R
         /
  --R---R---X---X---S---S---S

其中S是您在淺層存儲庫中的提交, R是接收推送的存儲庫中存在的提交。
因為你的歷史很淺,所以兩個存儲庫都沒有“ X ”,這是為了保持接收者存儲庫的歷史完整而需要存在的提交; 接受者一開始並不膚淺,我們不想讓它變得膚淺。

如果您前段時間進行淺層克隆,在另一端進行時不與另一端通信而工作,並且如果另一端的進度包括歷史的倒帶和重建,您將看到類似的拓撲。
上圖中最左邊的 ' S ' 可能是當你以深度 1 進行淺層克隆時分支的尖端,從那時起,遠端可能已經丟棄了最上面的三個提交並重建了它的歷史記錄,導致最右邊的 ' R ' .
在這種情況下,推送到遙控器的HEAD將失敗。


所以它在某些情況下可以工作,但不受支持:

如果我必須要說些什么...

  • 我認為“不支持”是提供足夠好的信息的簡潔方式,但它只適用於聰明人。

  • 不是每個人都聰明; 有些人自己嘗試一下,發現該操作似乎對他們有限的試驗次數有效,並得出結論,它在大多數情況下都有效。
    他們祝賀自己說“大部分時間”而不是“總是”的智慧。
    當他們看到它不起作用時,他們會感到不安,即使他們已經被警告過。


有關淺克隆更新過程的更多信息,請參閱“如何更新 git 淺克隆? ”。

是否有允許這樣做的 git 工作流程?

是的,它是將修復作為補丁發送。 git format-patch專門設計用於啟用此功能。 它被稱為“看門人”工作流程,如果您想通過谷歌搜索更多詳細信息。 很難相信像您這樣關注“安全和 IP 保護”的組織還沒有使用類似的東西,其中一個人或一個小組負責在“不受信任”的更改進入實際構建之前對其進行審查。


根據您的評論,我現在對您的要求有了更好的了解。 我推薦的是創建一個孤立分支(請參閱git checkout --orphan ),無論您希望開發人員從哪個點開始。 僅將該分支克隆到這些開發人員可訪問的不同存儲庫,並讓他們從該存儲庫中正常克隆、推送和拉取。

然后,當您需要將他們的更改重新集成到官方受保護的存儲庫時,只需拉取他們的分支,使用git branch復制它,這樣您就不會覆蓋原來的孤兒(以防您以后想重復該過程),然后變基復制到您的原始分支點,然后合並或正常進行。 歷史看起來像是直接從您的受保護存儲庫中工作的。

這比正常情況要復雜一些,但這是額外隔離所付出的代價。

我找到了一個使用 git bundles 的解決方法。

此解決方案將像“git push”一樣將完全相同的提交復制到其他存儲庫,並且不需要重新定位或導致更改提交 ID。

不幸的是,它需要對目標主機進行 shell 訪問(例如 ssh)。

我將通過示例展示解決方案。

首先,為了演示目的,我們需要獲得一個淺層克隆。

讓我們從https://github.com/skarnet/s6-rc獲取單個提交版本 v0.5.0.0 作為淺克隆到一個新的存儲庫。

我將在我的示例中使用 shell 變量,而不是直接在命令中包含示例設置,因為這將允許您在將變量設置為適用於您的情況的不同值后,將本次發布的指令直接復制/粘貼到您的 shell 中.

因此,請隨意使用不同的 URL 和版本來替換以下變量分配。

在我們的示例中,可以使用以下命令創建淺克隆:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ git init ${url##*/} && cd ${url##*/}
$ git pull --depth=1 "$url" $rel:master

這將創建一個包含新克隆的“s6-src”(當使用上述變量值時)子目錄。

現在我們的淺層克隆只包含一個提交,並且在本地存儲庫中丟失了它的所有父歷史記錄,我們將這個單一提交捆綁到一個 git bundle 文件中:

$ b=$rel.gbnd
$ git bundle create $b HEAD

這將使用之前設置的 shell 變量創建文件 v0.5.0.0.gbnd。

現在您必須將此文件復制到您通常希望推送到的目標機器上。 (只有 git push 拒絕從淺克隆推送,因此不會工作,至少不會使用舊的 git 版本。)

在目標主機上,執行以下操作以創建一個新的存儲庫作為子目錄,其中包含與之前捆綁的相同的提交:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ git init ${url##*/} && cd ${url##*/}
$ c=`git bundle unbundle $b | cut -d " " -f 1`; echo "$c"
$ git tag $rel $c # optional: create a tag for the imported commit.
$ git reset --hard $c
$ git fetch --depth=1 .

請注意,您應該將變量設置為與您在從中復制包的主機上所做的相同的值。

另請注意,如果存儲庫已存在,您可以省略“git init”。

就是這樣!

但是,后面的說明僅適用於常規結帳。

也許您想將淺克隆包導入到“裸”存儲庫中。

在這種情況下,請改為執行以下操作:

$ url=https://github.com/skarnet/s6-rc
$ rel=v0.5.0.0
$ cd ${url##*/}.git
$ c=`git bundle unbundle $b | cut -d " " -f 1`; echo "$c"
$ git tag $rel $c
$ git fetch --depth=1 . $rel

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM