Jac*_*ost 1 git rebase git-rebase
我对 git 有点陌生,试图了解分支/rebase 是如何工作的,以及是否有可能我搞砸了一些事情。
我和我的同事都在不同的分支机构,我需要他为我的工作所做的改变。所以我拉了他的改变。然后我做了
git rebase -i HEAD~3
Run Code Online (Sandbox Code Playgroud)
并删除了我不需要的他的提交。然后我向我们的存储库推送并创建了一个拉取请求,一切看起来都很好。看起来就像是我需要他的更改和我自己的更改的一项提交。
我还没合并呢 是否有可能一旦他合并,然后我合并,不知何故,因为我删除了他在我正在合并的分支上的提交,它删除了他的代码?
使用 Git,很多事情都可以实现。要了解Git实际发生的情况,您必须了解分支是什么以及它为您做什么。这实际上很少,要理解这一点,您必须了解 Git提交是什么以及它为您做什么。
\n在这种特殊情况下,我认为您和您的同事会安全,但这实际上取决于你们俩如何使用各种 Git 存储库。请注意,您和他有单独的 Git 存储库。您可能还使用存储在其他地方(例如 GitHub)的第三个存储库。您不共享分支,也不共享有关各个存储库本身的任何其他内容,这主要是一件好事。这意味着您真正共享的唯一内容就是提交。
\n我在这里要提到的是,分支名称主要是一种存储一次(单个)提交的 ID 的方法。分支名称也有很多辅助用途,但存储提交哈希 ID 是 Git\ 各种名称\xe2\x80\x94 分支名称、标记名称和其他名称的本质。这里有一个主题:一切都与提交有关。Git 与分支无关,尽管分支名称可以帮助您找到提交;尽管提交包含文件,但 Git 与文件无关。最后,一切都与提交有关。
\n提交是一种存储一堆文件的快照\xe2\x80\x94的方法,我们称之为数据,或者通常是一棵树\xe2\x80\x94以及有关提交的其他信息,我们称之为元数据。因此,提交是存储这两项的东西:源快照或树,以及有关提交的信息,例如谁进行的、何时以及为什么(他们的日志消息)。但我们需要更仔细地观察这个问题,看看每个提交里面有什么,以及我们如何找到一个提交。
\n每个提交都有一个唯一的编号。这个数字不是一个很好的简单顺序计数:我们没有提交 #1,然后是 #2、#3 等等。相反,该数字是一个大而难看的哈希 ID,以十六进制表示。它看起来是随机的,但事实并非如此。
\n任何一次提交的哈希 ID 实际上是该提交的全部内容(数据和元数据)的加密校验和。因为每个 Git 都以相同的方式计算这个 ID,所以两个 Git 只需比较哈希 ID 就可以判断一个是否拥有另一个的提交。Git通过在元数据中为每次提交添加日期和时间戳等方式保证1该哈希 ID 是唯一的,这样即使您使用相同的用户名和电子邮件地址保存相同的文件等等,你将得到一个新的不同的提交,除非你两次同时保存文件\ xe2\x80\x94,如果你这样做了,你怎么知道你已经做了两次?
\nGit 通过哈希 ID 查找提交\xe2\x80\x94 和其他也使用此哈希方案\xe2\x80\x94 的内部 Git 对象。实际上,Git 的大部分内容都是一个简单的键值数据库,其中键是哈希 ID,内容是对象。2 这提供了数据完整性检查:给定一个密钥,Git 查找数据,然后确保存储的数据仍然与该密钥校验和。
\n这样做的一个重要后果是,每次提交一旦完成,都是 100% 只读的。如果您从数据库中取出任何对象,对它进行大惊小怪,哪怕只更改一点点,然后将其写回,您将得到一个带有新密钥的新的不同对象。3 因此,当您通过提交执行此操作时,只需添加一个新提交即可。旧的提交保留在数据库中。4
\n提交内的文件同样是只读的,并且会永久存储(但请参见脚注 4)。它们采用压缩的、仅限 Git 的格式,为了解决将每个文件存储在每个快照中会使数据库增长得非常快的问题,它们都会自动进行重复数据删除(参见脚注 3)。因此,如果一千次提交重用同一版本的README.md,那么数据库中实际上只有一份副本。
关于提交的最后一件事\xe2\x80\x94你只需要记住这些部分,实际上\xe2\x80\x94是每个提交在其元数据中存储一些先前提交的哈希ID。大多数提交只存储一个先前的提交哈希 ID。这是提交的父级。
\n概括:
\n1鸽巢原理告诉我们,这最终必定会失败。哈希 ID 又大又难看,以确保它不会在任何合理的时间内 意外失败。有可能故意让它失败,因此 Git 正在从 SHA-1 迁移到 SHA-256,但与此同时,这在实践中不是问题。
\n2提交是四种内部对象类型之一。为了完整起见,其他三个是blob、tag(或带注释的标签)和tree。
\n3如果数据与数据库中已有的某些数据匹配,Git 只会说啊哈,重复,根本不费心存储它。例如,这就是 Git 删除重复存储文件的方式。提交通过时间戳和其他与之前的提交不匹配的元数据来获得其唯一性。
\n4这意味着数据库只会增长。有一种方法可以丢弃未使用的东西,但我们不会在这里详细介绍。
\n“提交存储其父哈希 ID”的一个主要结果是提交形成了一个向后查找的链。也就是说,假设我们有一系列提交,并且我们使用单个大写字母来代表哈希 ID。我们可以这样画:
\n... <-F <-G <-H\nRun Code Online (Sandbox Code Playgroud)\n其中是某个提交链中最后一次H提交的哈希 ID 。Commit存储快照和元数据,元数据中存储之前 commit 的哈希 ID 。我们说 that指向,或者说是\ 的父级。 也有快照和元数据,我们将在其中找到早期提交的哈希 ID 。 依次指向另一个较早的提交,依此类推。这一切都会持续下去,直到我们到达“第一次”提交,该提交没有父级。所以我们需要的只是\ 的实际哈希 ID。从那里,我们可以找到每个早期的提交。HHGH GGHGGFFH
但有一个问题:我们在哪里可以找到 commit 的哈希 ID H?我已经透露了:它位于分支名称中。这就是分支名称的含义和作用:它保存某个提交链中最后一次提交的哈希 ID。所以我们可以这样绘制提交:
..--G--H <-- branch\nRun Code Online (Sandbox Code Playgroud)\nGit 分支名称的有趣之处在于它们会移动。例如,让我们创建一个新的分支名称,并让它也feature指向:H
..--G--H <-- branch, feature\nRun Code Online (Sandbox Code Playgroud)\n现在我们需要知道要使用哪个分支名称,因此让我们将特殊名称附加HEAD到一个分支名称上:
..--G--H <-- branch (HEAD), feature\nRun Code Online (Sandbox Code Playgroud)\n这告诉我们,我们将通过name使用commit 。如果我们运行:H branch
git checkout feature\nRun Code Online (Sandbox Code Playgroud)\n我们将继续使用 commit H,但通过name feature:
..--G--H <-- branch, feature (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n假设我们现在进行新的提交。不讲太多细节,我们只说 Git 为新提交分配一个新的哈希 ID,我们将其称为I。Git 会将I\ 的父级设置为H,因此我们可以这样绘制:
..--G--H\n \\\n I\nRun Code Online (Sandbox Code Playgroud)\n现在我们看到 Git 的特殊技巧:当 Git 进行新的提交时,Git将其哈希 ID 写入所附加的名称中HEAD:
..--G--H <-- branch\n \\\n I <-- feature (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n这就是 xe2x80x94a 分支增长的一种方式:每次我们进行新的提交时,Git 都会更新名称以指向我们刚刚进行的新提交。新的提交指向刚才名称所指向的地方。
\ngit commit我们在上面已经看到了如何进行新提交的简要视图。该git merge命令还可以进行新的提交,其他各种命令也可以。一旦您进行了这些新的提交,您可能希望与其他 Git 用户(例如您的同事)共享它们。为此,您必须让您的 Git 调用其他 Git。您将使用 URL 来完成此操作:某些服务将应答该 URL 并调用另一个 Git。
为了避免每次都输入长 URL,Git 会将 URL 存储在短名称(如origin. 我们将这个短名称称为“ remote”。您可以使用以下任一方式调用遥控器git fetch,这意味着让我从他们那里获取提交,或者git push,这意味着让我向他们发送提交。这些操作非常相似,当然方向相反,但最终它们也变得非常不同。两者都首先让你的 Git 调用他们的 Git,之后他们的 Git 可能会列出他们的分支名称以及与这些名称相关的哈希 ID。5 现在您的 Git 知道其 Git 有\xe2\x80\x94 分支名称和哈希 ID\xe2\x80\x94,实际传输开始:
对于git fetch,此列表构成了一个产品:您可以拥有这些提交。如果您还没有这些特定的提交并且想要该分支,您的 Git 将开始通过其哈希 ID 向其 Git 询问特定的提交。如果您的 Git 要求进行某些提交,那么他们的 Git 现在也必须提供该提交的父级或父级,并且您的 Git 要么说请发送该提交,要么说不,谢谢,我已经有了那个提交。
使用git push,您的 Git 通过哈希 ID 提供您分支之一的最后一次提交(假设您使用了)。他们的 Git 要么说“请发送”,要么说“不,谢谢”,就像上面一样。这反过来又会导致您的 Git 在需要时向其父级提供服务,等等。git push origin somebranch
现在发送者知道要发送什么以及接收者已经拥有什么,发送者将要发送的提交以及接收者没有的任何文件打包在一起。通过了解接收方确实拥有的提交\xe2\x80\x94,发送方也具有相同的提交,其中具有相同的文件\xe2\x80\x94,发送方可以发送精简包。6 接收者修复该包裹以根据需要填写任何缺失的部分(详细信息远远超出了本答案的范围)。
\n最后,无论接收者是谁,都必须设置一些名称或名称来记住每个分支中的最后提交。在这里,获取和推送再次出现分歧。
\n有了git fetch,当你的 Git 有它们的分支提示,并且知道它们的分支名称时,你的 Git 所做的就是重命名它们的分支。例如,他们的分支是他们的,而不是您的,如果他们更新了他们的 develop分支,这并不意味着您希望自己的分支名称从新develop提交中删除。因此,如果他们有,您的 Git 将创建或更新您的,而不是您的. 这假设你正在做一个. 例如,如果您使用遥控器的其他名称,例如,您将得到。developorigin/developdevelopgit fetch originbobbob/develop
另一方面git push,您的 Git 会要求他们的 Git 设置其中一个分支名称。这需要一点特别的照顾;我们将在下面看到更多相关内容。
5对于一些具有大量分支和标签的长期存储库来说,此步骤已成为一个痛点,而较新的 Git 协议允许服务器端过滤名称,以避免在此处完整列出。否则,您可能会花费 10 分钟来获取名称和哈希 ID 信息,最后却发现您的 Git 只需要一次提交,而该提交只需几秒钟即可完成。但原理还是一样的。
\n6从技术上讲,发送者通常会构建 Git 所谓的精简包。有些协议根本不支持包:发送者必须发送单独的对象,这要慢得多。不过,现代传输协议都使用精简包。
\ngit fetch实际情况假设你的存储库中有这个:
\n I--J <-- your-feature (HEAD)\n /\n...--G--H <-- master, origin/master\nRun Code Online (Sandbox Code Playgroud)\n与此同时,你的同事的存储库中有这个:
\n...--G--H <-- master, origin/master\n \\\n K--L <-- his-feature (HEAD)\nRun Code Online (Sandbox Code Playgroud)\n请记住,每个哈希 ID 都是唯一的,因此两个存储库中只有共享 提交。...--G--H
他现在运行git push origin his-feature,这会将他的提交发送K-L到 GitHub 存储库,并在那里创建一个新的分支名称his-feature,以便 GitHub 上的第三个存储库具有以下内容:
...--G--H <-- master\n \\\n K--L <-- his-feature\nRun Code Online (Sandbox Code Playgroud)\n请注意,我们不知道也不关心 GitHub 存储库“位于”哪个分支(它可能实际上位于其上,master但它是一个裸存储库,这没有多大意义)。GitHub 存储库没有origin/*名称,因为它没有从其他存储库复制名称:GitHub 上没有人以管理员身份访问该存储库并运行git fetch.
如果您现在运行git fetch origin,您的 Git 会联系 GitHub Git,后者会列出其分支名称及其相应的提交:master,即 commit H,以及his-feature,即 commit L。你的 Git 已经有了H,所以它不需要任何东西,但是你的 Git 要求L然后 for K(然后再一次已经有了H)。因此,您将被K-L添加到您的存储库中,然后您的Git 创建您自己的origin/his-branch. 您现在拥有:
I--J <-- your-feature (HEAD)\n /\n...--G--H <-- master, origin/master\n \\\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n请注意,您正在处理或处理的任何事情都没有发生任何变化。您拥有之前所有相同的提交,加上两个新的提交。你的分支名称都没有改变,但你已经获得了这个origin/his-feature名称。7
7如果您使用的是非常旧的 Git 版本(早于 1.8.4),并且使用git pull代替git fetch,则不会获得名称origin/*。在这种情况下,我建议避免git pull或升级您的 Git 版本。这并不重要,但 Git 版本远远落后最多是令人烦恼的:从那时起你就错过了很多改进。
git pull表示run git fetch,然后运行第二个 Git 命令您早些时候提到过您:
\n\n\n拉动他的改变
\n
我认为您的意思是您git pull使用分支名称运行his-feature。我个人不喜欢这个git pull命令,因为它非常棘手:它git fetch首先运行,这更简单,但然后立即运行第二个 Git 命令。您必须先选择要运行的 Git 命令,然后才能有机会查看git fetch实际执行的操作。但在 之后git fetch,您经常需要使用git merge, 这是默认的第二个命令。因此,有时候,或者很多时候,让这两个命令一个接一个地运行是很方便的。这就是git pull为你做的。所以现在是时候看看了git merge。
但请注意,您并没有真正提取他的更改:相反,您提取了他的提交\xe2\x80\x94commits 保留快照,而不是更改\xe2\x80\x94然后合并。这是处理更改的合并步骤。说拉他的改变有点草率了。在普通对话中这没什么问题,但是当您思考自己在做什么并把它画出来以确保一切正常时,最好说得更精确。
\n正如我们将看到的,您根本不需要进行此合并。
\ngit merge主要是结合工作让我们稍微重画一下现在的内容,以删除零件master。我们也将其视为origin/his-feature一种分支。该名称 origin/his-feature不是分支名称,但它的作用与分支名称一样,因为它保存了链中最后一次提交的哈希 ID。
I--J <-- your-feature (HEAD)\n /\n...--G--H\n \\\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n当我们有这样两个不同的分支时,我们可能想要合并工作。这就是该git merge命令的作用。让我们快速了解一下它是如何实现的。
因为提交保存的是快照,而不是更改,所以我们必须将这些以 \xe2\x80\x94 结尾的一系列提交\xe2\x80\x94 链J转换L为更改。这意味着我们必须找到一些共同的起点。两个分支上都有哪些提交?好吧,从图中可以看出这一点非常明显,只要您意识到提交一次可以在多个分支上进行。提交H、 和G等,从头到尾,都在两个分支上。
该git merge命令将找到这些提交中最好的。运气好的话\xe2\x80\x94,在这种情况下\xe2\x80\x94,只有一个这样的最佳提交。此提交是合并基础。只要合并基础不是您要合并的两个提交之一,Git 就必须在这里进行真正的合并。在这种情况下H既不是J也不是L。现在,Git将 commit 中的快照与 中的快照进行比较,以查看您更改了哪些内容。它还将 中的快照与 中的快照进行比较,看看它们发生了什么变化。然后,Git 组合这两组更改,将组合的更改应用到 中的快照,并使用结果创建新快照。HJHLH
新快照\xe2\x80\x94新提交\xe2\x80\x94是合并提交。合并提交的唯一特别之处在于它有两个父级,而不是只有一个。第一个父级与任何新提交相同:您现在正在使用的提交。第二个父级是您在命令中命名的提交git merge。因此,git merge his-branch将您的更改(来自HEAD/ commit)J(与 相比H)与他的更改(来自L(与 相比H))结合起来。它将组合的更改应用于H并进行新的合并提交M:
I--J\n / \\\n...--G--H M <-- your-feature (HEAD)\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n现在您已经合并了这两个分支。(即使您的提交名称L不是分支名称,但以 结尾的提交链也L符合分支名称。另请参阅“分支”到底是什么意思?)
该git rebase命令是我们见过的最复杂的命令。如果上面合并的快速扫描看起来很复杂,请小心,因为变基更糟糕。有些人认为任何人都不应该使用git rebase. 我不是这些人中的一员,但这是一个棘手的命令,您需要知道如何以及何时使用它,以及何时不使用它。要知道何时使用它、何时不使用它,最好的方法就是确切地知道它的作用。因为它太复杂了,所以我无法在这里详细介绍所有细节,但让我们看看您运行的一个特定的变基:
\n\nRun Code Online (Sandbox Code Playgroud)\ngit rebase -i HEAD~3\n
该语法HEAD~3告诉 Git从通过 name 找到的提交中倒数三个第一个父级HEAD。鉴于我们已经绘制了这个:
I--J\n / \\\n...--G--H M <-- your-feature (HEAD)\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n我们知道commit 的第一个M父级是J,我们得到的第一个后退是从M到J。下一步是从J到I。CommitJ只有一个父级,因此它的第一个父级是它唯一的父级,但这很好:我们到达提交I并返回了两次。现在我们需要再返回一次,从I到H。现在的参数git rebase -i可以解析为 commit 的实际哈希 ID H。
它git rebase本身所做的是复制一些提交,就像通过git cherry-pick. 8 它复制的提交集部分取决于您提供的参数,在本例中指定了 commit H。这是它不会复制的第一个提交。它不会H向后复制任何提交。9
本质上,git rebase列出从开始HEAD并向后工作的提交,并在您列出的点和/或从那里返回的任何提交处停止。所以它最终会列出 commits M、J-and- L、和I-and- K,然后点击H并不列出它。因此,要复制的提交列表是I、J、K、L和M。10
从这个列表中,git rebase通常会完全删除任何合并提交。由于M是合并提交,因此您git rebase将删除它,留下提交I-J并K-L进行复制。它可能会下降更多,但在这种情况下,它不会这样做。然后,您将在交互式 rebase 中得到一个由 4 个11 pick命令组成的命令列表。这些代表 Git 运行的指令git cherry-pick。
此时,git rebase使用 Git 的分离 HEAD模式(我们再次没有涉及到)来复制这四个提交中的每一个,使用git cherry-pick或等效的。根据您的 Git 选择先复制您的提交还是先复制他的提交,以及您是否使用该--force标志,您git rebase可能会决定重复使用某些提交,或者实际上会复制它们。出于说明目的,我假设它最终会重新使用您的I和J,并复制他的K-L,但也可能会以相反的方式进行,或者复制所有这些。
与此同时,您告诉 Git 仅复制这两个提交之一。为了便于说明,我将选择L复制。
8一些 rebase 命令字面上使用git cherry-pick. 你所做的那种变基,确实如此。其他人只是近似它,但你仍然可以认为它们就像使用了cherry-pick。我们没有在这里单独描述cherry-pick,因为我不想让这个答案变得太长。
9请记住,提交通常是向后进行的。我们使用分支名称或原始哈希 ID 或类似的名称来指定某个提交,HEAD~3表示要向后计数,然后到达该提交后,Git 会从那里继续向后工作。指定的提交是 Git开始的地方,然后根据需要在其之前进行其他操作。
10由于合并提交,这里的顺序正确会变得很复杂。的实际顺序git rebase -i是用git rev-list产生的--topo-order --reverse,并且没有像我们希望的那样精确指定。幸运的是,有了git rebase -i,我们可以根据需要随意重新调整顺序。无论如何,这个细节对于您的特定情况可能并不重要。请注意合并提交时出现的陷阱:顺序可能不是您所期望的。
11从您的 中HEAD~3,我知道在您使用 进行合并提交之前,您的分支上有两个未共享的提交git pull。我不知道他们有多少这样的承诺。您的 rebase 中的实际数量将比他们的未共享数量多 2 个。
我们从这个开始:
\n I--J\n / \\\n...--G--H M <-- your-feature (HEAD)\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n以及复制提交的愿望I。新的(据说是改进的)提交应该在 之后H,而不是现在的地方。但现有的确实I 是在之后出现的H。所以 rebase 很聪明,它对自己说:我可以重新使用现有的I. 确实如此。现在它想要复制J,以便新副本出现在I\xe2\x80\x94 之后,但同样,它已经复制了,因此 rebase 只是重新使用现有的J. 此时,我们有:
I--J <-- HEAD\n / \\\n...--G--H M <-- your-feature\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n(这是正在运行的“分离头”模式,HEAD直接指向提交)。现在 Git 想要复制L,改进后的复制即将到来J。现有的L在 后面,所以这次KGit 确实必须复制它。请记住,提交的父级位于提交的元数据中,并且无法更改。CommitL总是指向 commit H。因此 Git 复制L到一个新的和改进的L\',如下所示:
I--J--L\' <-- HEAD\n / \\\n...--G--H M <-- your-feature\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n复制现已完成。
\n最后一步git rebase让 Git 将分支名称 \xe2\x80\x94(您开始时使用的分支名称)拉出,在本例中,将your-feature\xe2\x80\x94 从它现在指向的提交中拉出,以使其指向最终复制的提交反而。所以最后一步的git rebase结果是:
I--J--L\' <-- your-feature (HEAD)\n / \\\n...--G--H M ???\n \\ /\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\ncommit 发生了什么M,你的合并提交?答案是:它仍然存在,在您的 Git 存储库中。你就是找不到它。如果您在开始变基之前记下其哈希 ID,则可以使用它来查找它。Git 提供了找到它的方法,12但现在您不需要担心它们。由于您看不到commit M,所以看起来您现在拥有:
I--J--L\' <-- your-feature (HEAD)\n /\n...--G--H\n \\\n K--L <-- origin/his-feature\nRun Code Online (Sandbox Code Playgroud)\n你可以继续开发更多的东西。
\n12其中包括 Git 的reflogs,这是从错误的 rebase 或类似情况中恢复的常用方法。
\n我们不知道,因为我们不知道你们最终将如何合并你们的工作。你会用git merge,还是会用git rebase?你的同事呢?
假设此时您又进行了两次提交:
\n I--J--L\'-M--N <-- your-feature (HEAD)\n /\n...--G--H <-- master, origin/master\nRun Code Online (Sandbox Code Playgroud)\n您将这些提交发送到 GitHub 服务器并在那里使用“拉取请求”机制。让我们进一步假设合并此 PR 的人都使用真正的合并。(他们今天在 GitHub 上有三个选项;真正的合并是其中之一,这会迫使 Git 进行合并,即使它可以进行快进。)结果将如下所示,在 GitHub Git 上:
\n I--J--L\'-M--N [PR #123 was here, at commit N, but is done now]\n / \\\n...--G--H---------------O <-- master\n \\\n K--L <-- his-feature\nRun Code Online (Sandbox Code Playgroud)\n让我们假设他又进行了两次提交,我们将其称为P和R(跳过Q,因为它看起来太像O),并将它们作为拉取请求发送到 GitHub Git:
I--J--L\'-M--N\n / \\\n...--G--H---------------O <-- master\n \\\n K--L--------P--R <-- PR#124\nRun Code Online (Sandbox Code Playgroud)\n同样,负责合并的人可以选择使用哪个 GitHub Web 界面点击按钮。他们使用merge,还是rebase 和 merge,还是squash 和 merge ? 让我们假设他们使用常规合并。这次Git被迫进行真正的合并\xe2\x80\x94快进是不可能的\xe2\x80\x94并且真正的合并将使用commitH作为合并基础。它将H中的快照与 中的快照进行比较O,以查看一侧做了什么,并将 中的快照与H中的快照进行比较R,以查看另一方做了什么。它将结合这些更改并进行新的合并提交S:
I--J--L\'-M--N\n / \\\n...--G--H---------------O--S <-- master\n \\ /\n K--L--------P--R\nRun Code Online (Sandbox Code Playgroud)\n没有丢失任何提交,但可能有点丑陋,提交L和L\'都在历史记录中。该历史反映了现实:您确实将他的提交复制L到了您的提交中L\'。CommitL\'上有您的名字:您是提交者,您的同事是作者。13 因此,一些人认为这是最好的方法。
还有很多其他方法可以处理这个问题。客观上没有一个是“最好的”。Git 提供了工具。它没有规定特定的工作流程。它并不规定最终的提交集应该是什么:这取决于您。GitHub 提供了特定的工作流程(通过其可点击的按钮),但仍将很多操作留给操作该按钮的人,并且直接使用 Git,只要您在 GitHub\xe2\x80\x94 上拥有适当的权限,您就可以\xe2\x80\x94 执行任何操作git 可以做到。
\n13您可以在运行时控制某些行为git cherry-pick,但这也是正确的信息,因此您应该保持这种方式。当使用 时git rebase,很难对单个的选择大惊小怪。
| 归档时间: |
|
| 查看次数: |
646 次 |
| 最近记录: |