g.p*_*dou 21 git visual-studio
语境
我经常在 Visual Studio 2022 中移动、重命名文件。重命名是标准的重构实践。但是,当我在解决方案资源管理器中重命名文件时,不会git mv
执行任何操作,而是执行 git delete 和 git add 。
这会导致丢失该特定文件/类的历史记录,这在许多情况下都是巨大的损失。
问题
我可以离开 IDE 并使用命令行来执行移动操作
git mv myoldfile.cs mynewfile.cs
Run Code Online (Sandbox Code Playgroud)
这将完美地保留历史记录,但离开 IDE 会成为生产力杀手,尤其是在谈论重构和重命名多个类/文件时。
在解决方案资源管理器中重命名、移动文件时,如何git mv
在 Visual Studio 中执行,而不是 git delete 和 git add?
Dai*_*Dai 24
git
是整个存储库在给定时间点的快照。git
不是差异或变更集。git
不包含任何文件“重命名”信息。git
它本身不会记录、监视、记录或以其他方式关注移动或重命名的文件(...在创建提交时)。上述内容可能是反直觉的,甚至对某些人(包括我自己,当我第一次了解到这一点时)来说是令人兴奋的,因为它与所有主要的先前源代码控制系统(如 SVN、TFS、CSV、Perforce (Helix 之前))相反等等,因为所有这些系统都存储差异或变更集,并且这是它们模型的基础。
在内部,git
确实使用了各种形式的比较和增量压缩,但是这些是故意对用户隐藏的,因为它们被认为是实现细节。这是因为 git 的域模型完全建立在原子提交的概念之上,原子提交代表整个存储库在特定时间点的快照状态。此外,使用操作系统的低级文件更改检测功能来检测哪些特定文件已更改,而无需重新扫描整个工作目录:在 Linux/POSIX 上它使用lstat
,在 Windows 上(lstat
不可用)它使用fscache
. 当 git 计算存储库的哈希值时,它使用默克尔树结构来避免不断重新计算存储库中每个文件的哈希值。
git
处理移动或重命名的文件呢?git
GUI 清楚地显示文件重命名,而不是文件删除+添加或编辑!虽然git
不存储有关文件重命名的信息,但它仍然能够启发式检测任意两个 git 提交之间的重命名文件,以及检测在未提交的存储库工作目录树和提交之间重命名/移动的文件HEAD
(又名“与未修改”)。
例如:
Foo.txt
和Bar.txt
.Foo.txt
为Qux.txt
(并且不进行其他更改)。git
“diff
快照 1”和“快照 2”,那么 git 可以看到它Foo.txt
被重命名为Qux.txt
(并且Bar.txt
没有改变),因为内容(以及文件的加密哈希值)是相同的,因此它推断文件重命名Foo.txt
为Qux.txt
发生。
git
执行相同的 diff,但使用“快照 2”作为基本提交,使用“快照 1”作为后续提交,那么 git 会显示它检测到从Qux.txt
back 到Foo.txt
.但是,如果您所做的不仅仅是重命名或在两次提交之间移动文件,例如同时编辑文件,那么 git可能会或可能不会将该文件视为新的单独文件,而不是重命名的文件。
git
比以文件为中心的源代码控制(如 TFS 和 SVN)更好地处理常见的文件系统级重构操作(如拆分文件),并且您赢了也没有看到与重构相关的错误重命名。MultipleClasses.cs
包含多个class
定义的文件拆分为单独的.cs
文件,每个class
文件一个。在这种情况下,没有执行真正的“重命名”,并且git
diff 会显示 1 个文件在添加新的 、 等文件
的MultipleClassesw.cs
同时被删除 ( ) 。SingleClass1.cs
SingleClass2.cs
MultipleClasses.cs
中SingleClass1.cs
,就像在SVN 或 TFS 中一样。但是,正如您可以想象的那样,有时git
启发式不起作用,您需要使用--follow
and/or --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
1% 不同,Foobar.cs
因此它认为重命名/移动而不是删除+添加或编辑,因此 Visual Studio 的解决方案资源管理器将使用该文件旁边的“移动/重命名”git 状态图标,而不是“文件已编辑”或“新文件”状态图标。Barfoo.cs
(尚未提交)超过默认更改百分比阈值 50%,则解决方案资源管理器将开始显示“新文件”图标,而不是“重命名/移动的文件”图标。
Barfoo.cs
(再次强调:尚未保存任何提交),使其滑落到 50% 更改阈值以下,则 VS 的解决方案资源管理器将再次显示“重命名”图标。git
在提交中不存储实际文件重命名/移动的一个巧妙之处在于,这意味着您可以安全地使用git
任何软件,包括任何重命名/移动文件的软件!尤其是不具备源代码控制意识的软件。
因此,Visual Studio(有或没有 git
内置支持)不需要通知git
文件已重命名/移动。
事实上,git 提交不是增量,而是快照,这意味着您可以更轻松地重新排序提交,并以最小的痛苦重新调整整个分支的基础。这在 SVN 或 TFS 中根本不可能实现。
归档时间: |
|
查看次数: |
6087 次 |
最近记录: |