簡體   English   中英

如果更改了完整的文件夾結構,git如何管理跟蹤更改?

[英]How does git manage to track changes if the complete folder structure is changed?

我正在分支上工作,最近我重構了文件夾結構,很多文件在這里和那里移動了,許多文件也被重命名了。 但是當我將master(舊結構)合並到當前分支時,git能夠了解文件的位置並自動合並代碼而不會發生沖突。 這怎么可能?

“方式”分為兩部分,可以通過以下方式進行總結:

  • 對於提交 ,Git 不在乎 它只是制作快照。 無論您告訴Git使用什么文件名來保存要告訴Git使用的文件內容-在運行git commit ,所有文件內容都存儲在索引中,這就是為什么必須一直git add文件進行復制的原因他們在舊版本在索引的Git只是凍結所有這些文件,用他們的指數有現在 ,當你運行git commit 這些凍結的文件是提交的快照。

    換句話說,用git mv重新排列所有內容(這會同時更改索引和工作樹中的名稱),並根據需要使用git add更新內容,然后使用git commit ,您將獲得一個包含新名稱的新快照以及任何更新的內容。 舊的快照保持原樣:永久凍結所有現有快照,或至少在提交本身有效之前將其凍結。 (默認設置是永久保留它們。可以刪除提交,但這只是簡單的操作,除非將它們分發到其他存儲庫,此后它們將繼續從其他存儲庫重新感染您的存儲庫,即使您刪除了它們由您自己決定。)

  • 為了進行比較(包括合並),Git必須發現/檢測重命名的文件。 Git通過比較文件內容來做到這一點。

這里第二個要點的聲明實際上有點誇張,但是讓我們通過使用git diff來說明它是如何工作的,至少在我們關心的模式下,它比較了兩次提交。 請記住,每次提交都代表所有文件的完整快照。 我們將找到兩個提交的哈希ID,然后運行:

git diff --find-renames <hash of earlier commit> <hash of later commit>

此時,Git要做的是提取兩個提交中的每個提交。 (“提取”通常會盡可能地短路,這通常很多:Git通常可以直接檢查凍結的提交。但這只是速度的優化;您可以將其視為Git完全將兩個提交完全提取到一個文件中。臨時工作區。)在這里我們將較早的提交稱為提交,將較晚的提交稱為提交。 1 git diff的工作是告訴您如何將新舊更改為新 這不一定是任何進行更改的人所做的,只是一些會產生相同結果的指令。

要查找這些說明,Git將:

  • 首先,在oldnew中找到名稱完全相同的所有文件。 Git假定,如果old具有名為README的文件,而new具有名為README的文件,則這些文件必須為“相同”文件。 這些文件已配對:現在暫時將它們從等式中刪除。 Git尚未弄清楚如何更改配對文件,它只是將它們配對。

  • (您可以使用-B選項在此處插入具有一個命令的步驟。但是我們暫時將其忽略,因為這會使此過程變得復雜。)

  • 現在,如果存在未配對的文件,則這些文件代表文件丟失和/或文件中突然出現的文件...還是它們? 也許它們是已重命名的文件,在名稱中具有名稱O,在名稱中具有不同名稱N。 在這里,Git為每個可能的文件配對計算一個相似性索引號。

    為了提高速度,Git可以非常快速地將100%相同的任何兩個文件配對(一個來自文件,一個來自新文件 )。 這通常會大大縮小必須比較的文件池。

    最后,Git歸結為未配對文件,即使它們不是100%逐位相同,也應考慮配對。 Git現在對每對文件執行完全相似性索引計算(使用與Git用於打包文件中的增量壓縮相同的xdelta式代碼)。 (這實際上需要提取所有這些文件的數據。)如果得分最高的配對得分超過您選擇的最小值,則將配對得分最高的文件配對在一起,默認為“ 50%相似”。

  • 在完成所有這些額外工作后仍未配對的文件將被刪除或重新創建。 (如果您添加--find-copies--find-copies-harder --find-copies在此處引入更多的復雜性,但同樣,在這里我們將忽略它們。)

既然文件已經配對,即git diff知道文件README.md文件README.rst基本上匹配,那么這兩個文件實際上必須是一個文件,其中一個身份,而不是兩個具有兩個身份的不同文件— 現在, Git會比較每個配對的文件以產生指令:

  • - :從的文件版本中刪除此行
  • + :將此行添加到文件的版本中

如果您遵守所有的指示,包括在上面給出任何“這個文件重命名”命令,將改變發現,在發現一個文件。


1如果願意,可以反轉哈希ID。 然后,Git將告訴您如何將較新的提交轉換為較舊的提交。


git merge如何使用git diff

合並兩個提交時,Git使用提交圖(通過查看每個提交的父哈希或哈希表將所有單個提交連接到一個大DAG中而形成的有向非循環圖)來找到最佳的公共祖先提交。 該提交是兩個指定提交的合並基礎

實際上, git merge命令運行兩個 git diff命令。 兩者都啟用--find-renames ,相似性閾值默認為50%。 您可以使用-X find-renames=<number>更改此閾值,以允許對名稱不匹配的文件進行更多或更少的配對。

這兩個差異是:

git diff --find-renames <hash of merge base> <hash of HEAD commit>

和:

git diff --find-renames <hash of merge base> <hash of other commit>

兩個diff在內部git diff期間根據需要對任何未配對的文件名進行相似度計算。

並發症

添加-B告訴Git 破壞自動配對的文件:僅僅因為在兩次提交中文件都被命名為README並不意味着它實際上是同一文件。 例如,如果您將README重命名為old/README ,然后將new/README重命名為README怎么辦? 在這種情況下,Git將在我之前提到的那個步驟中對自動配對的文件進行相似度計算。 如果相似度太低 ,Git將破壞配對。 稍后,如果相似度是不是太極低 ,配對保持斷開,Git會重新加入兩個文件,所以-B使用兩個數字,不只是一個。

merge命令不允許您提供-B參數。 (可以說。)

如果您使用--find-copies--find-copies-harder ,則Git將查看部分或全部源(“舊”)文件,以查看是否從中復制了新創建的目標(“ new”)文件。它。 這些使用相同的相似性索引。 此步驟在重命名檢測之后發生,並且有時再次將修改后的文件視為可能的源,這再次是因為計算量很大。

merge命令也不允許您指定查找副本選項。

暫無
暫無

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

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