使用 Git 重新定位



我看了大量关于如何使用 Git 变基的文章,这是有道理的......或者至少我认为是这样。但是,我正在努力解决以下问题...

对于此方案,我们有以下分支:

  • 主(本地)
  • 原产地/主
  • 杰格斯(当地)
  • 原产地/杰格斯

好的,所以现在让我们假设 origin/master 领先 1 个提交。因此,我从文章中被告知,我正在研究的开发团队将在jheigs分支上执行以下操作:

$ git add ...
$ git commit ...
$ git status (ensure everything is up-to-date locally)
$ git pull (again, check and ensure that everything is ready to go)
$ git pull --rebase origin master
$ git push (defaulting to origin/jheigs)
  1. 当变基运行良好时,我遇到的是 origin/jheigs 和本地 jheigs 的 HEAD 提交不匹配(给定上述变基),所以有时我可能不得不拉然后推,这可能会导致冲突。我感到困惑的是...我应该改用:

    $ git push --force origin jheigs (?)
    
  2. 第二个问题...现在,假设我已经推动并且 jheigs 已正确重定为原点/母版。不存在冲突,我的 jheigs 和 origin/jheigs 现在领先主 1 次提交。好吧,一天过去了,我需要做出更多改变。所以我在 jheigs 和添加/提交上进行这些更改。但是,源/主没有其他更新。从本质上讲,我仍然领先于原始/主 1 次提交(很快将是 2 次)。我是否仍遵循上述相同流程?还是我只是添加/提交并推送到原点/jheigs而不变基,因为我已经领先于原点/主站?

我很抱歉这太长了,但我认为我已经弄清楚了,它并不像我想象的那么顺利。我想小心变基,所以任何帮助都值得赞赏!

首先,我会(并且确实)完全避免git pull,或者大部分:它本来是为了方便,但事实证明它很方便。它只是运行git fetch然后是第二个 Git 命令,该命令会影响您签出的任何分支。 有时我不想或不需要获取;其他时候,我想在执行任何第二个命令来影响当前分支之前,环顾一下 fetch 运行时发生了什么。

正如您可能已经读到的,git rebase实际上是关于复制(一些)提交。 你的仓库中有一些提交的集合,现在,无论出于何种原因,一些提交已经消失了,你想要做出更新、更好、更漂亮、更闪亮的提交。

使所有这些有意义的方法是绘制提交图。 请记住,涉及多个克隆 - 不同的存储库,其中包含大致相同的提交集,但不完全相同的提交集!

绘制您自己的仓库提交

你可以让 Git 为你做这件事:git log --all --decorate --oneline --graph,或者 git log (with) A DOG。 不过,一开始用手做是很好的锻炼。 此外,当您手动操作时,您可以水平绘制这些内容,这往往更有意义。

请记住,每个提交(由其唯一的哈希 ID 标识)都是只读的。 每个提交都指向其提交。 像masterjheigs这样的分支名称,或者像origin/masterorigin/jheigs这样的远程跟踪名称,指向(记录)提示提交的哈希 ID,Git 从这些提示向后工作:

...--C--D--E   <-- master

F--G   <-- jheigs (HEAD)

这可能是存储库的图形片段,其中提交Emaster的提示,并且E指向D,而您添加了自己的两个提交:G,这是jheigs的提示,指向F,早些时候,您添加了指向DF

请注意,在这里,提交D及更早版本都在两个分支上。

git rebase会将1个提交复制到新的和改进的提交中。 例如,在这里你可能想F复制到一个新的和改进的F',其中的主要区别在于F'附加到E,而不是D

F'   [new and improved!]
/
...--C--D--E   <-- master

F--G   <-- jheigs (HEAD)

F复制到F'后,您现在可以将G复制到新的和改进的G'

F'-G'   [new and improved!]
/
...--C--D--E   <-- master

F--G   <-- jheigs (HEAD)

现在,所有"打开"(可从)jheigs不是master上的提交都已复制到新的和改进的版本,您可以让 Git 从提交G剥离jheigs标签并将其粘贴到G'

F'-G'  <-- jheigs (HEAD)
/
...--C--D--E   <-- master

F--G   [abandoned]

昨天如此闪亮和漂亮的旧、沉闷的FG提交现在是垃圾,取而代之的是闪亮的新F'G'。 这是因为您的分支名称现在jheigs指向最后一个新复制的提交。


1此复制就像通过git cherry-pick. 根据您使用的变基命令,实际上可以使用git cherry-pick来完成。


还涉及另一个存储库:fetchpush

上图适用于您的存储库,但此处涉及第二个存储库。 它们有自己的分支名称和提交。 您拥有的提交以及它们也拥有的提交共享提交哈希 ID。 可能有一些提交是他们没有的;并且可能有一些他们没有的提交。

如果您认为他们可能有您没有的提交,您应该运行git fetchgit fetch origin。 这让你的 Git 在名称origin下列出的 URL 处调用他们的 Git。 您的 Git 调用他们的 Git,并让他们列出其分支名称给出的所有提交(通过哈希 ID)。

如果他们有你没有的提交,你的 Git 现在会下载这些提交。 您的 Git 还会更改其分支名称,例如masterjheigs,以便它们读取origin/masterorigin/jheigs。 这些新名称不会干扰您的分支名称。

现在您已经拥有了他们拥有的所有提交,加上您之前的所有提交,您的存储库可能如下所示 — 假设您尚未完成git rebase

H   <-- origin/master
/
...--C--D--E   <-- master

F--G   <-- jheigs (HEAD), origin/jheigs

您的origin/*是您的 Git 对其分支名称的记忆。 这意味着他们的master识别提交H。 多亏git fetch,您现在已经提交了H他们jheigs识别提交G,就像你的一样。

如果你现在运行git rebase master,你的 Git 会将你的FG复制到一个新的F'G',在提交E之后构建,这是你的master点。 您可能希望让它们在提交H之后出现。

在这里,您可以非常轻松地执行此操作:您可以运行git rebase origin/master。 这告诉您的 Git 查找您拥有的提交(即FG),这些提交无法从您的origin/master访问(即,据您所知,它们的master),并将副本放在提交H之后。 结果如下所示:

F'-G'  <-- jheigs (HEAD)
/
H   <-- origin/master
/
...--C--D--E   <-- master

F--G   <-- origin/jheigs

请注意,origin/*名称都没有移动,您自己的master也没有移动。 但是,称之为origin/jheigs的他们的jheigs仍然记得提交G

现在你需要git push --force jheigs,告诉他们:扔掉提交FG,以支持新的闪亮F'G'一旦他们同意这样做,你的 Git 就会记住他们的jheigs指向G'

F'-G'  <-- jheigs (HEAD), origin/jheigs
/
H   <-- origin/master
/
...--C--D--E   <-- master

由于没有名字可以找到它们,提交FG似乎完全消失了。

为什么你可能不想变基,永远

请注意,那里可能有第三个Git 存储库,以及第四个或更多,其中包含另一个origin/jheigs。 如果是这样,所有其他存储库必须采取一些操作(例如运行git fetch)来获取新提交并更新自己的origin/jheigs名称。

此外,在您决定放弃提交以支持新的和改进的提交之前,他们可能已经在您的提交之上构建了自己的提交。 如果是这样,他们可能会被迫复制他们的提交,就像你复制你的提交一样。 这甚至可能是一件好事,也可能让他们感到恼火。

因此,如果你要变基其他人已经或可能有的提交,你应该合理地确定为他们工作是可以的。 如果没有其他人拥有原始提交,那么复制和替换它们显然是安全的。 如果其他人都同意这种复制替换应该发生,那仍然很好。 因此,如果可以这样做,并且这样做有意义,请变基。

当变基运行良好时,我遇到的是 origin/jheigs 和本地 jheigs 的 HEAD 提交不匹配(给定上述变基)

是的,但区别在于您额外的非推送工作。git pull --rebase后,上游的HEAD将是你本地HEAD的祖先

所以有时我可能不得不拉然后推

这通常是正确的做法

这可能会导致冲突。

它不应该,除非其他人在你的拉和推之间推(在这种情况下,你需要再做一次,以合并他们的工作)。

好吧,一天过去了,我需要做出更多改变。所以我在 jheigs 和添加/提交上进行这些更改。但是,源/主没有其他更新。从本质上讲,我仍然领先于原始/主 1 次提交(很快将是 2 次)。我是否仍遵循上述相同流程?还是我只是添加/提交并推送到原点/jheigs而不变基,因为我已经领先于原点/主站?

两者都很好。如果上游没有移动,git pull --rebase什么也不做。

最新更新