我读了很多关于变基后的强制推送的文章,但我仍然不理解所有的东西。
我不清楚的是,rebase是以何种方式重写git历史的。
假设处于这种情况:
所以有一个main
分支,在某个时候我从提交d
(在main
分支上)创建一个新分支(feat1)
。然后I 4提交(e
到h)
。与此同时,其他人继续在main
上工作,并推送提交i
和l
。
现在我准备在main
上重定feat1
分支的基,所以在执行之前,我拉main
:
git checkout main
git pull --rebase
git checkout feat1
git rebase main
现在的情况是这样的:
我解决(如果是)冲突,并测试一切都按我预期的那样工作。太棒了,太完美了。
现在我想推我的分支,但我不能。因为我做了一个变基,我需要做力推。为什么?为什么?
我为什么要重写git历史?
3条答案
按热度按时间4nkexdtk1#
如果你在变基之前将你的修改向上游推送到你的特性分支,那么你的本地副本将与上游的顺序不同--因此需要强制推送。
然而,如果你把你的本地副本合并到主分支上,这将是一个只允许快进的合并,所以可以不需要强制地将其向上推到主分支上。
brvekthn2#
第二个图中的
e
与第一个图中的e
不是同一个提交。它可能 * 做出相同的更改 *(尽管不一定),它可能有相同的消息(尽管不一定),但它的祖先和树的内容都不同,所以它是一个不同的提交。同样地,第二个f
不可能与第一个f
相同,这同样适用于g
和h
。通常,人们在解释换基时会将第二个图中的黄色提交表示为e'
、f'
、g'
和h'
,以显示差异。当你去推时,上游有
h
,你推h'
。h'
与h
不是同一个提交,也不是h
的后代(我们不能通过在h
上添加更多提交来达到h'
),所以这被称为“非快进”推送。在
h
作为feat1
发布的时候,其他人可能已经做了更多的提交i
和j
,从h
开始。在你推送h'
之后,它们留下的提交仍然是h
的后代,而h
不再是feat1
的一部分(可能不再是任何分支的一部分)。对他们来说,修复这种情况实际上并不困难(这只是另一个rebase,使用--onto
),但这是一个烦恼,它迫使人们停下来弄清楚发生了什么,所以git在你的路上设置了一个路障,以确保这是你真正想要做的事情。8cdiaqws3#
当你在
main
分支的顶部重定基新创建的提交时,在@hobbs回答中可以看到很好的解释。你现在应该明白了,在你的特性分支中,当你的推送成功时,新提交
i
、l
、e'
、f'
、g'
和h'
将替换旧提交e
、f
、g
和h
。普通的分支推送只能在现有提交的基础上添加新提交(我们称之为快进),以确保您不会错误地丢失数据。
所以git迫使你强制push来确保你完全意识到你正在重写历史,你会丢失一些提交(那些被替换的)。这是为你准备的,因为你已经创造了类似的东西。