我遇到过这样的情况,三个月前我从开发中创建了一个功能分支,从那时起,其他同事一直在开发其他已发布到开发中的功能分支。我现在想将我的更改集成到开发中,而不破坏他们的代码,也不破坏我的代码。
我研究了这个并在这里找到了答案更简单的方法来保持 git 功能分支最新。请按照以下步骤操作。
git checkout feature/foo
git pull --all
git rebase develop
Run Code Online (Sandbox Code Playgroud)
我得到了错误。致命:无效的上游“开发”
在进一步阅读该页面时,我尝试了以下内容
git checkout develop
git pull
git checkout feature/xxxx
git merge develop
git push
Run Code Online (Sandbox Code Playgroud)
我的问题是,在遵循前面指定的链接后,为什么会出现错误。致命:上游“开发”无效。当我想使用 rebase 选项时我会问这个问题。
这个答案分为两部分,因为一部分是所有背景知识,一部分是您提出的问题的答案。您可能应该首先阅读这部分,即使它只是背景。
\n我认为这里讨论的问答对(链接的问题加上其接受的答案)并不是很好。这里棘手的部分是,Git 比人们想象的更简单,也更复杂,人们的头脑中会产生错误的想法,这需要大量的工作来摆脱并用正确的模型替换。
\n人们心目中的错误模型是分支在某种程度上就是 Git 中的东西。但它们不是:它们不是事物,无论“事物”意味着什么。 问题是,“分支”\xe2\x80\x94无论我们松散地使用该词\xe2\x80\x94 时可能意味着什么,都是不明确的,而当我们指的是“Git 存储库中提交的某些子集”时,它们是只是一个后果。也就是说,这些分支就像你冲刺后必须用力呼吸的事实。你冲刺并不是为了让你呼吸困难:你冲刺是为了赢得一场比赛,或者为了锻炼身体,或者类似的事情。令人喘不过气的部分发生了,但这不是目标。
\n同样,分支(无论我们的意思是什么)在 Git 中发生是因为我们\xe2\x80\x94 和 Git\xe2\x80\x94真正关心的事情。在这种情况下,“事情”就是提交。 Git 的核心就是提交。提交是Git存在的理由。 因此,了解以下内容至关重要:
\nGit 存储库是提交的集合。 事实上,存储库的核心是两个数据库。两者都是简单的键值存储。一个保存Git的内部对象,包括commits(也就是我们人类在这里一般会关心的对象),另一个保存names\xe2\x80\x94分支名称、标签名称和其他名称。
\n提交是有编号的。 每个内部 Git 对象都有一个编号;特别是提交会获得一个全局唯一的编号,我们称之为哈希 ID,有时也称为 Git OID(对象 ID)。过去,Git 将这些称为SHA-1 哈希 ID (因为当前的 OID 实际上是 SHA-1 哈希),但由于 SHA-1 已被有效破坏,Git 正在转向 SHA-2 。
\n每个提交依次存储两个集合。 我们稍后再讨论这个问题。
\n事实上,每个提交都有一个完全唯一的编号,这意味着任何两个 Git 存储库在相互接触时,只需查看编号就可以判断它们是否包含相同的提交。与 Git 存储库配合使用的 Git 软件可以访问与另一个 Git 存储库配合使用的其他 Git 软件:origin例如,您可以将其称为另一个 Git。因此,您的 Git 会调用 Git atorigin并让它们列出(部分)其提交哈希 ID。如果您的 Git 具有相同的 ID,则您和他们具有相同的提交,并且你们处于同步状态。如果没有,则你们中的一个人有一些对方没有的提交,和/或反之亦然。Git 通常对提交非常贪婪,因此此时一个具有额外提交的 Git\xe2\x80\x94将向另一个 Git提供其他数据库所缺少的提交。接收的 Git 会将这些提交添加到其集合中,这会将它们添加到其集合中,这与Borg类似。(“我们会将你们的生物和技术独特性添加到我们自己的独特性中。”)
编号系统有一些后果。一是因为这些数字是加密摘要,所以它们看起来相当随机,对人类来说不友好。没有人能记住所有的哈希 ID。幸运的是,我们不必这样做:计算机可以做到这一点,而且计算机很擅长这样做。另一个原因是,由于提交的哈希 ID是提交内容的加密校验和,因此任何提交的任何部分都无法更改。
\n每个 Git 提交都有两部分:
\n每次提交都会存储每个文件的完整快照。提交内的文件以特殊的、只读的、压缩的和\xe2\x80\x94由于各种原因而重要的\xe2\x80\x94去重复格式存储。由于每个提交的所有部分都是只读的,因此任何提交与任何其他提交(甚至同一提交的其他部分)共享其任何文件内容都是安全的。因此,无论您如何处理提交\xe2\x80\x94,例如,添加一百万个相同的\xe2\x80\x94,您都不会因为重复的文件而使存储库膨胀,即使每次提交都将每个文件存储在逻辑意义。
\n提交的快照方面意味着可以轻松获取您曾经提交过的内容的每个版本:只需找到该提交的正确哈希 ID,即可获得所有文件,与当时的情况一模一样你犯了他们。因此,只要您能找到提交的哈希 ID,所有内容都会一直保存。
\n与快照分开,每个提交存储元数据:诸如谁进行了提交的信息\xe2\x80\x94名称和电子邮件地址\xe2\x80\x94以及他们何时或为何进行提交(他们的日志消息:这的意义取决于对人类来说,所以并不是每个提交消息都有一个很好的“为什么”)。
\n现在我们来了解一下 Git 中的秘密技巧。这些并不复杂 \xe2\x80\x94 无论如何还没有 \xe2\x80\x94 但它们是理解分支的第一个关键。 在任何提交的元数据中,Git 都会存储先前提交或父提交哈希 ID的列表。 该列表通常只有一个条目长,为每个提交提供一个父哈希 ID。这种提交是一种普通的提交,是您每天都会进行的提交,当我们按照您的提交顺序将它们并排放置时,最新的位于右侧:
\n... <-F <-G <-H\nRun Code Online (Sandbox Code Playgroud)\n我们得到了一个简单的向后看的链。这里H代表您刚刚所做的最新提交的真实哈希 ID。它有一个快照和元数据,在它的元数据中, commitH存储了早期提交的原始哈希 ID G。因为 Git 有一个简单的键值存储,可以在其中查找Ghash ID 并获取 commit ,所以 Git 实际上可以“同时”G处理 commitH 和commit 。G我们只需为 Git 提供 commit 的哈希 ID 即可H。
G不过,Commit是一个普通的提交:它有一个快照和元数据,并且在其元数据中, commitG存储了早期提交的原始哈希 ID F。因此,Git 可以查找实际提交本身,仅使用 的哈希 IDG来查找G元数据来查找F哈希 ID。所以现在 Git 有了G-and-F对。
换句话说,从 开始H,Git 能够后退一步到G,从那里开始,Git 能够再后退一步到F。CommitF当然也是一个普通的提交,只有一个父提交,因此 Git 现在可以后退一步。Git 可以永远重复这个过程,或者至少,直到它回到第一次提交。第一次提交不能向后指向,因此它不会:
A <-B ... <-G <-H\nRun Code Online (Sandbox Code Playgroud)\n如果我们让 Git 从 at 开始H并一次向后工作一跳,Git 最终会到达提交A并在那里停止。
这是存储库中的历史记录。 提交包含快照;每次提交都会存储每个文件(具有重复数据删除功能);通过向后移动,一次一次提交,Git 找到了这个简单线性链中的每一次提交。但有一个大问题:我们必须向 Git 提供 commit 的哈希 ID H。我们如何找到它?
这就是分支名称发挥作用的地方。在 Git 中,分支名称\xe2\x80\x94 或任何其他名称(就此而言)\xe2\x80\x94 仅包含一个哈希 ID。假设提交哈希 ID 1为我们提供了 \xe2\x80\x94 或 Git\xe2\x80\x94a上次提交的起始位置。从那里,Git 可以向后工作。由于提交向后指向其父级,这就是存储库中的历史记录,因此这就是 Git查找历史记录的方式。
\n请注意,如果我们有多个分支名称,则可以有多个“最后一次提交”。为了说明这一点,假设我们有一个以 commit 结尾的提交链H:
...--G--H <-- main\nRun Code Online (Sandbox Code Playgroud)\n我们现在创建另外两个分支名称,例如br1和br2,这两个名称目前也都指向:H
...--G--H <-- br1, br2, main\nRun Code Online (Sandbox Code Playgroud)\n此时所有提交都在所有三个分支上。但当我们进行新的提交时,Git 会“向前”移动一个(且只有一个)分支名称。如果我们开始并br1进行新的提交I,它将指向现有的提交H并将名称br1向前拖动:
I <-- br1\n /\n...--G--H <-- br2, main\nRun Code Online (Sandbox Code Playgroud)\n当我们进行第二次新提交时,我们得到:
\n I--J <-- br1\n /\n...--G--H <-- br2, main\nRun Code Online (Sandbox Code Playgroud)\n名称br1指向J;J向后指向I; I向后指向H; 等等。因此,从 开始br1,Git 将找到所有提交。br2从或开始main,Git 只会查找以 结束的提交H。我们有两个分支\xe2\x80\x94还是三个分支?这取决于我们所说的“分支”一词的含义,不是吗?
不管怎样,假设我们现在改用该名称br2并进行两次提交。现在我们将拥有:
I--J <-- br1\n /\n...--G--H <-- main\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n我们现在好像有三个分店。我们肯定有三个分支名称。哪个分支包含截至之前的提交H?Git 的答案是:全部。事实上,如果我们不介意直接查找的话,此时我们可以安全地删除该名称:mainH
I--J <-- br1\n /\n...--G--H\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n现在我们只有两个分行。但我们仍然有完全相同的提交。树枝不重要!只有提交才是重要的。
\n当然,这并不意味着分支名称没有用。我们\xe2\x80\x94和Git\xe2\x80\x94使用它们来查找最后的提交。如果我们想快速找到任何特定的“最后”提交\xe2\x80\x94,H例如,如果我们想算作“最后”提交,即使它也是中间提交\xe2\x80\ x94我们需要给它起一个名字。
1非分支名称有时可以包含非提交哈希 ID。这主要是为了使标签更有用的功能。分支名称必须始终包含提交哈希 ID。
\n我上面说过,提交是带有元数据的只读快照。这是事实:提交中的文件实际上无法更改,而且它们的格式其他(非 Git)程序甚至无法读取。您实际上无法对这些文件进行任何操作!但我们需要完成工作,那么我们该怎么做呢?
\nGit 的答案是:您不处理或使用已提交的文件。相反,Git将提交提取到工作区域中,您可以在其中实际完成工作。这意味着,从字面上看,您在 Git 中使用的文件并不在 Git 中。它们从 Git 中复制出来,然后您可以使用这些副本进行工作。
\n当您进行新的提交时,您仍然不直接使用这些文件。相反,Git 存储了这些文件的副本,2准备好进行新的提交。每个文件的这个额外副本占用了 Git 的三个名称:索引、暂存区或(现在很少)缓存。所有三个名称都指的是同一件事,我喜欢将其描述为您建议的下一次提交。
\n这解释了git checkout或git switch正在做什么。当我们使用这些命令中的任何一个并为其指定分支名称时,我们实际上是在选择我们想要提取的提交。例如,如果我们有:
I--J <-- br1\n /\n...--G--H <-- develop, main\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n我们运行:
\ngit switch main\nRun Code Online (Sandbox Code Playgroud)\n我们告诉 Git 我们要开始处理 commit 中的文件H。Git 现在应该:
H。为了记住我们正在使用哪个分支名称,我们将像这样更新我们的绘图:
\n I--J <-- br1\n /\n...--G--H <-- develop, main (HEAD)\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n特殊名称HEAD全部大写,仅附加到一个分支名称。这是我们“所在”分支的分支名称。所以如果我们在br1:
I--J <-- br1 (HEAD)\n /\n...--G--H <-- develop, main\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n现在main,Git 已将所有 commit- 文件替换J为所有 commit-H文件。
这里有一些特殊情况。有时 Git 不必切换文件。假设当我们运行切换到 commit时,我们处于on状态develop,这意味着“提交H” 。我们告诉 Git从,切换到. 这其实算不上什么转变,不是吗?在这种情况下,Git 不必更改任何文件,因此它不会打扰。git switch mainH H H
如果我们还没有develop . 假设我们正在main:
I--J <-- br1\n /\n...--G--H <-- main (HEAD)\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n然后我们开始更改一堆文件。然后我们意识到:嘿,等等,我打算在一个新分支上完成这项工作。 我们可以创建一个新分支并立即切换到它,只要新分支现在也意味着“提交H”,那么该切换是完全免费的,因为 Git 不需要交换任何文件。我们可以将部分完成的工作保留为部分完成,test2例如创建一个新的分支名称:
I--J <-- br1\n /\n...--G--H <-- main, test2 (HEAD)\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n如果我们最终做出一个新的提交 \xe2\x80\x94let\'s 称之为N\xe2\x80\x94,我们将得到:
I--J <-- br1\n /\n...--G--H <-- main\n \\__\n \\ `--N <-- test2 (HEAD)\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n新提交N将指向旧提交H作为其父级,因为我们N 从commit进行了提交H。
此索引或暂存区域\xe2\x80\x94组成建议的下一个提交的每个文件的额外副本\xe2\x80\x94解释了为什么必须运行git add. 当你运行时git add,Git 将:
如果存在一些现有副本,Git 可以丢弃刚刚制作的压缩版本,并使用副本。如果没有,当我们最终提交时,Git 将安排新的压缩版本进入存储库。3
\n虽然这有点复杂,但要记住的部分并不是那么糟糕:
\ngit add它们之前,Git 甚至不关心文件是否已更新。 您应该git status经常运行以查看哪些文件尚未git add编辑。git add步骤意味着使索引/暂存副本与工作树副本匹配。 也就是说,它会更新您建议的下一次提交。git commit,Git 会根据建议的下一次提交创建新提交的快照。 这就是为什么您必须git add:更新建议的下一次提交,以便git commit提交该内容。这也导致了对 \xe2\x80\x94 的正确理解,但git status我们稍后会回到这一点。
2 Git 索引或暂存区域中的“副本”已经进行了重复数据删除,并且始终保持这种状态,因此除非您更改了文件并运行git add,否则这些副本不会占用任何空间。从技术上讲,索引中的内容实际上只是文件的名称、模式、哈希 ID 和缓存数据,以及合并期间使用的槽号;我们根本不会讨论这个。
3从技术上讲,Git 会立即添加一个新的 blob 对象。如果我们最终没有提交它,Git最终会清理它,前提是我们最终不会做另一件事git add并且最终会git commit提交它。因此,如果您有一个非常大的文件\xe2\x80\x94,比如说几十 TB 或 PB\xe2\x80\x94,您可能不想要它,除非确实有必要。但对于小文件来说,这通常并不重要。git add
我不断回到快照的概念,因为提交就是快照(加上元数据)。但是,如果我们使用git show或 来查看提交git log -p,我们就不会看到快照。相反,我们看到了一个差异:
$ git show | head -25 | sed \'s/@/ /\'\ncommit f01e51a7cfd75131b7266131b1f7540ce0a8e5c1\nAuthor: Junio C Hamano <gitster pobox.com>\nDate: Mon Mar 21 14:18:51 2022 -0700\n\n The thirteenth batch\n \n Signed-off-by: Junio C Hamano <gitster pobox.com>\n\ndiff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt\nindex d67727baa1..f1449eb926 100644\n--- a/Documentation/RelNotes/2.36.0.txt\n+++ b/Documentation/RelNotes/2.36.0.txt\n @ -74,6 +74,10 @@ UI, Workflows & Features\n refs involved, takes long time renaming them. The command has been\n taught to show progress bar while making the user wait.\n \n+ * Bundle file format gets extended to allow a partial bundle,\n+ filtered by similar criteria you would give when making a\n+ partial/lazy clone.\n+\n \n Performance, Internal Implementation, Development Support etc.\n \n @ -132,6 +136,12 @@ Performance, Internal Implementation, Development Support etc.\n \nRun Code Online (Sandbox Code Playgroud)\n@其中带有 s 的东西是diff hunk,在此之前我们得到一个diff 标头:
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt\nindex d67727baa1..f1449eb926 100644\n--- a/Documentation/RelNotes/2.36.0.txt\n+++ b/Documentation/RelNotes/2.36.0.txt\nRun Code Online (Sandbox Code Playgroud)\nGit 所做的就是获取提交f01e51a7cfd75131b7266131b1f7540ce0a8e5c1,使用其元数据查找其父级,并从两次提交bc3838b310b32081d48393ba0dcf26e4735c6d19中提取文件。在“左侧”(如),Git 放置文件的早期版本;在“右侧”(如),Git 放置文件的最新版本。然后 Git 玩了一个找不同的游戏。Git 看到的第一个区别是 Junio 在第 77 行周围添加了四行。差异显示了添加的行,加上一些上下文,然后继续 Git 发现的下一个更改,即在第 135 行周围添加更多行(在旧版本)或 139(新版本)。Documentation/RelNotes/2.36.0.txta/b/
换句话说,Git使用提交中的元数据来查找(单个)父级。这给了我们两个快照,Git 可以比较它们。但事实上,Git 可以从任意两个快照中进行差异,而不仅仅是彼此相邻的快照:
\n...--E--F--G--H <-- somebranch (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n这里git show将比较G和H,因为它们是两个相邻的提交,但我们可以运行:
git diff <hash-of-E> HEAD\nRun Code Online (Sandbox Code Playgroud)\n让 Git 直接比较E和中的快照H,并将其显示为差异。这一切都有效,因为每次提交都保存一个完整的快照,并且 Git 可以轻松比较任何两个快照。事实上,由于内部重复数据删除,只要大多数文件是重复的,Git 就可以非常快速地比较两个快照:它只需要查看那些不重复的文件。总的来说,这对于 Git 来说相当容易。
这一切都将我们引向了git merge,这就是 Git 发挥其真正威力的地方。让我们再次回到这个设置:
I--J <-- br1 (HEAD)\n /\n...--G--H\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n这告诉我们,我们“在”分支br1\xe2\x80\x93 上,也就是说,我们执行了 agit checkout br1或 a git switch br1\xe2\x80\x94 并且我们正在使用 commit 中的文件J。还假设我们没有触及任何这些文件(以便索引和工作树副本都与提交J副本匹配)。我们现在运行:
git merge br2\nRun Code Online (Sandbox Code Playgroud)\n我们的目标是结合变化。也就是说,我们希望将我们或其他人在我们的br1分支上所做的任何工作,以及我们或其他任何人在br2分支上所做的任何工作,并将这些工作结合起来。
我们刚刚看到 Git 不存储更改。但我们也看到 Git 可以轻松比较任意两个提交。我们如何让 Git合并更改? 我们必须做一些比较。
\nJ我们可以将中的快照与 中的快照进行比较L,但这并不能真正得到我们想要的东西。这里的技巧是以稍微不同的方式使用元数据。提交J有父级I,提交I有父级H,父级又有父级G,依此类推。同时提交L有父级K,父级有父级H,然后又回到父级G,依此类推。 其中一些父母是共享的。 事实上,一旦我们回到H,从那里开始的每个父母都是共享的。这意味着H两个分支上的 commit 是最好的共享父级。Git 将这个“最佳”共享父级称为合并基础。4
通过使用这个最佳共同祖先或合并基础,Git 可以运行两个 git diffs:
git diff --find-renames <hash-of-H> <hash-of-J> # what we changed\ngit diff --find-renames <hash-of-H> <hash-of-L> # what they changed\nRun Code Online (Sandbox Code Playgroud)\n这两个差异适用于同一个快照\xe2\x80\x94(提交H\xe2\x80\x94中的快照) ,现在Git 可以合并这些差异。只要我们触及了他们没有触及的文件,并且他们触及了我们没有触及的文件,这很容易。当我们和他们接触相同的文件时,Git 的规则很简单:如果我们没有接触相同的行,并且我们的更改不会相互冲突,Git 就会接受这两个更改。如果我们确实触及了相同的行,Git 会要求我们对这些相同的行进行相同的更改,然后 Git 会执行其中一项更改。如果我们的更改无法合并,Git 将其称为合并冲突。
这就是合并冲突的含义。 Git 选择了一些合并基础提交,并将其快照与其他两个提交的快照进行了比较。Git 现在正在尝试合并更改。Git 遇到过一种情况,它的简单的、基于行的、面向文本的规则对于如何组合这些规则没有一个简单的答案,所以 Git 说“冲突”。
\n注意:Git 还可以检测全新的、完全删除的或重命名的文件。这会产生一种不同类型的合并冲突\xe2\x80\x94,有些人称之为树冲突;我将其称为高级冲突\xe2\x80\x94,它不涉及文件中的特定行,而是涉及与该文件有关的整个事情。例如,假设我们添加了一些函数,subroutines.py但它们完全删除了 subroutines.py。Git 不知道如何将“添加这些行”与“删除此文件”结合起来,因此它将称为修改/删除冲突。
在所有这些冲突情况下,Git 将解决冲突的工作转嫁给了人类,而人类大概理解文件的内容。人类不仅仅应用简单的文本替换规则。人类知道是否在合并的一侧更改red ball为,在另一侧更改为,是否应该导致,或者可能是或其他什么。blue ballred ballred cubeblue cubegreen pyramid
但是,如果不存在冲突\xe2\x80\x94,如果合并顺利进行\xe2\x80\x94,Git 将采用组合的更改(无论最终结果是什么),并将它们应用到基本快照。也就是说,给定:
\n I--J <-- br1 (HEAD)\n /\n...--G--H\n \\\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\nGit 将我们的H-vs-J更改与其H-vs-L更改结合起来,并将这两个更改应用到H. 这会保留我们的工作并添加他们的工作,或者保留他们的工作并添加我们的工作,无论您想如何查看它。然后 Git 根据这个结果进行一个新的提交,这个新的提交在一个方面是特殊的:
I--J\n / \\\n...--G--H M <-- br1 (HEAD)\n \\ /\n K--L <-- br2\nRun Code Online (Sandbox Code Playgroud)\n提交M是合并提交。它有一个快照,就像任何提交一样。它有元数据,就像任何提交一样。它的特别之处在于它有两个而不是一个父级。Commit指向现有的 commit ,就像新提交一样。但 commit也指向合并的commit 。MJM L
这个\xe2\x80\x94这两个父项\xe2\x80\x94使提交成为M合并提交。当然,在这种情况下,快照也是合并更改的结果,但这并不是M合并提交的原因。两个父级进行M合并提交。
请注意,与往常一样,Git 已更新当前分支名称以指向新提交。所以br1现在的意思是“提交M”,而不是“提交J”。没有提交已更改\xe2\x80\x94 没有提交可以更改\xe2\x80\x94,但分支名称已像往常一样移动。
不寻常的是,因为M指向 backL以及 to J,我们可能不再关心查找L具有分支名称的提交。现在可以安全删除该名称 br2了:
I--J\n / \\\n...--G--H M <-- br1 (HEAD)\n \\ /\n K--L\nRun Code Online (Sandbox Code Playgroud)\n因为我们仍然可以通过从 开始并向后工作来找到所有提交。M现在更棘手了,因为当我们从 后退一次时,M我们必须访问提交J 和 L。然后我们必须访问和, 然后我们访问一次,然后返回到,依此类推。 Git 知道如何做到这一点,但它很棘手,这是 Git 中最难理解的事情之一。 特殊的是,两个分支从最初的 \xe2\x80\x94 分叉的 split \xe2\x80\x94 实际上更容易,而两个分支汇聚在一起的 处的合并则很困难。这是因为 Git 是向后工作的,当我们向后工作时,可以说是合并进行了拆分,拆分又进行了合并。但请记住,提交保存快照和元数据,你会没事的:合并保存快照。准备快照可能很困难,并且弄清楚为什么是该快照,尽管父提交中有什么内容并且可能很困难,但它仍然只是一个快照。I KHGHMJL
但请注意,用于普通提交的“将提交显示为补丁”技巧git log -p在这里不起作用。当我们有:
...--G--H <-- branch (HEAD)\nRun Code Online (Sandbox Code Playgroud)\nGit 会比较G和H快照以显示差异,但是当我们有:
...--J\n \\\n M <-- branch (HEAD)\n /\n...--L\nRun Code Online (Sandbox Code Playgroud)\nGit 应该将哪个快照与 中的快照进行比较M? 默认情况下使用的答案是这太难了,所以我根本不会费心显示任何内容。git log 这不是一个很好的答案,但请注意这一点。(对于这个困境没有单一的正确git log -p答案,但如果插入一些东西来表明它不费心在这里做任何工作,那可能会很好。)
4从技术上讲,两个提交的合并基础是使用提交形成的DAG 上的最低公共祖先算法找到的。有时有多个 LCA,这会使合并变得复杂,但我们在这里完全忽略这种情况。
\n| 归档时间: |
|
| 查看次数: |
3681 次 |
| 最近记录: |