繁体   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