簡體   English   中英

為什么git會說“未暫緩提交更改”並指示子模塊文件夾?

[英]Why does git say 'Changes not staged for commit' and indicate the submodule folder?

我在另一個模塊中有一個git子模塊,可以通過git submodule add <...> (從父存儲庫發出的命令)添加,因此.gitmodules文件是在父.gitmodules庫中自動生成的。

假設我對子模塊進行了更改(編輯:並且提交這些更改),然后導航回到父模塊,並執行git add -Agit status ,它說:“未上演提交更改: 子模塊dir name 。 ..等”。

我以為git會讀取.gitmodules文件(由父git生成的文件!),實現了它的git子模塊目錄,因此當我向父文件詢問其狀態時不提及其未暫存狀態?

這里發生的是您的子模塊存儲庫處於與超級項目中記錄的哈希ID不同的提交。 您在超級項目中運行的git status告訴您這一點,而沒有更改,而git add -A顯然也沒有更改。

最后一部分似乎是錯誤的。 當我做類似的事情,然后使用git add -A ,我得到:

Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

        modified:   [submodule path]

然后,如果我再運行兩個命令,它會像我期望的那樣返回:

$ git reset
Unstaged changes after reset:
M       [submodule path]
$ git submodule update
Submodule path [path]: checked out '[hash]'
$ git status
On branch ...
nothing to commit, working tree clean

(我懷疑您已經在子模塊中進行了一些更改,但從未在此處提交過。)

發生了什么,細粒度的細節將使您診斷問題

我們有一個名為superproject的 Git存儲庫,它控制着另一個名為submodule的存儲庫。 超級項目實際上具有三個單獨的控制旋鈕,每個提交中都存在一個控制旋鈕,因此也可以在索引中找到它(因為索引控制着下一次提交的內容)。

這些控制旋鈕之一是您提到的文件.gitmodules 如果子模塊還不是git clone d,它將告訴超級項目如何克隆子模塊。 克隆子模塊后,便完成了其主要工作。

第二個是您的.git/config文件。 它包含從.gitmodules文件中復制的信息,如果.gitmodules文件不完全適合您自己的目的(可能與負責.gitmodules文件的人不同),您可以根據需要進行更新。 .git/config任何設置都將覆蓋.gitmodules 否則,這兩個放置設置在本質上是等效的。

最后一個是導致問題的原因。 為了使子模塊能夠入您的工作樹並因此對您有用,由超級項目控制的Git會啟動第二組Git命令。 通常,您可以運行:

git submodule update --init

以檢出子模塊(盡管如果您使用git clone --recursive ,Git會為您完成此操作)。

至此,超級項目Git已經建立了一個具有正確路徑的幾乎為空的目錄。 (該目錄包含一個.git文件,該文件為克隆存儲庫的路徑命名,或者在過去或者使用舊樣式的向后兼容模式時,都包含實際的.git目錄本身。)超級項目Git chdir進入該目錄,並告訴子模塊Git:

  • 運行git checkout hash

一旦發生這種情況,路徑中就會充滿從ID為hash的提交中提取的文件,這大多數會使外部Git(超項目)與文件“完成”。 但是有一個副作用,因為子模塊本身就是一個完整的Git存儲庫,包含了這一切。

特別是,子項目具有自己的HEAD 現在已經分離了這個HEAD ,並且子模塊的存儲庫的當前提交是hash ,因此它位於子模塊的索引和工作樹中,這當然是我們想要的:子模塊的工作樹是超級項目中的路徑所有子模塊文件所在的位置。

但是有一個有趣的問題要回答: 超級項目Git從哪里獲得哈希ID? 答案是:它存儲在超級項目的每個快照中(好吧,每個使用子模塊的快照),每個快照都具有每個文件的完整副本。 為此,超級項目的索引包含類型gitlink的特殊條目。

當超級項目告訴子模塊Git時,超級項目索引中的gitlink條目告訴超級項目哪個哈希ID賦予子模塊Git: 檢出一些特定的commit

如果您手動導航到子模塊,並git checkout出分支名稱或任何其他通過哈希ID提交的信息,則子模塊存儲庫的HEAD更改。 它要么成為分支名稱的附件,要么指向另一個提交,仍處於分離HEAD模式。

此時,子模塊和超級項目不同步 超級項目Git對此不做任何事情。 您可以控制,選擇所需的提交。 您甚至可以進行新的提交,然后git push它們git push到上游。 完成所需的所有提交和git checkout ,並正確安排了所有內容,您應該爬出子模塊工作樹,回到超級項目。

現在git statusgit diff會在默認情況下,有一噸的控制旋鈕的位置太告訴你,上層項目呼吁一些散列H,但子模塊具有一些其他的哈希小號簽出。 (如果設置了控制旋鈕,它們可能也可能不會告訴您子模塊本身是否需要提交。)如果希望您的下一個超級項目提交在此子模塊的gitlink中記錄此新的提交哈希S, , 你跑:

git add path-to-submodule

(或者git add -A 應該做同樣的事情,這就是令人費解的原因)。 這將更新索引中的gitlink以記錄哈希ID S而不是H ,以便下一個超級項目提交將在git submodule update命令上告訴子模塊Git: 簽出提交S,作為分離的HEAD

一旦超級項目中的索引與實際檢出的子模塊中的HEAD相匹配,該子模塊將不會未暫存的提交更改部分中列出。 如果索引中gitlink中的哈希與HEAD中gitlink中的哈希不匹配,則git status 列出要提交的更改中子模塊的路徑。

因此,當我向父母詢問其身份時,沒有提及其未分級的狀態嗎?

除非您正在使用(與Git 1.7.2或更高版本一起使用),否則它仍將報告子模塊中的更改:

您可以在此處看到原始討論(針對Git 1.7.x,是在2010年) ,它導致了該功能:

順便說一句,我認為該操作路線將使生成的git在內部保持一致,因為默認情況下,所有內容均會將其工作樹中具有未跟蹤路徑的子模塊報告為臟。

  • 在“ git status”輸出的“ Untracked”部分中,我們列出了超級項目中的未跟蹤路徑(即運行“ git status ”的路徑),以提醒用戶該路徑可能是一個忘記添加的新文件。 (除非它當然被忽略)。
    但這不會使工作樹變臟。

  • 當子模塊中有未跟蹤的路徑時:

    • 該子模塊在“已更改但未更新”部分中列出。
      即使子模塊的工作樹不是 ,這也會使超級項目的工作樹變臟。

    • 在超級項目級別的輸出“ git diff ”表明該子模塊已修改(即,顯示了“ -dirty”),但是在子模塊中運行時,未顯示任何更改。

我認為這在UI級別是錯誤的設計; 將一條未跟蹤且未被忽略的路徑報告為提醒用戶的潛在錯誤是一件好事,但是當前的方式“ status ”和“ diff ”這樣做對我來說意義不大。

暫無
暫無

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

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