[英]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
提交之間重命名/移動的文件(又名“與未修改的比較”)。
例如:
Foo.txt
和Bar.txt
。Foo.txt
重命名為Qux.txt
(並且不進行其他更改)。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.cs
、 SingleClass2.cs
等文件的同時刪除了 1 個文件( MultipleClassesw.cs
)。
SingleClass1.cs
為MultipleClasses.cs
/ TFS。 但是,正如您可以想象的那樣,有時git
的啟發式方法不起作用,您需要使用--follow
和/或--find-renames=<percentage>
(又名-M<percentage>
)來刺激它。
我個人的首選做法是將基於文件系統和編輯代碼文件的更改保留在單獨的 git 提交中(因此提交僅包含已編輯的文件,或僅添加+刪除的文件,或僅拆分更改),這樣您就可以git 的--follow
啟發式檢測重命名/移動要容易得多。
考慮這種情況:
Project/Foobar.cs
的文件,其中包含class Foobar
。 該文件只有大約 1KB 大小。class Foobar
重命名為class Barfoo
。
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.cs
與Foobar.cs
有 1% 的不同,所以它認為重命名/移動而不是刪除+添加或編輯,因此 Visual Studio 的解決方案資源管理器將使用該文件旁邊的“移動/重命名”git 狀態圖標,而不是“已編輯文件”或“新文件”狀態圖標。Barfoo.cs
進行了超過默認更改百分比閾值 50%的更實質性更改(尚未提交),則解決方案資源管理器將開始顯示“新文件”圖標而不是“重命名/移動文件”圖標。
Barfoo.cs
的一些更改(同樣:尚未保存任何提交),使其低於 50% 更改閾值,那么 VS 的解決方案資源管理器將再次顯示重命名圖標。 git
沒有在提交中存儲實際文件重命名/移動的一個巧妙之處在於,這意味着您可以安全地將git
與任何軟件一起使用,包括任何重命名/移動文件的軟件! 尤其是不支持源代碼控制的軟件。
因此,Visual Studio(有或沒有git
支持)無需通知git
文件已重命名/移動。
事實上,git 提交不是增量,而是快照,這意味着您可以更輕松地重新排序提交,並以最小的痛苦重新調整整個分支。 這在 SVN 或 TFS 中根本不可能實現。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.