需要澄清涉及 git 拉取和拉取请求的 git 工作流
Need clarity with git workflow involving git pull and pull requests
上图让我们很好地理解了 git pull 和 git pull --rebase。
我对这里的一件事感到困惑。让我详细说明-
1.案例 1 -> git pull --rebase origin master
命令后我的本地主分支 - A B C X Y D' E'
命令后我的远程主分支 - A B C X Y
如果我现在执行 git push origin master:master,我的远程主分支将看起来像 - A B C X Y D' E'
2。案例 2 -> git pull origin master
命令后我的本地主分支 - A B C D E F
命令后我的远程主分支 - A B C X Y
git push origin master:master 在这种情况下会如何表现?我无法理解为什么在任何情况下我们都想使用 git pull without --rebase?
我认为,您缺少的是 避免 git pull
的最佳解释。不过,让我们假设 git pull
有一个假设的 --merge
选项,这样我们就可以说你是 运行ning git pull --merge origin master
。 (您已经进行了合并;如果此选项是显式选项,则此选项将是默认选项。)也就是说,您的 git pull origin master
运行s 等同于:
git fetch origin
;然后
git merge -m "merge branch master of <url>" origin/master
.
生成图表,他们画成:
A--B--C--D--E--F <-- master
\ /
X----Y
(我这里把它转过来了。旋转90˚ccw匹配。)
我现在建议像这样重新绘制它:
D--E
/ \
A--B--C F <-- master
\ /
X--Y
现在我已经用这种方式绘制了图形,哪些提交在“分支”上master
?如果您选择 A-B-C-D-E-F
,为什么不也选择 X-Y
?如果你选择 A-B-C-X-Y-F
,你为什么不也选择 D-E
?
事实是所有八个提交,包括D-E
和 X-Y
,都是“on " 分支 master
。 名称 master
标识提交 F
,但提交 F
是一个 合并提交 。它返回到两个不同的提交:E
和 Y
。这两个不同的提交分别返回到 D
和 X
,而这两个不同的提交返回到一个共同的共享起点 C
.
提交 C
是两个 提示 提交的 合并基础,当时您有 Git 运行 git merge
,来自 git pull
。所以 Git 通过 运行 在提交的快照 C
和 E
。然后 Git 通过 C
和 Y
之间的差异 运行 找到了他们在 C
到 Y
腿上所做的事情。然后 Git 获取两个差异并 组合 它们,将组合结果应用到来自提交 C
的共享快照,并使用它来进行新的合并提交 F
.
合并提交 F
有一个快照,就像其他所有提交一样。它与其他提交的不同之处在于它有 两个 parent、E
和 Y
。所以你可以问 Git:*从 E
到 F
有什么变化,你会得到的是由于合并的下端(在我的绘图中)带来的变化;或者您可以询问 从 Y
到 F
发生了什么变化,您会看到由于合并的上端带来了哪些变化。
无论如何,这是合并的工作(和要点):合并工作,记录合并工作的事实。你现在可以清楚地看到发生了什么:你在他们工作的时候做了一些事情,他们在你工作的时候做了一些事情,然后你同时把它们结合起来。
使用变基使得历史“更干净”:看起来他们做了什么,你等他们完成,然后你开始你的任务,知道他们做了什么,做了你的工作并提交了它。那不是真的发生了什么,但也许它一样好。也许它 更好 因为对于未来的你、他们或任何人来说,它 更简单: 它不需要弄清楚在work-combining。但是,如果确实出了问题,它可能会隐藏某事的内容,使更糟未来 you/them/whoever.
这就是为什么你有选择的原因:一个可能比另一个更好,也可能不是。
[编辑:]git push
的作用
当你 运行:
git push origin master
或其等价物但 more-explicit 变体:
git push origin master:master
您的 Git 将:
- 使用名称
origin
为这个 git push
操作找到 URL(git config --get remote.origin.pushurl
;如果未设置,git config --get remote.origin.url
);
- 调出响应此 URL 的任何内容:那应该是另一个 Git 软件,连接到另一个存储库;
- 提议通过哈希 ID 向他们发送您最新的
master
提交;和
- 从那里开始。
我们先假设你使用了rebase,那么你最新的master
commit hash ID 就是commit E'
的hash ID。您的 Git 提议将此提交发送到他们的 Git。他们从未听说过这个哈希 ID,所以他们说 是的,请发送那个,并告诉我它的 parent(s)。然后你的 Git 告诉他们提交的哈希 ID D'
;他们也没有听说过那个,所以你的 Git 告诉他们 D'
s parent Y
。此时他们对你的Git说:啊,我已经提交了Y
,你现在可以停止发送东西了;打包我要求的提交所需的内容,知道我已经提交 Y
和每个较早的提交 .
或者,让我们暂时假设您使用了 git merge
。您的 Git 将提供发送提交 F
(通过哈希 ID)。他们的 Git 会对那个说 是 ,所以你的 Git 现在会主动发送 both parents, E
和Y
。他们会对Y
说不,谢谢,因为他们已经有了那个,但是是的,请对E
,所以你的Git 将提供 D
;他们也会同意那个,然后你的 Git 要么提供 C
,要么意识到他们有 C
因为他们有 Y
:如果你的 Git 确实提供了 C
他们会说他们不需要它,所以无论哪种方式,结果都是一样的(如果你的 Git 更聪明,效率会更高)。
既然您的 Git 知道要发送哪些提交,以及他们已经拥有哪些提交,您的 Git 可以合理地最小化 thin pack——这技术上取决于选择的推送协议,但现在每个人都应该使用“智能”协议——包含必要的提交和 objects,知道另一个 Git 存储库已经拥有所有 objects与他们已经拥有的所有提交一起使用。然后,您的 Git 将这个“精简包”发送给他们,如果一切顺利,他们会将其保存起来以供进一步使用。
最后,您的 Git 发送了一个礼貌的请求,格式如下:如果可以,请将您的分支名称 master
设置为 ________。让我知道它是否正常。 您的 Git 使用您自己的 master
的哈希 ID 填充空白。他们的 Git 然后检查新提交是否 添加 到他们自己的 master
分支,而不是从他们的 master
之前的任何提交中删除.
这两种情况——你要求他们添加 F
,或者你要求他们添加 E'
——继续添加,将他们现有的提交 Y
保留在他们的分支中,所以他们可能会接受您的礼貌请求。
请注意,他们永远不会知道或关心您使用什么分支名称来查找这些提交。他们只关心他们他们被要求设置什么分支名称,什么散列ID,以及涉及的各种提交。
上图让我们很好地理解了 git pull 和 git pull --rebase。 我对这里的一件事感到困惑。让我详细说明-
1.案例 1 -> git pull --rebase origin master
命令后我的本地主分支 - A B C X Y D' E'
命令后我的远程主分支 - A B C X Y
如果我现在执行 git push origin master:master,我的远程主分支将看起来像 - A B C X Y D' E'
2。案例 2 -> git pull origin master
命令后我的本地主分支 - A B C D E F
命令后我的远程主分支 - A B C X Y
git push origin master:master 在这种情况下会如何表现?我无法理解为什么在任何情况下我们都想使用 git pull without --rebase?
我认为,您缺少的是 避免 git pull
的最佳解释。不过,让我们假设 git pull
有一个假设的 --merge
选项,这样我们就可以说你是 运行ning git pull --merge origin master
。 (您已经进行了合并;如果此选项是显式选项,则此选项将是默认选项。)也就是说,您的 git pull origin master
运行s 等同于:
git fetch origin
;然后git merge -m "merge branch master of <url>" origin/master
.
生成图表,他们画成:
A--B--C--D--E--F <-- master
\ /
X----Y
(我这里把它转过来了。旋转90˚ccw匹配。)
我现在建议像这样重新绘制它:
D--E
/ \
A--B--C F <-- master
\ /
X--Y
现在我已经用这种方式绘制了图形,哪些提交在“分支”上master
?如果您选择 A-B-C-D-E-F
,为什么不也选择 X-Y
?如果你选择 A-B-C-X-Y-F
,你为什么不也选择 D-E
?
事实是所有八个提交,包括D-E
和 X-Y
,都是“on " 分支 master
。 名称 master
标识提交 F
,但提交 F
是一个 合并提交 。它返回到两个不同的提交:E
和 Y
。这两个不同的提交分别返回到 D
和 X
,而这两个不同的提交返回到一个共同的共享起点 C
.
提交 C
是两个 提示 提交的 合并基础,当时您有 Git 运行 git merge
,来自 git pull
。所以 Git 通过 运行 在提交的快照 C
和 E
。然后 Git 通过 C
和 Y
之间的差异 运行 找到了他们在 C
到 Y
腿上所做的事情。然后 Git 获取两个差异并 组合 它们,将组合结果应用到来自提交 C
的共享快照,并使用它来进行新的合并提交 F
.
合并提交 F
有一个快照,就像其他所有提交一样。它与其他提交的不同之处在于它有 两个 parent、E
和 Y
。所以你可以问 Git:*从 E
到 F
有什么变化,你会得到的是由于合并的下端(在我的绘图中)带来的变化;或者您可以询问 从 Y
到 F
发生了什么变化,您会看到由于合并的上端带来了哪些变化。
无论如何,这是合并的工作(和要点):合并工作,记录合并工作的事实。你现在可以清楚地看到发生了什么:你在他们工作的时候做了一些事情,他们在你工作的时候做了一些事情,然后你同时把它们结合起来。
使用变基使得历史“更干净”:看起来他们做了什么,你等他们完成,然后你开始你的任务,知道他们做了什么,做了你的工作并提交了它。那不是真的发生了什么,但也许它一样好。也许它 更好 因为对于未来的你、他们或任何人来说,它 更简单: 它不需要弄清楚在work-combining。但是,如果确实出了问题,它可能会隐藏某事的内容,使更糟未来 you/them/whoever.
这就是为什么你有选择的原因:一个可能比另一个更好,也可能不是。
[编辑:]git push
的作用
当你 运行:
git push origin master
或其等价物但 more-explicit 变体:
git push origin master:master
您的 Git 将:
- 使用名称
origin
为这个git push
操作找到 URL(git config --get remote.origin.pushurl
;如果未设置,git config --get remote.origin.url
); - 调出响应此 URL 的任何内容:那应该是另一个 Git 软件,连接到另一个存储库;
- 提议通过哈希 ID 向他们发送您最新的
master
提交;和 - 从那里开始。
我们先假设你使用了rebase,那么你最新的master
commit hash ID 就是commit E'
的hash ID。您的 Git 提议将此提交发送到他们的 Git。他们从未听说过这个哈希 ID,所以他们说 是的,请发送那个,并告诉我它的 parent(s)。然后你的 Git 告诉他们提交的哈希 ID D'
;他们也没有听说过那个,所以你的 Git 告诉他们 D'
s parent Y
。此时他们对你的Git说:啊,我已经提交了Y
,你现在可以停止发送东西了;打包我要求的提交所需的内容,知道我已经提交 Y
和每个较早的提交 .
或者,让我们暂时假设您使用了 git merge
。您的 Git 将提供发送提交 F
(通过哈希 ID)。他们的 Git 会对那个说 是 ,所以你的 Git 现在会主动发送 both parents, E
和Y
。他们会对Y
说不,谢谢,因为他们已经有了那个,但是是的,请对E
,所以你的Git 将提供 D
;他们也会同意那个,然后你的 Git 要么提供 C
,要么意识到他们有 C
因为他们有 Y
:如果你的 Git 确实提供了 C
他们会说他们不需要它,所以无论哪种方式,结果都是一样的(如果你的 Git 更聪明,效率会更高)。
既然您的 Git 知道要发送哪些提交,以及他们已经拥有哪些提交,您的 Git 可以合理地最小化 thin pack——这技术上取决于选择的推送协议,但现在每个人都应该使用“智能”协议——包含必要的提交和 objects,知道另一个 Git 存储库已经拥有所有 objects与他们已经拥有的所有提交一起使用。然后,您的 Git 将这个“精简包”发送给他们,如果一切顺利,他们会将其保存起来以供进一步使用。
最后,您的 Git 发送了一个礼貌的请求,格式如下:如果可以,请将您的分支名称 master
设置为 ________。让我知道它是否正常。 您的 Git 使用您自己的 master
的哈希 ID 填充空白。他们的 Git 然后检查新提交是否 添加 到他们自己的 master
分支,而不是从他们的 master
之前的任何提交中删除.
这两种情况——你要求他们添加 F
,或者你要求他们添加 E'
——继续添加,将他们现有的提交 Y
保留在他们的分支中,所以他们可能会接受您的礼貌请求。
请注意,他们永远不会知道或关心您使用什么分支名称来查找这些提交。他们只关心他们他们被要求设置什么分支名称,什么散列ID,以及涉及的各种提交。