我最近在习惯了mercurial后开始使用git。
在mercurial中,如果我hg add
一些文件,然后是hg diff
,我会得到一个补丁,然后我可以在理论上使用简单的patch -p1
来获取并获得完全相同的本地副本
现在,使用git,情况有所不同:git diff
之前git add
。但是,如何git diff
覆盖所有未跟踪的文件,例如hg diff
之后的hg add
?
答案 0 :(得分:4)
git diff --cached
Mercurial和Git在这里有不同的哲学。 Git明确地公开了Git所谓的索引。 Mercurial没有索引(它在内部有类似的东西但不暴露它,所以你甚至不需要知道它存在)。许多喜欢Git的人认为暴露的指数很好,许多诅咒Git的人都认为这很糟糕。 :-)尽管如此,这是你在这里遇到的问题,如果你正在使用Git,你正在使用索引,所以现在是时候了解它是什么以及如何处理它。
所以,让我们定义"索引"。 Git的索引 - 它也被称为临时区域,有时候缓存 - 是一个复杂的小野兽,有很多Git 不会通常暴露的隐藏方面。但是,它确实有一个简单的定义,您需要知道:它是您构建下一次提交的地方。
除了Git和Mercurial之间的另一个区别之外,值得一点点。 Mercurial存储更改 - 更改集,是技术性的,而Git存储快照。大多数时候,这没有什么不同。快照很容易转换为变更集:只需将快照与其父级相区分即可。如果父级为快照,则变更集很容易转换为新快照:只需应用变更集即可。但是,应用一长串变更集的速度很慢,因此Mercurial会定期存储快照。它在幕后完成所有这些工作,你永远不必了解它。像往常一样,Git暴露了所有东西(它有点像flasher或streaker那样,赤身裸体,暴露出无人真正想要看到的脏块。)
运行git commit
时,Git会将索引中的所有内容转换为提交快照。所以git add
将文件放入索引中。如果文件已经存在,git add
将使用从工作树中获取的新版本替换现有副本。如果该文件尚未 ,则git add
将工作树版本作为新文件放入索引中。无论哪种方式,索引版本现在都已更新 - 暂存 - 并准备好进入下一个快照。
要获取索引的文件 out ,您可以运行git rm
。这将从 索引和工作树中删除文件。或者,您可以运行git rm --cached
,它仅从索引中获取它,将其保留在工作树中(但要注意,因为这可能是未来的陷阱)。
现在,因为索引/ staging-area / cache是这样公开的,所以你可以git diff
它。要做到这一点,请使用git diff --cached
或git diff --staged
(这些具有完全相同的含义;我通常坚持使用--cached
因为git rm
有--cached
但不是{{1} }})。
问题是此仅区分已在索引中更新的文件。更准确地说,它运行相当于--staged
,即它将当前提交与索引的内容进行比较。这意味着您在工作树中修改但不尚未上架的任何文件都不会出现差异。但解决方案很简单:只需要git diff HEAD <index>
这些文件。
git add
和未跟踪与忽略一次添加一堆文件很痛苦,因此您可能希望使用.gitignore
或git add .
(这些略有不同;请参阅其他StackOverflow问题和答案,并注意有围绕Git 2.0版的一个重大变化,影响了git add -A
选项。但是,您的工作树通常包含您 想要添加的文件,这是我们进入未跟踪和未跟踪和忽略的文件的时候。
既然我们知道索引是什么,那么未跟踪的文件的明确(对于Git)是一个非常简短的定义。未跟踪的文件是不在索引中的文件。这就是它的全部内容。如果它在索引中,则会对其进行跟踪。如果没有,那就没有了。
但当然有一个复杂的问题(Mercurial也有):如果你有一堆未跟踪的文件,你会从版本控制系统中得到很多关于它们的抱怨。要关闭它,可以将文件名或glob模式添加到-A
。请注意,与Mercurial不同,您不能将正则表达式添加到.gitignore
,只能添加glob模式。这两者都很好(glob模式远更容易正确)和坏(glob模式不如完整的正则表达式那么强大),但无论如何,它就是它。 1
.gitignore
中列出的文件不会自动添加.gitignore
或git add -A
。但是,列出git add .
中的文件并未使其无法跟踪。 仅使文件无法跟踪的事情是它不在索引中。如果您不小心将文件放入了不应跟踪的索引中,则必须从索引中.gitignore
。
人们从Mercurial转移到Git通常真的很讨厌索引。有一件事使得它更适合许多人git rm
。有些人完全没有用这个,但对于那些人来说,实际上是相当不错的。
Git给你的分离&#34;什么被添加到索引,并将在下一次提交&#34;和&#34;工作树中的内容&#34;意味着您可以签出分支,修改某些项目以进行调试,修改其他项目(在相同或单独的文件中)以修复问题或添加功能,然后选择性地添加只有错误修复或新功能,而不是调试更改。
当你git add -p
结果时,你会得到一个只有bug修复或新功能的提交,而不是额外的调试。
git commit
它的某些部分。但是,因为Git有点鼓励
&#34;修改&#34;并重写提交, 2 并使提交和分支真正便宜,你可以在Git中以不同于Mercurial的方式工作。 Mercurial分支较重,它的提交和rebase和git add
明显变慢,这阻碍了这种快速和松散的commit-recommit-rebase-fixup-squash工作。 Git强烈 en 勇敢的这一点。你应该以不同的方式使用Git,在很多临时分支上进行大量的临时提交。你没有 ,但尝试它是个好主意。
1 Mercurial支持hg histedit
中的glob模式和正则表达式。不幸的是,正则表达式 - 那些难以理解的表达式 - 在实践中比glob模式快得多。我有同事为了速度而改变整体,但后来却弄错了。如果要将glob模式转换为regexp,请记住锚定它们,并注意.hgignore
!
2 在Mercurial和Git中,提交都是永久性的。但是,两者都提供历史编辑和.
。它们以非常不同的方式到达:Git通过复制旧提交来进行新提交,并将分支名称移动到指向新提交。这造成了“被抛弃的”#34;存储库中的对象。 Git使用它所谓的 reflogs 来保持它们一段时间,以便你可以在需要时恢复它们,然后最终使reflog条目到期并且&#34;垃圾收集&#34;留下垃圾完全摆脱它。
Mercurial字面意思不能这样做,所以相反它&#34;剥离&#34;更改集,将它们放入条带备份导出的变更集文件中。然后,如果需要,可以重新导入它们。这比Git的松散 - goosey&#34;提交,重新发送,移动分支指针,放弃旧对象&#34;慢得多。 &#34;重写历史&#34;的方法。由于Git的方法成本较低,在时间和空间方面,你做重写的临时提交往往非常接近免费,尽管这取决于&#34;松散的对象&#34 ;文件大小 - 它在Git中为做更有价值。