我是版本控制的新手,我知道"提交"实际上是在创建备份的同时更新您正在处理的新"当前"版本.
从实际角度来看,我不明白的是什么是分期.是暂存只存在于名称中还是有用的东西?当你提交时,无论如何它都会提交一切,对吧?
编辑:我想我可能会混淆术语."暂存"文件与"跟踪"文件相同吗?
Ben*_*son 72
当你提交它时,它只会提交索引中的更改("暂存"文件).这有很多用途,但最明显的是将你的工作变化分解成更小的,独立的部分.也许您在实现功能时修复了一个错误.你可以git add只是那个文件(或git add -p只添加一个文件的一部分!)然后在提交其他所有内容之前提交该bugfix.如果您正在使用git commit -a那么您只是add在提交之前强制执行所有操作.-a如果要利用暂存文件,请不要使用.
您还可以使用--cachedto to many命令将暂存文件视为中间工作副本.例如,git diff --cached将向您展示舞台的不同之处,HEAD以便您可以在不混淆其他工作变化的情况下查看您即将提交的内容.
小智 21
Dar*_*der 11
分段的一个实际目的是文件提交的逻辑分离.
由于staging允许您继续对文件/工作目录进行编辑,并在您认为已准备就绪时进行部分提交,因此您可以使用单独的阶段进行逻辑上不相关的编辑.
假设你有4个文件fileA.html,fileB.html,fileC.html和fileD.html.您更改所有的4个文件,并准备提交,但在改变fileA.html和fileB.html有逻辑关系(例如,在这两个文件相同的新功能实现)而变化fileC.html,并fileD.html有独立的和逻辑无关,以前的文件.您可以第一阶段的文件fileA.html和fileB.html并提交这些.
git add fileA.html
git add fileB.html
git commit -m "Implemented new feature XYZ"
Run Code Online (Sandbox Code Playgroud)
然后在下一步中,您将更改为剩余的两个文件.
git add fileC.html
git add fileD.html
git commit -m "Implemented another feature EFG"
Run Code Online (Sandbox Code Playgroud)
tor*_*rek 10
为了扩展本杰克逊的回答,这很好,让我们仔细看看原始问题。(请参阅他的回答,了解为什么要打扰类型的问题;这更多的是关于正在发生的事情。)
我是版本控制的新手,我知道“提交”本质上是在更新您正在处理的新“当前”版本的同时创建备份。
这不太对。备份和版本控制当然是相关的——确切地说,在某种程度上取决于某些事情的强烈程度,这些事情在某种程度上取决于意见——但肯定有一些差异,如果只是出于意图:备份通常是为灾难恢复而设计的(机器故障,火灾破坏整个建筑物,包括所有存储介质等)。版本控制通常是为更细粒度的交互而设计的,并提供备份所没有的功能。备份通常会存储一段时间,然后因为“太旧”而被丢弃:更新的备份才是最重要的。版本控制通常会永远保存每个提交的版本。
我不明白的是,从实践的角度来看,登台是为了什么。上演是名义上存在的东西还是有目的的?当您提交时,它无论如何都会提交所有内容,对吗?
是和否。Git 在这里的设计有点奇特。如前所述,存在的版本控制系统并不需要单独的分期一步。举例来说,水银,这是否则会很喜欢的Git在使用方面,并不需要单独的hg add一步,超越了最初的一个介绍一个全新的文件。使用 Mercurial,您可以使用hg选择某个提交的命令,然后执行您的工作,然后运行hg commit,然后就完成了。使用 Git,你使用git checkout, 1然后你做你的工作,然后你运行git add,然后git commit. 为什么要多出git add一步?
这里的秘密是 Git 对index或staging area 的不同称呼,或者有时(最近很少见)cache。这些都是同一个东西的名字。
编辑:我想我可能会混淆术语。“暂存”文件与“跟踪”文件是否相同?
不,但这些是相关的。一个跟踪文件是一个存在于Git的指数。要正确理解索引,最好从理解提交开始。
1由于Git版本2.23,您可以使用git switch来代替git checkout。对于这种特殊情况,这两个命令完全相同。新命令的存在是因为git checkout塞满了太多东西;它们被拆分为两个独立的命令git switch和git restore, 以便更轻松、更安全地使用 Git。
在 Git 中,提交会保存Git 知道的每个文件的完整快照。(Git 知道哪些文件?我们将在下一节中看到。)这些快照以一种特殊的、只读的、Git 专用的、压缩和重复数据删除的形式存储,通常只有 Git 本身可以读取. (每个提交中的内容不仅仅是这个快照,但这就是我们将在这里介绍的全部内容。)
重复数据删除有助于节省空间:我们通常只更改几个文件,然后进行新的提交。所以,大多数的文件提交大多相同,在以前的文件提交。通过简单地直接重用这些文件,Git 节省了大量空间:如果我们只触及一个文件,新的提交只占用一份新副本的空间。即便如此,它还是被压缩了——有时非常压缩,尽管这实际上发生在以后——因此.git,一旦将目录扩展为普通的日常文件,目录实际上可能比它包含的文件小。重复数据删除是安全的,因为提交的文件始终处于冻结状态。没有人可以更改一个,因此提交依赖于彼此的副本是安全的。
但是,由于存储的文件采用这种特殊的、永久冻结、仅限 Git 的格式,因此 Git 必须将每个文件扩展为普通的日常副本。这个普通的副本不是Git 的副本:它是你的副本,随你怎么做。当你告诉 Git 这样做时,Git 只会写到这些,这样你就有了可以使用的副本。这些可用副本位于您的工作树或工作树中。
这意味着当您检出某个特定提交时,每个文件都会自动生成两个副本:
Git 在当前提交中有一个永久冻结的 Git 化副本。您不能更改此副本(尽管您当然可以选择不同的提交,或进行新的提交)。
您的工作树中有一个普通格式的副本。您可以使用计算机上的任何命令执行您想要的任何操作。
其他版本控制系统(包括上面提到的 Mercurial)到此为止,只有这两个副本。您只需修改您的工作树副本,然后提交。Git ...没有。
在这两个副本之间,Git 存储每个文件的第三个副本2。第三个副本采用冻结格式,但与提交中的冻结副本不同,您可以更改它。要更改它,请使用git add.
该git add命令意味着使文件的索引副本与工作树副本匹配。也就是说,您是在告诉 Git:通过压缩我更新的工作树副本、对其进行去重并准备好将其冻结到新的提交中,来替换索引中的冻结格式、去重副本。 如果您不使用git add,索引仍保留当前提交的冻结格式副本。
当您运行git commit,Git的封装了无论是在指数权,然后以用作新快照。由于它已经处于冻结格式并已预先删除重复,因此 Git 不必做很多额外的工作。
这也解释了未跟踪文件的全部内容。未追踪文件是一个文件,它是你的工作树,但不是在Git的指数现在。文件在这种状态下如何结束并不重要。也许您将它从计算机上的其他位置复制到您的工作树中。也许你在这里创造了它。也许有是在Git的指数的副本,但你删除的副本git rm --cached。无论如何,您的工作树中有一个副本,但 Git 的索引中没有副本。如果您现在进行新提交,该文件将不会在新提交中。
请注意,git checkout最初从您检出的提交中填充Git 的索引。所以索引开始匹配提交。Git 还会从同一来源填充您的工作树。所以,最初,所有三个匹配。当您更改工作树中的文件和git add它们时,现在索引和您的工作树匹配。然后你运行git commit,Git 从索引中进行一个新的提交,现在这三个再次匹配。
因为 Git 会根据索引进行新的提交,所以我们可以这样说:Git 的索引保存您计划进行的下一次提交。 这忽略了 Git 索引在冲突合并期间所扮演的扩展角色,但无论如何我们现在都想忽略它。:-)
这就是它的全部内容——但它仍然相当复杂!这特别棘手,因为没有简单的方法可以准确查看 Git 索引中的内容。3 但是有是,告诉你这是怎么回事,在某种程度上这是非常有用的,并且该命令是一个Git命令git status。
2从技术上讲,这实际上根本不是副本。相反,它是对 Git 化文件、预先去重和所有内容的引用。这里还有更多内容,例如模式、文件名、暂存编号和一些缓存数据,以加快 Git 运行速度。但是,除非你进入一些Git的低级别的命令-的工作git ls-files --stage和git update-index特别,你可以把它看作一个副本。
3该git ls-files --stage命令将显示 Git 索引中每个文件的名称和暂存编号,但通常这并不是很有用。
git status该git status命令实际上是通过git diff为您运行两个单独的命令来工作的(并且还做一些其他有用的事情,例如告诉您您在哪个分支上)。
第一个git diff比较当前提交——记住,它一直处于冻结状态——与 Git 索引中的任何内容进行比较。对于相同的文件,Git 根本不会说什么。对于不同的文件,Git 会告诉你这个文件是为提交而暂存的。这包括全新的文件——如果提交中没有sub.py,但索引中确实有sub.py,那么这个文件会被添加——以及任何删除的文件,这些文件曾经(并且现在)在提交中但不在索引不再(git rm,也许)。
第二个git diff将 Git 索引中的所有文件与工作树中的文件进行比较。对于相同的文件,Git 什么也不说。对于不同的文件,Git 会告诉你这个文件没有暂存以进行提交。与第一个差异不同,这个特定列表不包括全新的文件:如果该文件untracked存在于您的工作树中,但不在 Git 的索引中,则 Git 只是将其添加到未跟踪文件列表中。4
最后,将这些未跟踪的文件累积在一个列表中,git status也会公布这些文件的名称,但有一个特殊的例外:如果文件名列在.gitignore文件中,则会抑制最后一个列表。 请注意,在 a 中列出跟踪的文件(位于 Git 索引中.gitignore的文件)在这里没有任何影响:该文件在索引中,因此会进行比较并提交,即使它在.gitignore. 忽略文件仅抑制“未跟踪文件”投诉。5
4使用短版时git status——git status -s未跟踪的文件没有分离出来,但原理是一样的。像这样累积文件git status有时还可以通过仅打印目录名称来汇总一堆未跟踪文件的名称。要获取完整列表,请使用git status -uall或git status -u。
5列出文件还可以使大量添加许多文件操作,例如git add .或git add *跳过未跟踪的文件。这部分变得有点复杂,因为您可以使用git add --force添加通常会被跳过的文件。还有一些其他通常较小的特殊情况,所有这些都加起来:文件.gitignore可能更合适地调用.git-do-not-complain-about-these-untracked-files-and-do-not-auto-add-them或同样笨拙的东西。但这太荒谬了,所以.gitignore就是这样。
git add -u,git commit -a等这里有几个方便的快捷方式:
git add .将添加当前目录和任何子目录中的所有更新文件。这尊重.gitignore,因此如果当前未跟踪的文件没有被 投诉git status,则不会自动添加。
git add -u将在您的工作树中的任何位置自动添加所有更新的文件。6 这仅影响跟踪的文件。请注意,如果您删除了工作树副本,这也将删除索引副本(这样做是为了使索引与工作树匹配)。git add
git add -A就像git add .从工作树的顶层运行一样(但请参阅脚注 6)。
除此之外,您还可以运行git commit -a,这大致相当于7运行git add -u然后git commit。也就是说,这会让您获得在 Mercurial 中方便的相同行为。
我通常建议不要使用这种git commit -a模式:我发现最好git status经常使用,仔细查看 output,如果状态不是您所期望的,请找出为什么会这样。使用git commit -a,很容易意外修改文件并提交您不打算提交的更改。但这主要是品味/意见问题。
6如果您的 Git 版本早于 Git 2.0,请注意:git add -u仅适用于当前目录和子目录,因此您必须先爬到工作树的顶层。该git add -A选项也有类似的问题。
7我说大致相当,因为git commit -a实际上是通过创建一个额外的索引并使用其他索引来进行提交来工作的。如果提交有效,您将获得与执行相同的效果git add -u && git commit。如果提交不起作用——如果你让 Git 以任何你可以做到的方式跳过提交——那么之后没有文件被git add-ed,因为 Git 抛出临时额外索引并返回使用主索引.
如果您git commit --only在此处使用,则会出现其他复杂情况。在这种情况下,Git 创建了第三个索引,事情变得非常棘手,特别是如果您使用预提交挂钩。这是使用单独git add操作的另一个原因。
这是比较容易理解的使用Git命令的add和commit如果你想像被保持在Github上你的资料库的日志文件。我的典型项目日志文件可能如下所示:
---------------- Day 1 --------------------
Message: Complete Task A
Index of files changed: File1, File2
Message: Complete Task B
Index of files changed: File2, File3
-------------------------------------------
---------------- Day 2 --------------------
Message: Correct typos
Index of files changed: File3, File1
-------------------------------------------
...
...
...and so on
Run Code Online (Sandbox Code Playgroud)
我通常以一个git pull请求开始我的一天,并以一个请求结束它git push。因此,一天记录中的所有内容都对应于它们之间发生的情况。在每一天,我都会完成一个或多个逻辑任务,这些任务需要更改一些文件。在该任务期间编辑的文件列在索引中。
这些子任务(这里的任务 A 和任务 B)中的每一个都是单独的提交。该git add命令将文件添加到“已更改文件索引”列表中。此过程也称为分期。该git commit命令记录/完成更改和相应的索引列表以及自定义消息。
请记住,您仍然只更改存储库的本地副本,而不是 Github 上的副本。在此之后,只有当您执行“git push”时,才会将所有这些记录的更改以及每次提交的索引文件都记录到主存储库(在 Github 上)。
例如,要获取该假想日志文件中的第二个条目,我会这样做:
git pull
# Make changes to these files
git add File3 File4
# Verify changes, run tests etc..
git commit -m 'Correct typos'
git push
Run Code Online (Sandbox Code Playgroud)
简而言之,git add它git commit允许您将主存储库的更改分解为系统的逻辑子更改。正如其他答案和评论所指出的那样,它们当然还有更多用途。然而,这是最常见的用法之一,也是 Git 作为多阶段修订控制系统背后的驱动原则,这与 Svn 等其他流行的系统不同。
小智 5
它就像一个复选框,可以选择要提交的文件。
例如,如果我编辑了fileA.txt和fileB.txt。但我只想提交更改fileA.txt。因为我还没有完成fileB.txt。
我可以简单地使用git add fileA.txt并提交使用git commit -m "changed fileA.txt"并继续工作fileB.txt,完成后我可以fileB.txt轻松提交