git - Git相当于 Mercurial 添加+ Mercurial 差异?

标签 git mercurial diff

我最近习惯了水银后开始使用git。

通常,如果我对某些文件进行hg add编码,然后对hg diff进行编码,那么我会得到一个补丁,然后可以用理论上简单的patch -p1对其进行应用,并获得完全相同的本地副本。

现在,使用git,情况有所不同:在git diff之前先使用git add。但是,如何使git diff也覆盖所有未跟踪的文件,例如hg diff ing之后的hg add

最佳答案

TL; DR:添加所有内容,然后运行git diff --cached
Mercurial和Git在这里有不同的哲学。 Git显式公开了Git所谓的索引。 Mercurial没有索引(它在内部具有相似的东西,但是不公开它,因此您甚至不必知道它的存在)。许多喜欢Git的人认为暴露指数非常好,并且许多诅咒Git的人都认为可怕。 :-)尽管如此,这就是您遇到的问题,如果您使用的是Git,那么您正在使用索引,因此现在该学习它的含义和如何处理它了。

因此,让我们定义“索引”。 Git的索引(也称为暂存区,有时也称为缓存)是一个复杂的小野兽,具有许多Git通常不会暴露的隐藏方面。但是,它确实有一个简单的定义,您需要知道:在此构建下一次提交。

这里值得一提的是Git和Mercurial之间的另一个区别。 Mercurial存储更改(技术变更集),而Git存储快照。在大多数情况下,这并没有真正的区别。快照很容易转换为变更集:只需将快照与其父对象进行比较即可。给定父级快照,更改集可以轻松转换为新快照:只需应用更改集即可。但是,应用很长的变更集链很慢,因此Mercurial会定期存储快照。它在幕后完成所有这些操作,您无需了解它。像往常一样,Git公开了所有内容(这种方式有点像flasherstreaker,赤裸裸地跑着,暴露出没人真正想看到的悬空碎片)。

运行git commit时,Git会将索引中的内容转换为提交快照。因此,git add将文件放入索引。如果文件已经存在,则git add用工作树中获取的新版本替换现有副本。如果文件尚不存在,git add将工作树版本作为新文件放入索引中。无论哪种方式,索引版本现在都可以更新(暂存)并准备好进入下一个快照。

要从索引中取出文件,可以运行git rm。这将从索引和工作树中删除文件。或者,您可以运行git rm --cached,它仅将其移出索引,而将其保留在工作树中(但请注意,因为这可能会成为将来的陷阱)。

现在,由于索引/登台区域/缓存是这样暴露的,因此您可以对其进行git diff编码。为此,请使用git diff --cachedgit diff --staged(它们具有完全相同的含义;我通常坚持使用--cached,因为git rm具有--cached而不是--staged)。

问题在于,这仅差异索引中已更新的文件。更确切地说,它运行的等效项为git diff HEAD <index>,即,它将当前提交与索引的内容进行比较。这意味着您在工作树中已修改但尚未暂存的任何文件都不会进行比较。但是,解决方案很简单:只需git add这些文件。

撇开:.gitignore和未跟踪vs被忽略

一次添加一堆文件很麻烦,因此您可能想使用git add .git add -A(它们有些微不同;请参阅其他StackOverflow问题和答案,并请注意,围绕Git 2.0版进行了很大的更改,影响了-A选项这里)。但是,您的工作树通常包含您不想添加的文件,这是我们进入未跟踪文件与未跟踪并忽略的文件的时候。

现在我们知道索引是什么了,对于Git而言,对未跟踪的文件有一个非常简短的定义。未跟踪的文件是不在索引中的文件。就是这样,仅此而已。如果在索引中,则会对其进行跟踪。如果不是,则不是。

但是,当然有一个复杂的问题(Mercurial中也有):如果您有一堆未跟踪的文件,则版本控制系统会对它们产生很多抱怨。要关闭它,可以将文件名或全局模式添加到.gitignore。请注意,与Mercurial不同,您不能将正则表达式添加到.gitignore,而只能添加glob模式。这既好(全局模式更容易正确实现)也很差(全局模式不如完整的正则表达式强大),但是无论如何,它就是它。1
.gitignore中列出的文件不会自动与git add -Agit add .添加。但是,.gitignore中列出文件并不会使其无法跟踪。 使文件无法跟踪的唯一原因是它不在索引中。如果您不小心将文件放入了不应跟踪的索引中,则必须从索引中对其进行git rm编码。

撇开:强大的索引功能可以为您提供

从Mercurial迁移到Git的人们通常最初确实讨厌指数。使得它对许多人来说更可口的一件事是git add -p。某些人对此根本没有用,但是对于那些这样做的人,这实际上是相当不错的。

Git为您提供的“添加到索引中的内容,将在下一次提交中”和“工作树中的内容”之间的分隔意味着您可以 checkout 分支,出于调试目的而修改某些项目,其他项目(在相同或单独的文件中)以解决问题或添加功能,然后有选择地仅添加错误修复或新功能,而不添加调试更改。

当您用git commit结果时,您将获得仅具有错误修复或新功能而没有额外调试的提交。

通常,这既有优点也有缺点。例如,很难确保您刚刚提交的内容确实有效。也许只有额外的调试才能使它工作。也许您忘记了对它的某些部分进行git add。但是,由于Git鼓励
“修改”和重写commits2,使提交和分支确实便宜,在Git中工作的方式与在Mercurial中不同。 Mercurial分支较重,其提交和重新设置以及hg histedit明显较慢,这不鼓励这种快速而松散的commit-recommit-rebase-fixup-squash工作。 Git强烈鼓励这样做。您应该以不同的方式使用Git,在许多临时分支上进行大量临时提交。您不必这样做,但是尝试一下是个好主意。

1Mercurial在.hgignore中支持glob模式和正则表达式。不幸的是,在实践中,正则表达式(很难正确使用)比全局模式要快得多。我曾让同事将glob改为regexp以提高速度,但后来弄错了。如果要将glob模式转换为正则表达式,请记住将其 anchor 定,并注意.!

2在Mercurial和Git中,提交都是永久性的。但是,两者都提供了历史记录编辑和commit --amend。它们以不同的方式到达那里:Git通过复制旧提交来提交新提交,并移动分支名称以指向新提交。这将在存储库中创建“废弃”对象。 Git使用所谓的reflog保留它们一段时间,以便您可以在需要时对其进行恢复,然后最终使reflog条目到期,并“垃圾收集”剩余的垃圾以完全清除它。

Mercurial实际上无法做到这一点,因此,它“剥离”变更集,将其放入剥离备份导出的变更集文件中。然后,如果您想将它们重新导入,则可以将其重新导入。这比Git的“重写历史记录”方法的松散-松散的“提交,重新提交,移动分支指针,放弃旧对象”方法要慢得多。由于Git的方法在时间和空间上花费更少,因此您可以重写的临时提交通常非常接近于免费,尽管这确实取决于“松散对象”文件的大小,这样做更有意义。在Git中。

关于git - Git相当于 Mercurial 添加+ Mercurial 差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41825958/

相关文章:

Git Hook 静默失败

version-control - 在 Mercurial 中,有没有办法(除了 "Cherry picking")推送变更集而不推送与不同头部相关联的变更集?

git - Hg-Git 和 Mercurial 的当前版本 (2)?

git - merge 2个补丁文件

html - 彩色 Git 差异到 HTML

linux - 如何在新行上获取 diff 命令的输出

git - 将默认的 Git merge 放入 TFS

git - 如何配置 git 以忽略本地某些文件?

git - `.gitignore` 文件中前导斜杠的含义

version-control - 如何仅在创建新标签时强制执行 Mercurial 存储库的远程 gnupg 签名?