我正在处理名为“role”的分支。远程主分支经常被更新,因此在将我的更改提交到远程分支后,我需要将该分支与最新的主分支合并。下面是我的步骤:
# from local
git add .
git commit 'Add feature'
git push origin role
# rebase
git pull --rebase origin master
rebase只影响本地分支还是远程分支或两者都有影响?如果仅重新命名本地分支,是否应在重新命名后提交到源?
这里有很多要注意的东西。首先,Git术语并不是很好理解——“远程”,“跟踪”,“分支”和“远程跟踪分支”都有非常不同的含义!—而你又使用了另一组术语,这使事情变得更加棘手。因此,在回答我认为你想问的问题之前,让我们定义一下这些术语。(另请参见gitglossary
,尽管其中并不包含所有这些术语。)
远程仓库是一个短名称,如origin
。它主要用作URL的占位符,这样您就不必一直输入一些长URL,并且还构成了远程跟踪分支的名称(稍后我们将定义)。
分支是一个模糊的术语:请参见 我们所说的“分支”到底是什么意思?。在这种情况下,我们首先使用它来表示像master
这样的分支名称。在Git中,分支名称只是特定提交的名称,我们称之为该分支的tip,但是像master
这样的本地(普通)分支名称具有特殊属性,我们很快就会介绍。
远程跟踪分支是您的Git根据您的Git调用其他Git时看到的内容为您分配和更新的名称。这些是像origin/master
这样的名称。这些远程跟踪分支名称没有普通(本地)分支名称的特殊属性。
跟踪是Git用作缩写词的可怕动词,表示更现代和冗长的方式来表达同样的意思。可以设置本地分支“跟踪”远程跟踪分支。更现代的方法是将远程跟踪分支设置为其上游的本地分支。设置上游不会做任何您无法“手动”完成的事情,但使Git自动为您执行此操作非常方便。
通常,我们会将远程跟踪分支origin/master
设置为本地分支master
的上游。同样,我们会将origin/role
设置为本地分支role
的上游。此时记住,本地分支和远程跟踪分支都在您自己的 Git中。它们实际上都是本地的!远程跟踪分支之所以被称为“远程跟踪”,只是因为它们是自动更新的。
git fetch
和git push
(以及git pull
,但请参见结尾的旁注)时,您的Git会调用另一个Git。另一个Git有自己独立的仓库。您的Git获取其他Git的方式是通过某个URL,并且该URL存储在“remote”名称下,例如origin
:您的Git通过Internet-phone呼叫origin的Git并与其他Git通信。您的Git从它们那里获取东西(git fetch
)或将东西发送给它们(git push
),您的Git和它们的Git都完全在本地工作,您的Git在您的仓库上工作,它们的Git在他们的仓库上工作。
rebase 只影响本地分支还是远程分支还是两者都有影响?
这个很简单:如果你没有推送,那么你只能影响本地事物。如果只有本地分支被 rebase,是否应该在 rebase 后再次提交到 origin?
这段文字有一个嵌入式的误解。当你进行提交时,你仍然只影响本地事物。要将本地内容发送到其他地方,需要将它们推送(push)出去(或者,如果您的计算机可以充当服务器,则让您的计算机回答别人的git fetch
电话——但让我们不要谈论这个,至少现在不要!)。git fetch
和 git push
不是对称的。
git fetch
时,你的Git会调用他们的Git并从他们那里获取新的内容。你的Git将新的内容(提交和其他需要这些提交的内容)保存在你的存储库中,然后更新你的远程跟踪分支名称。这些名称与你自己的本地分支名称完全不同:你的origin/master
与你的master
不同,你的origin/role
也与你的role
不同。你的origin/*
分支名称唯一的作用就是记住你的Git在他们的Git上看到了什么,所以每当你的Git在他们的Git上看到新的内容时,改变它们是非常安全的。git push
时,你的Git会调用他们的Git,发送你的东西,然后请求他们更改他们的master
或role
。他们没有ddd/master
或ddd/role
:你的Git要求他们更改他们自己的,唯一的master
或role
。如果他们在他们的master
或role
中有新的内容,而你尚未将其合并到你要推送的内容中,那么你将要求他们放弃这些新内容,取而代之使用你的内容。git rebase
实际上是如何工作的。这也是回顾其他问题“分支”确切意思是什么?的好时机。
Git主要关注提交。提交是Git的存在意义:它们是永恒不变的快照,记录了您提交的任何内容。没有一次提交可以被永久更改,尽管现有的提交可以被复制到新的(不同的)提交中,方法是提取旧的快照,进行更改 - 无论是什么更改 - 并在某个新位置创建新的快照。但是这里的“位置”是什么意思?这就是提交图表的作用。
每个提交都有一个唯一的ID。这是Git在各种情况下显示的大而丑陋的commit face0ff...
数字和字母组合。(实际上,每个Git对象都有一个这样的ID,但现在我们只关心提交对象。)
每个提交都保存了与其快照一起的所有内容,包括您通过git add
添加或保留的内容,您的名称、电子邮件地址、日志消息以及 - 这是关键项目 - 上一个提交的ID。
这意味着提交形成了(向后)链:
A <- B <- C <-- master
A <- B <- C <- D <-- master
A--B--C--D <-- master
\
E--F--G <-- role
role
分支上,一个——提交D
——仅在master
分支上,还有三个——A-B-C
链——在两个分支上。(这是Git的另一个奇怪之处:提交通常在许多分支上。)git rebase
时,通常是要移动提交,使其直接位于其他分支(新)尖端之后。例如,在这种特殊情况下,我们想将E-F-G
链移动到D
之后,而不是C
之后。但是提交不能更改,只能复制。
因此,这就是git rebase
所做的事情:它复制提交。我们将E-F-G
复制到新的提交E'-F'-G'
中,这些提交与E-F-G
非常相似,但它们在图形中的位置不同:它们位于D
之后。A--B--C--D <-- master
\ \
\ E'-F'-G' <-- role
\
E--F--G [previous role, now abandoned]
他们会说“不”!
如果他们将自己的role
设置为指向G'
,他们将会失去提交E-F-G
。现在,他们的Git找到G
的唯一方式是查看(他们的)名称role
,如果他们更改role
以指向G'
,他们将失去与G
的链接。
当然,这正是我们想让他们做的!但默认情况下,他们会说“不,如果我这样做,我将失去一些提交。”(这个默认值的原因很简单:他们不知道或不关心是我们给了他们G
,他们只知道,现在,他们将失去G
)。因此,我们必须将我们的Git的礼貌请求“请移动role
”改为更有力的命令:“移动role
!”
理想情况下,我们甚至可以说:“我们认为您的role
名称为G
,如果是这样,它应该改为名称G'
;但是请告诉我们如果我们对您的role
有误,好吗?”Git称此为--force-with-lease
。它不支持每个Git版本,并且如果您确定只有您更改其role
,则不需要它;但是需要某种强制操作,因为您需要让他们的Git放弃旧的(已复制)提交,就像您的Git一样。
git pull
git pull
命令旨在提供便利。每当你运行 git fetch
,通常可以从远程获取一堆新的提交,但这些新的提交都会出现在其远程跟踪分支下。一旦你拥有了这些提交,通常希望对它们进行一些操作。你可以使用两种主要方式来处理它们: git merge
或 git rebase
。因此,git pull
就是将 git fetch
与立即执行的 git merge
或 git rebase
结合起来。git pull
会让你提前决定如何处理它们。想象一下:“我要伸手进这个黑暗的壁橱里,拿出一瓶饮料,无论是什么,我都要喝掉。”如果你拿出一瓶啤酒,那很好;但如果你拿出一瓶漂白剂呢?git pull
,因为它只是git fetch
后跟第二个命令。 fetch
通过存储在远程名称下的URL调用另一个Git。无论是git merge
还是git rebase
,第二步都在本地工作。关于git pull
特别令人困惑的是,因为它先于远程跟踪分支名称的发明而存在,所以它有自己的特殊语法。这就是为什么即使您从origin获取,然后在origin/master
上进行变基,您也要写“pull(作为rebase)origin master”,而不是“pull(然后在)origin/master上进行变基”。git reflog
也无法找到它们;(2)git gc
决定,它们已经被遗弃并且足够老了,应该被垃圾回收。Git会定期自动运行git gc
来清理垃圾。很难预测这实际上发生的时间,但如果您看不到它们,那么保留它们也没有真正的危害-或者至少是这个理论。 - torekgit gc
和git fsck
仍然可以找到它们,因为这是它们的工作:扫描整个存储库,而不考虑对象可达性。两者之间的区别在于,git gc
会继续删除剩余的对象,而git fsck
会检查正在使用和已死亡的对象的有效性。两个命令都相当慢:如果您在大型存储库上手动运行它们,请准备等待。 - torek
git status
吗? - jonrsharpegit commit
,然后再执行git pull --rebase origin master
。接着将本地分支推送到远程仓库git push origin role
。这样做对吗? - ddd