簡體   English   中英

如何在 Visual Studio 中執行 git 移動,而不是 git 刪除和 git 添加,重命名時,在解決方案資源管理器中移動文件?

[英]How to perform git move in Visual Studio, instead of git delete and git add, when renaming, moving files in Solution Explorer?

語境

我經常在 Visual Studio 2022 中移動、重命名文件。重命名是一種標准的重構實踐。 但是,當我在解決方案資源管理器中重命名文件時,不會執行git mv操作,而是執行 git 刪除和 git 添加。

這會導致丟失該特定文件/類的歷史記錄,這在許多情況下是一個巨大的損失。

問題

我可以離開 IDE 並使用命令行進行移動操作

git mv myoldfile.cs mynewfile.cs

這將完美地保留歷史,但留下 IDE 是生產力殺手,尤其是在談論重構和重命名多個類/文件時。

如何在 Visual Studio 中執行git mv ,而不是 git 刪除和 git 添加,重命名時,在解決方案資源管理器中移動文件?

首先,讓我們澄清一些誤解......

  • git提交是給定時間點的整個倉庫的快照。
  • git提交不是差異或變更集。
  • git提交不包含任何文件“重命名”信息。
  • 並且git本身不會記錄、監視、記錄或以其他方式關注被移動或重命名的文件( ...在創建提交時)。

以上可能是違反直覺的,甚至對某些人(包括我自己,當我第一次了解到這一點時)來說甚至令人震驚,因為它與之前所有主要的源代碼控制系統(如 SVN、TFS、ZCC8D68C5501C4A9ADDZD531到 Helix)相反和其他人,因為所有這些系統存儲差異或變更集,這是他們模型的基礎。

在內部, git確實使用了各種 forms 的差異和增量壓縮,但是這些都是故意對用戶隱藏的,因為它們被認為是實現細節。 這是因為 git 的域 model完全建立在原子提交的概念之上,它代表了整個 repo 在特定時間點的快照 state。 此外,使用操作系統的低級文件更改檢測功能來檢測哪些特定文件已更改,而無需重新掃描整個工作目錄:在 Linux/POSIX 上,它使用lstat ,在 Windows 上(其中lstat不可用) 它使用fscache 當 git 計算您的存儲庫的哈希時,它使用默克爾樹結構來避免必須不斷地重新計算存儲庫中每個文件的 hash。

那么git如何處理移動或重命名的文件呢?

...但是我的git GUI 清楚地顯示了文件重命名,而不是文件刪除+添加或編輯!

  • 雖然git存儲有關文件重命名的信息,但它仍然能夠啟發式檢測任何兩個 git 提交之間的重命名文件,以及檢測在未提交的 repo 的工作目錄樹和HEAD提交之間重命名/移動的文件(又名“與未修改的比較”)。

  • 例如:

    • 考慮使用 2 個文件提交“快照 1”: Foo.txtBar.txt
    • 然后將Foo.txt重命名為Qux.txt (並且不進行其他更改)。
    • 然后將其保存為新提交(“快照 2”)。
    • 如果您要求git “快照 1”和“快照 2”,那么diff可以看到Foo.txt已重命名為Qux.txt (並且Bar.txt未更改),因為內容(以及因此文件的加密哈希)是相同,因此它推斷文件從Foo.txt重命名為Qux.txt
      • 有趣的事實:如果您要求git執行相同的差異,但使用“快照 2”作為基本提交並使用“快照 1”作為后續提交,那么 git 將顯示它檢測到從Qux.txt重命名回Foo.txt
  • 但是,如果您不只是在兩次提交之間重命名或移動文件,例如同時編輯文件,那么 git可能會或可能不會將文件視為新的單獨文件而不是重命名的文件。

    • 這不是一個錯誤,而是一個特性:這種行為意味着git可以處理常見的文件系統級重構操作(如拆分文件),比以文件為中心的源代碼控制(如 TFS 和 SVN)要好得多,而且你也不會看到與重構相關的錯誤重命名
    • 例如,考慮一個重構場景,您將包含多個class定義的MultipleClasses.cs文件拆分為單獨的.cs文件,每個文件一個class 在這種情況下,不會執行真正的“重命名”,並且git的差異會顯示在添加新SingleClass1.csSingleClass2.cs等文件的同時刪除了 1 個文件( MultipleClassesw.cs )。
      • 我想如果您允許將第一個重命名SingleClass1.csMultipleClasses.cs / TFS。
  • 但是,正如您可以想象的那樣,有時git的啟發式方法不起作用,您需要使用--follow和/或--find-renames=<percentage> (又名-M<percentage>來刺激它。

  • 我個人的首選做法是將基於文件系統和編輯代碼文件的更改保留在單獨的 git 提交中(因此提交包含已編輯的文件,或添加+刪除的文件,或拆分更改),這樣您就可以git 的--follow啟發式檢測重命名/移動要容易得多。

    • (這確實意味着在使用 VS 的重構重命名功能 fwiw 時,我確實需要暫時重命名文件,因此我可以使用已編輯的文件進行提交,但沒有任何重命名的文件)。

但是,這與 Visual Studio 有什么關系?

  • 考慮這種情況:

    • 您有一個 C# 項目的現有 git 存儲庫,沒有待處理的更改(分階段或其他)。 該項目有一個位於Project/Foobar.cs的文件,其中包含class Foobar 該文件只有大約 1KB 大小。
    • 然后,您使用 Visual Studio 的Refactor > Rename...功能將class Foobar重命名為class Barfoo
      • Visual Studio 不僅class Foobar重命名為class Barfoo編輯項目中其他地方出現的所有Foobar ,而且還將Foobar.cs重命名為Barfoo.cs
      • 在此示例中,標識符Foobar僅在 1KB 大小的Foobar.cs文件中出現兩次(首先在class Foobar中,然后再次在構造函數定義中Foobar() {} )因此僅更改了 12 個字節(2 * 6 個字符) . 在一個 1KB 的文件中,這是 1% 的變化( 12 / 1024 == 0.0117 --> 1.17% )。
      • git (和 Visual Studio 的內置git GUI)只看到最后一次提交Foobar.cs ,並看到當前的 HEAD (帶有未提交的更改)有Barfoo.csFoobar.cs有 1% 的不同,所以它認為重命名/移動而不是刪除+添加或編輯,因此 Visual Studio 的解決方案資源管理器將使用該文件旁邊的“移動/重命名”git 狀態圖標,而不是“已編輯文件”或“新文件”狀態圖標。
      • 但是,如果您對Barfoo.cs進行了超過默認更改百分比閾值 50%的更實質性更改(尚未提交),則解決方案資源管理器將開始顯示“新文件”圖標而不是“重命名/移動文件”圖標。
        • 如果您手動恢復對Barfoo.cs的一些更改(同樣:尚未保存任何提交),使其低於 50% 更改閾值,那么 VS 的解決方案資源管理器將再次顯示重命名圖標。
  • git沒有在提交中存儲實際文件重命名/移動的一個巧妙之處在於,這意味着您可以安全地將git與任何軟件一起使用,包括任何重命名/移動文件的軟件! 尤其是不支持源代碼控制的軟件。

    • 以前,使用 SVN 和 TFS,您需要將自己限制在內置支持您正在使用的任何源代碼控制系統(並自行處理重命名)或支持 MSSCCI 的軟件(因此通過 MSSCCI 保存重命名)的軟件程序中,否則您必須使用單獨的 SVN 或 TFS 客戶端來保存/提交您的文件重命名(例如分別為 TortoiseSvn 和 Team Foundation Explorer)。 這是一個乏味且容易出錯的過程,我很高興看到它的結束。
  • 因此,Visual Studio(有或沒有git支持)無需通知git文件已重命名/移動。

    • 這就是為什么沒有 IDE 支持它的原因:因為根本不需要它。
  • 事實上,git 提交不是增量,而是快照,這意味着您可以更輕松地重新排序提交,並以最小的痛苦重新調整整個分支。 這在 SVN 或 TFS 中根本不可能實現。

    • (畢竟,您如何才能有意義地重新排序文件重命名操作?)

暫無
暫無

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

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