Git相当于hg add + hg diff?

时间:2017-01-24 10:37:18

标签: git mercurial diff

我最近在习惯了mercurial后开始使用git。

在mercurial中,如果我hg add一些文件,然后是hg diff,我会得到一个补丁,然后我可以在理论上使用简单的patch -p1来获取并获得完全相同的本地副本

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

1 个答案:

答案 0 :(得分:4)

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将工作树版本作为新文件放入索引中。无论哪种方式,索引版本现在都已更新 - 暂存 - 并准备好进入下一个快照。

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

现在,因为索引/ staging-area / cache是​​这样公开的,所以你可以git diff它。要做到这一点,请使用git diff --cachedgit diff --staged(这些具有完全相同的含义;我通常坚持使用--cached因为git rm--cached但不是{{1} }})。

问题是此区分已在索引中更新的文件。更准确地说,它运行相当于--staged,即它将当前提交与索引的内容进行比较。这意味着您在工作树中修改但尚未上架的任何文件都不会出现差异。但解决方案很简单:只需要​​git diff HEAD <index>这些文件。

除此之外:git add和未跟踪与忽略

一次添加一堆文件很痛苦,因此您可能希望使用.gitignoregit add .(这些略有不同;请参阅其他StackOverflow问题和答案,并注意有围绕Git 2.0版的一个重大变化,影响了git add -A选项。但是,您的工作树通常包含您 想要添加的文件,这是我们进入未跟踪和未跟踪和忽略的文件的时候。

既然我们知道索引是什么,那么未跟踪的文件的明确(对于Git)是一个非常简短的定义。未跟踪的文件是不在索引中的文件。这就是它的全部内容。如果它在索引中,则会对其进行跟踪。如果没有,那就没有了。

但当然有一个复杂的问题(Mercurial也有):如果你有一堆未跟踪的文件,你会从版本控制系统中得到很多关于它们的抱怨。要关闭它,可以将文件名或glob模式添加到-A。请注意,与Mercurial不同,您不能将正则表达式添加到.gitignore,只能添加glob模式。这两者都很好(glob模式更容易正确)和坏(glob模式不如完整的正则表达式那么强大),但无论如何,它就是它。 1

.gitignore中列出的文件不会自动添加.gitignoregit 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中为更有价值。