[英]how to merge branch into master on the created commit
我有这个场景,我从 master 创建了一个分支 A,其中 master 负责人在1234
提交 id
现在一些开发人员将更多的分支和提交推送到 master 中,现在 master 负责人在789
提交 id 上。
是否可以在提交1234
时将分支 A 合并到 master 中?
不要试图把这个比喻推得太远(因为它会崩溃),但这有点像问你是否可以将你的 package 放在中国的货船上,因为船在洛杉矶的港口。 你可以,但你得先把船弄回中国。
让我们看看 Git 是如何工作的,而不是上面的笨拙的类比。 Git 都是关于提交的,而且——正如你在这里正确描述的——这些提交被编号。 不过,这个数字并不是简单的连续计数数字——例如,提交 #52 后面没有提交 #53——而是它们是大的、丑陋的、看起来随机的 hash ID。 所以我喜欢用单个大写字母来表示它们:
...--G--H <-- master
在这里,名称master
指向提交H
。 H
是master
上的最新提交。 提交H
本身向后到达较早的提交G
,后者向后到达另一个较早的提交,依此类推。
在您的情况下,您创建了一个新名称也指向提交H
,然后进行了一些新提交:
I--J <-- your-branch
/
...--G--H <-- master
不幸的是,从那时起,其他人向master
添加了更多提交,如下所示:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
您现在询问是否使用git merge
。
当我们确实使用git merge
时,我们这样做是因为我们想合并工作。 也就是说,你从提交H
开始——一些特定的文件集,永远存储在一个带有一些丑陋的大 hash ID 的提交中。 您更改了一个或两个文件并进行了新的提交,它得到了一些我称之为I
的其他大而丑陋的随机 ID,并且可能更改了另一个或两个文件(或相同的文件或两个)并进行了另一个提交J
. 所以在H
和J
之间,你做了一些工作,导致一些文件发生了一些变化。
Git 可以通过将提交H
中的快照(从您开始的所有时间冻结的文件集)与您最近提交中的快照进行比较,向您展示您所做的(总结为一组大的一次性更改), I
。 这将有如下指令:在文件main.py
中,删除第 47 行,并在第 300 行之后添加一些行。
Git 还可以通过比较H
中的快照中的内容(注意此快照在两个分支上共享)与提交K
中master
上的最新快照中的内容,向您展示其他人做了什么。 这可能包含更改 README.md 中的第 7 行README.md
类的指令,以及诸如在main.py
中的第 100 行添加一行的指令。
git merge
可以为您或任何人做的就是结合这些更改。 也就是说,如果他们接触README.md
而你没有接触,Git 将保留他们的更改。 如果您触摸了Documentation/info.md
而他们没有,Git 将保留您的更改。 如果您和他们都修改main.py
, Git 将尝试保留对该文件的两组更改。
如果 Git可以自己组合所有这些更改,则 Git 将自己进行一个新的提交。 这个新的提交将包含来自H
中快照的所有文件(通用起点)作为其快照,并应用组合更改,以便 Git 保留您的更改并添加他们的更改,或者 - 如果您更喜欢查看它方式 - 保留他们的更改并添加您的。 结果都是一样的,看起来像这样:
I--J
/ \
...--G--H M
\ /
K--L
我在这里留下的是哪个分支拥有新的提交M
。 有两个名称——master 和your-branch
master
并且 Git 只会更新这两个名称之一,以便它指向新的提交M
。 另一个名称将继续指向提交J
或提交L
(无论它之前指向哪个)。
我还省略了另一个细节,这有时确实很重要:因为提交M
有两个反向链接,或者parents ,指向提交J
和L
,所以这两个中的一个首先出现。 另一个是第二个,尽管对于 Git,这只是“不是第一”。 稍后, --first-parent
标志有时对于挑选“第一个”父级很有用。 无论您如何进行合并, M
中的快照都是相同的,但是第一父级的选择取决于您git switch
到哪个分支,以及您给git merge
的名称:
git switch master
git merge your-branch
给我们:
I--J <-- your-branch
/ \₂
...--G--H M <-- master
\ /¹
K--L
也就是说, master
是指向M
的名称,而第一个父级现在是L
。
这通常是大多数人想要做的——除非他们想使用git rebase
。
是否可以在 [shared] 提交时将 [my branch] 合并到 master 中?
不完全是,因为无论你做什么, master
最终都需要指向除H
之外的其他提交。
您可以“弹出”提交KL
,如下所示:
I--J <-- your-branch
/
...--G--H <-- master
\
K--L [abandoned]
这样做的问题是提交K
和L
现在丢失了。 它们并没有消失——它们仍然在存储库中——但是 Git 通过以分支名称开头来查找提交。 用于查找提交L
的名称master
。 从L
, Git 可以向后工作到K
。
Git无法继续工作。 Git 总是向后工作。 因此,一旦您将master
向后移动两步,指向H
, Git 就再也找不到K
了。 即使 Git可以找到K
,也无助于找到L
。 所以这两个提交现在被“放弃”了。 这丢掉了他们的工作。 这不是合并的目的:合并有助于在添加您的工作时保留其他人的工作,或者等效地,在添加其他人的同时保留您的工作。
无需赘述,变基背后的想法是我们希望将一些提交复制到一些新的和改进的提交中。 在这种特殊情况下,您可能希望接受您认为非常好的IJ
提交,并通过进行两次新的提交来“改进”它们——由于目前还没有明显的原因,我们将其称为I'
(I- prime) 和J'
—很像I
和J
。
新的和改进I'
与原来的I
之间的区别在于两部分:
I'
将不向后链接到H
,而是链接到K
。I'
作为它的快照,不是H
中随您的更改而修改的快照,而是K
中随您的更改而修改的快照。 I'
的rest将与I
完全相同,包括提交日志消息。 现在让我们画出I'
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
\
I' <-- temporary-branch
(The underlying Git command that produces I'
from I
is git cherry-pick
. We have to have Git do this on a temporary branch , because Git needs to be able to find all the commits, including both the old ones and the new ones正在构建。rebase 命令隐藏了这种复杂性的大部分,但是因为 Git 在某些事情上很糟糕,所以有时你会看到这一切。)
一旦 Git 复制了I
到I'
,我们需要让 Git 复制J
到J'
:
I--J <-- your-branch
/
...--G--H
\
K--L <-- master
\
I'-J' <-- temporary-branch
一旦将your-branch
上的所有提交复制到新的临时分支,然后我们将 Git 从提交J
中“剥离分支名称” your-branch
并将其粘贴到提交J'
— 刚刚制作的最后一个副本 Git —并丢弃临时名称:
I--J [abandoned]
/
...--G--H
\
K--L <-- master
\
I'-J' <-- your-branch
因为 Git 按分支名称查找提交,所以如果我们现在查看这个存储库,看起来好像我们等到提交L
存在,然后才开始工作并生成提交IJ
。 我们将看到提交I'
和J'
,而不是I
和J
,但除非我们记住实际的 hash ID——而且没有人这样做过——否则我们不会注意到我们现在正在查看两个不同的提交。 (Git 会知道。Git 查看原始的 hash ID。但我们会忘记,因为这是人类所做的。)
因为 rebase用新的提交替换了旧的提交(新的并且据说是改进的),所以它并不总是合适的。 特别是,如果你已经将你的I
和J
提交给了其他人,并且他们依赖于他们——包括他们的 hash ID——然后说“把它们扔掉,改用这些新的和改进的”会让他们做额外的工作. 有时这很好。 (例如,如果他们已经同意这样做,那也没关系。)有时不是。
但是,如果您从未将这些提交给任何其他人,他们甚至不会知道您这样做了。 所以对于那个特殊的情况——“私人”提交——只要你知道你在做什么,rebase 是安全的。
变基的好处是,最后,Git 的历史“看起来更简单”,人们可以用更少的精神负担来思考它。 缺点是它不是真正发生的事情:如果你在 rebase 期间破坏了某些东西,它可能很难调试,这是一个谎言。 是一个善意的谎言让事情变得更好,还是一个丑陋的大谎言导致死亡和毁灭? 我们不知道,您可能还不知道,直到您尝试一下。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.