如何停止其他分支中的某些文件以在master分支中合并?我有一个在特定分支中添加的文件。我想将此分支合并到master,但我希望master分支忽略与它合并的新文件。
如何通知Git该文件仅与此分支相关?
Git中没有这样的东西。
分支不是永久的,在许多方面都不重要。恐怕这个答案会很长,因为在这里您需要了解很多背景,并且许多Git简介都不善于传达它。
提交很重要:提交是永久的且不可更改。1 每个提交都保存一些文件的快照;该组文件在那次提交,它们的内容一起,是因为持久不变的承诺本身。
任何一次提交的“真实名称”是其较大的丑陋哈希ID。Git为您添加到存储库中的每个新的唯一提交组成一个新的,唯一的,丑陋的哈希ID。添加后,该提交将是永久的且不可更改(尽管再次参见脚注1)。提交将以您当时所说的形式完全保存您说时Git 跟踪的所有文件git commit
(我们稍后会再讨论)。
1提交可以在各种条件下删除,这些条件基本上可以归结为没有人可以找到它们。这比看起来要棘手,最好只是从一开始就将它们视为Git永久保存的东西,该东西可以保存文件快照。尽管一旦您找不到它,提交就可以消失,但是它实际上不能更改,因为它的真实名称(其哈希ID)是提交本身的加密校验和。
提交还记住其父提交。也就是说,每个提交都存储了您之前使用提取的提交的丑陋的哈希ID git checkout
。它还存储您的姓名(作为提交的作者和提交者)以及您的电子邮件地址和日期/时间戳记;并存储您的日志消息,告诉所有人您为什么认为进行该特定提交是件好事。
假设我们从只有三个提交的存储库开始。让我们给它们一个大写的字母,而不是笨拙的哈希ID。第一个提交是A
,第二个提交是,B
依此类推。一旦我们有26次提交,我们将不再能够进行新的提交,但这对我们来说已经足够了。
由于commit A
是第一个提交,因此没有父级。如果我们做B
的A
,不过,B
记得A
为B
的父,如果我们做C
的B
,C
记得B
。由于提交一旦完成就无法更改,A
无法记住B
,B
也无法记住C
:此“我记得”的东西,此箭头从较晚的提交指向较早的提交,必须向后移动:
A <-B <-C
Run Code Online (Sandbox Code Playgroud)
如果我们C
使用A
而不是使用该B
怎么办?然后C
将指向,而不是B
,而是A
:
A--B
\
C
Run Code Online (Sandbox Code Playgroud)
但目前,让我们坚持直线的提交:
A--B--C
Run Code Online (Sandbox Code Playgroud)
(在这里我们懒得去画箭头,但实际上这部分是因为我们在使用倾斜的箭头时会遇到问题)。现在,记住这些方便的大写字母代表实际的大丑陋哈希ID,请问自己:我们(或Git)如何记住commit 的实际哈希ID C
? C
记住的ID B
,也记住的ID A
,因此我们不需要记住这两个。但是我们确实需要记住链中的最后一次提交。
这是分支名称输入图片的地方。 像这样的分支名称master
只是用来保存一个提交哈希ID:链的末尾或提示提交。从那里,Git将计算出所有较早的提交。因此,我们来画一下:
A--B--C <-- master
Run Code Online (Sandbox Code Playgroud)
现在,让我们进行一次新提交。我们称它为,D
但实际上它有一些独特的丑陋的哈希ID。我们使运行一下:
git checkout master
... edit some files ...
git add ... some files ...
git commit
Run Code Online (Sandbox Code Playgroud)
当我们进行时D
,我们已经提交了C
检出。因此,C
将成为new commit的父对象D
。Git会收集您的日志消息,并为所有文件制作快照,而不仅仅是git add
-ed 文件;我们将使用您的姓名以及作者和提交者数据的当前时间来稍作讨论,并进行新的,永久的,不可更改的提交D
,C
并将其记住为父项:
A--B--C--D
Run Code Online (Sandbox Code Playgroud)
但是现在这个名字master
必须改变。它在记忆C
; 现在它必须记住D
。因此,最后一步git commit
是将D
的实际哈希ID写入名称master
,从而得到以下结果:
A--B--C--D <-- master
Run Code Online (Sandbox Code Playgroud)
假设我们现在git checkout
回过头来进行commit B
,并使其(或更容易地已经拥有)一个指向commit的分支名称B
,以便我们可以像这样绘制图形:
C--D <-- master
/
A--B <-- branch
Run Code Online (Sandbox Code Playgroud)
现在我们再次提交E
。Git将照常写出新的提交,制作快照并将E
的父级设置为— B
因为这是我们已签出的。完成后,branch
将指向新提交E
:
C--D <-- master
/
A--B
\
E <-- branch
Run Code Online (Sandbox Code Playgroud)
Git如何知道移动名称branch
而不是移动名称master
?这是HEAD
进来的。当您运行时:
git checkout branch
Run Code Online (Sandbox Code Playgroud)
Git将您/它的HEAD附加到该分支名称,因此我们应该将其真正记录为:
C--D <-- master
/
A--B
\
E <-- branch (HEAD)
Run Code Online (Sandbox Code Playgroud)
您可能现在想知道哪个分支提交A
并B
处于启用状态。我们可以从图中看到,C
与D
上master
-and了Git知道这一点,因为混帐从开始结束的master
,提交D
,并在后台工作来达到C
。我们可以看到这E
是的技巧branch
。但是哪个分支B
在?
Git的答案是这两个提交都在两个分支上。包含或达到任何给定提交 的分支集是通过从所有分支名称(在右边经过,或图形的任一端是“最新”端)开始并向后工作来确定的。如果我们可以像这样向后移动来到达提交,则该提交在该分支上。
一般来说,分支机构倾向于增加新的提交。正如我们在上面看到的,添加的提交对branch
无效master
。我们可以做出更多新的提交:
C--D <-- master
/
A--B
\
E--F--G--H <-- branch (HEAD)
Run Code Online (Sandbox Code Playgroud)
并且master
仍然指向D
。但是,如果我们git checkout master
(附HEAD
到master
),然后使用git merge
到合并提交H
到 master
,我们得到这样的:
C--D---------I <-- master (HEAD)
/ /
A--B /
\ /
E--F--G--H <-- branch
Run Code Online (Sandbox Code Playgroud)
现在分支master
从和I
同时返回,因此所有提交都再次打开。D
H
master
我在这里走得很快,所以到现在为止,您可能需要花一些时间来研究网站Think Like(a)Git,该网站提供了有关此图形工作原理的更多信息。
Git内部的已保存文件(快照)存储在提交中。提交是该提交附带的所有文件的快照。没有该文件的任何提交都不会永久地拥有该文件。任何确实包含该文件的提交,都将永久拥有该文件。但是包含该提交的分支集取决于您对分支名称的处理方式。
您可以具有特定于提交的文件,但是这些提交可能突然在许多分支上,尤其是在有人使用之后git merge
。
使用Git一段时间后,您将了解提交如何存储文件的冻结版本,并使用git checkout <some old commit>
可以将其恢复。上面我们还提到过,Git保存每个文件的快照,或者更精确地说,保存所有跟踪的文件的快照。
由于每次提交(快照)都会保存每个文件,因此Git需要一种使它们不占用太多空间的方法。Git通过压缩文件来部分实现此目的。无需太多技术细节,Git可以压缩一些文件中的内容。这些超压缩文件采用特殊的,仅Git的格式,与提交本身一样永久且不可更改。但这意味着没有其他程序可以处理这些文件。您需要以git checkout
一种可以查看,编辑和与其他程序一起使用的格式来删除文件。
因此,Git为您提供了一个称为工作树或工作树的区域。这里的文件采用普通格式,而不是某些特殊的仅Git格式。这也很简单。
其他版本控制系统在这里停止:它们具有冻结的提交文件和工作树文件。当您运行hg commit
或执行svn commit
任何操作时,他们会花费数小时来分析您的工作树中的内容,以弄清楚如何提交。好吧,这实际上不是几个小时,只是感觉就像几个小时。无论如何,它很慢。但是,当您跑步时git commit
,它就像闪电一样迅速。Git从Git调用(这里称为index,暂存区域或缓存)获得了巨大的速度,具体取决于Git文档或命令的调用位。
这里的窍门是,当您git checkout
提交时,Git不仅会将所有冻结的文件扩展为工作树中的普通解压缩形式。Git首先将冻结的,Git格式的文件复制到该索引中,使它们保持特殊的仅Git格式,但不冻结它们。只有这样,才将它们解压缩到工作树中。因此,该索引跟踪(又是这个词)工作树中的文件集。
在运行时,Git所做的是将工作树副本压缩为特殊的仅Git格式,然后将其写入index中。如果索引中还有文件的其他版本,那么现在它已从工作树更新为新版本。如果文件以前不在索引中,那么现在是。无论哪种方式,文件现在都可以使用了。git add file
file
因此,当您运行时git commit
,Git要做的只是冻结index中已经存在的预压缩文件。Git这么快就是这样:它只是重新使用所有那些已经压缩的文件。如果尚未运行git add
,则会得到与先前签出的提交中的文件相同的版本。
请注意,当Git执行此操作时,也都为下一次提交进行了设置。例如,假设您处于这种状态:
...--F--G <-- somebranch (HEAD)
Run Code Online (Sandbox Code Playgroud)
因为你跑了git checkout somebranch
。索引和工作树现在充满了commit的所有文件G
。您修改一些工作树文件,运行git add
以将修改后的文件复制回索引,然后运行git commit
。Git H
从索引进行新提交,更改名称somebranch
以指向new commit H
,您将拥有:
...--F--G--H <-- somebranch (HEAD)
Run Code Online (Sandbox Code Playgroud)
与提交H
匹配索引!
这也解释了为什么,如果你忘了到git add
一个文件,并提交,提交获取旧版本的文件。提交将获取index中的任何内容,该索引是上一次提交的旧版本。
这也是Git定义跟踪文件还是未跟踪文件的方式:当且仅当文件当前在索引中时,才会跟踪工作树中的文件。使用git add
会将其复制到索引中,然后对其进行跟踪,因为它在索引中并且将在您进行的下一次提交中。使用git rm
将从索引和工作树中删除一个文件:现在它已经消失了,因此既没有被跟踪也没有被跟踪。使用git rm --cached
会将其从索引中删除,但将其保留在工作树中:现在它已被取消跟踪,因为它在工作树中,但不在索引中。
那么,对索引的一个很好的简短描述是:索引是将进入下一个提交的文件集。 使用git commit
只会冻结准备就绪的索引。使用git add
,您可以将文件更新或插入索引中,以使其随时可用。您在工作树中进行工作,但是从索引中提交。
git status
和.gitignore
该git status
命令首先打印出一些有趣的事实,例如“在分支上master
”,它通过名称HEAD
的附加位置知道您在哪个分支上。然后,它告诉您有关暂存的文件和/或未暂存的文件。
这实际上是在告诉您索引中的内容。您的索引开始与您的提交匹配-例如,由于您是从上一次提交而来的,或者是因为git checkout
。但是,如果您运行git add
,则会将新文件或现有文件的新版本写入索引。Git可以非常快速地比较HEAD
提交(从分支名称记住的哈希ID)到索引的提交,以告诉您索引中的文件是否与它们的HEAD
版本不同。这些是准备提交的文件。
让我们再来看一遍,因为它很重要:
HEAD
,则Git不执行任何操作。HEAD
文件不同,则Git表示已准备好提交。这样,如果您有一个包含数千个文件的大型项目,那么Git可以引起您的注意,如果您立即进行提交,那将变得与众不同。
后半部分是关于您仍然可以进行的操作git add
。如果您已经更改(或创建或删除了)工作树中的某些文件,但尚未使索引匹配,则可以运行git add
以更新索引以匹配工作树。因此,第二个比较是index-vs-work-tree,并且:
但是,这里发生的一种情况在第一次比较中不会发生,那就是当有一个工作树文件根本不在索引中时。这样的文件未跟踪,Git会抱怨。
好吧,也就是说,除非您告诉Git ,否则 Git会抱怨的:不要抱怨这个特定的未跟踪文件。 这就是很多事情.gitignore
:关闭Git。列出其中的文件.gitignore
不会使Git 在索引中没有该文件,因为如果您在该提交中检出提交,则该文件将进入索引。
清单文件.gitignore
会告诉Git的,一个大规模的“添加”,如git add .
或git add *
不应该添加该文件,如果它不是已经在索引中。但是一旦由于某种原因将其放入索引后,便会跟踪该文件,并且.gitignore
条目不再适用。它们仅适用于未跟踪的文件(非索引文件)。
你无法得到想要的东西。 最好至少在通用软件的存储库中避免提交主机或站点特定的文件(例如配置)。相反,提交示例或一组默认配置,然后让VCS 忽略实际配置(如果它位于同一目录中)。如果要对配置进行版本控制,请将实际配置保存在单独的存储库中。
归档时间: |
|
查看次数: |
518 次 |
最近记录: |