当我尝试将rebase从master转到我的开发分支时,我遇到了一个奇怪的问题。主人和开发部门都在进行一些工作。
为了从主人那里得到改变,我在下面做
git checkout dev
git rebase master
这很好用。但是 -
dev
分支提交正在重复
git checkout dev
git add .
git commit -m 'some change'
git push
git rebase master
提交some change
在dev分支的git项目历史中重复。它还会创建循环。git rebase master
那么它运行良好,我可以在项目中看到线性历史记录。我不确定为什么会这样。这在我看来是奇怪的行为。如果有人能解释,请帮忙。
项目历史
提交b48659d
正在重复(我做37c07a4
的原始提交),当第一次推送然后在dev分支中进行rebase。
* fbadb86 (HEAD -> dev) Merge branch 'dev' of *******
|\
| * b48659d (origin/dev) sample added in dev branch --> did rebase after push and got this commit again
* | 37c07a4 sample added in dev branch --> commit + push
* | 46c1f40 (origin/master, origin/HEAD, master) master file added in master branch --> commit + push
|/
* 5baae80 first commit
这种情况发生在推送之后的所有提交中。这导致了重新定位中的大量问题,因为提交正在重复,并且即使我自己的代码更改来自先前的提交,也会产生很多冲突。
答案 0 :(得分:1)
所有提交始终是只读的。它们也是永久性的,有一些例外(与任何人是否可以找到它们有关)。这意味着git rebase
副本提交。这是它的工作!
让我们来看看您的git log --graph --oneline ...
输出,但让我们开始更简单一点:
* b48659d (dev) ...
* | 46c1f40 (origin/master, origin/HEAD, master) ...
|/
* 5baae80 first commit
请注意缩短的哈希ID,例如5baae80
和b48659d
。这些是真正的名字"每个提交,缩短为只有7个字符,因为它通常就足够了。 1 每个提交记录父提交的ID,Git使用这些父提交哈希值从更近期的分支提示提交开始,逐步跟踪每个提交历史记录。分支dev
的提示提交现在为37c07a4...
:
5baae80--46c1f40 <-- master, origin/master
\
b48659d <-- dev
这些提交都不能改变!
您现在git push
到origin
。 git push
命令调用第二个Git,在作为origin
的机器上调用,然后移交你没有的提交,每个人都同意他们的ID。然后你的Git要求他们的Git将dev
设置为与origin/dev
相同的值dev
:b48659d...
如果他们同意此请求, Git记得他们现在他们的 dev
- 你的origin/dev
- 指向b48659d
,就像我们在这里画的那样,所以现在我们有了这个:
5baae80--46c1f40 <-- master, origin/master
\
b48659d <-- dev, origin/dev
此时,您运行git rebase
,这就是事情开始出错的地方。
1 Git现在动态选择缩短的长度,而不是总是使用7,但默认情况下以7开头。您可以随时使用更多:全名当前为40个字符。
git rebase
命令无法更改任何现有提交,因为Git中的 nothing 可以做到这一点。 Git的目的是让这个变得不可能。所以它甚至没有尝试。相反,它 copy 提交。
复制提交时,Git需要两条信息:
Git获取第一个 - 通过列表提交进行复制的提交列表,从HEAD
开始并向后工作,在您选择的某个时刻停止。 (这个列表是向后的,所以它必须反转它。)Git得到第二个 - 目标&#34;复制后&#34;从您提供的论点开始,例如master
。
在这种情况下,HEAD
名称为dev
(因为您在启动rebase之前运行git checkout dev
),因此要复制的提交以名称{{1点:
dev
因此,我们将复制一系列在5baae80--46c1f40 <-- master, origin/master
\
b48659d <-- dev (HEAD), origin/dev
停止的提交。
复制它们的地方来自你的论点b48659d
。名称master
标识提交master
,因此副本将追溯46c1f40
。
棘手的部分是Git如何计算提交而不是进行复制的内容。它是从46c1f40
开始并向后工作的。你可以想象Git会暂时将这些提交中的每个提交着色。这会将Git带到b48659d
,它具有 no 父提交(它是存储库中的第一个提交,因此它不能拥有父提交)。这会停止步行,因此这两个提交被涂成绿色。然后Git从您通过名称 - 5baae80
指定的提交开始 - 并暂时将提交绘制为红色。 46c1f40
的父级是46c1f40
,因此Git将这一个描绘成红色(不要复制),并尝试继续绘制其父级以绘制红色。没有父母,所以我们完成了临时绘画,留下了一个绿色提交,5baae80
。
这是要复制的提交列表。 (它倒退了,但无论如何它只有一个条目,所以逆转它什么都不做。)
现在Git开始复制过程。每个要复制的提交都会被复制,就像b48659d
一样(如果您使用git cherry-pick
,它会被樱桃选择复制)。这使 new 提交。
现有git rebase -i
的新提交是b48659d
。让我们把它画进去:
37c07a4
现在已经复制了整个提交列表, 37c07a4
/
5baae80--46c1f40 <-- master, origin/master
\
b48659d <-- dev, origin/dev
做了最后一件事。它将名称git rebase
从原始提交字符串中删除,并将其粘贴到新副本上。结果是:
dev
您可以在问题中引用的 37c07a4 <-- dev (HEAD)
/
5baae80--46c1f40 <-- master, origin/master
\
b48659d <-- origin/dev
输出中看到这一点。
剩下的一个问题是,这是从哪里来的:
git log --graph
该提交存在是因为您运行了* fbadb86 (HEAD -> dev) Merge branch 'dev' of *******
。
您可能通过运行git merge
来运行git merge
。默认情况下,git pull
为您运行git pull
,然后为您运行git fetch
。 (我建议Git中的初学者根本不要使用git merge
:它做了什么,以及它做的方式,过于混乱。将其分成git pull
,然后迟早会被分成一秒钟Git命令,有时为git fetch
,有时为git rebase
。)
一般来说,git merge
的作用是尝试将两个独立的&#34;开发线组合在一起&#34;。给出这样的图表:
git merge
Git或多或少地认为,在您撰写 37c07a4 <-- dev (HEAD)
/
5baae80--46c1f40
\
b48659d <-- origin/dev
时,其他人写了b48659d
(origin/dev
)。为了组合它们,Git找到了他们的&#34;合并基地&#34;,这是这两条线再次连接的地方。按照眼睛的线条清楚地表明:那是37c07a4
。所以Git创建了一个新的合并提交,这是一个与两个父级的提交。让我们在:
5baae80
这就是您现在所看到的 37c07a4--fbadb86 <-- dev (HEAD)
/ /
5baae80--46c1f40 /
\ __--------
b48659d <-- origin/dev
输出中的内容(git log --graph --oneline ...
和master
箭头也添加了 - 我把它们排除了因为它们太难了画这种方式)。
这里的根本错误是在其他人已经拥有的提交上运行origin/master
。在这种情况下,git rebase
处的其他Git已经提交了origin
。您无法更改该提交,因此在制作新副本时,您将停止使用 b48659d
,但他们仍然拥有他们的。最终你必须加入他们的#34;回到&#34;你的副本&#34;,通过合并,给出这个相当混乱的画面。
(此规则有一个例外:如果您可以说服其他人让b48659d
放弃,并切换他们的b48659d
以使用您的新规则相反,你仍然可以改变。但是,你是否可以,以及如何,是另一个问题。)