我有一个关于git如何从远程拉取更改的问题,以及有多少历史记录。
我正在考虑为我的项目遵循gitFlow工作流。我们有80名开发人员,我们将把我们的更改从特性分支集成到开发分支--通过拉取请求首先执行代码审查。
我们将需要(本地)将我们的特性分支重新基于(顶部)develop,以便我们集成所有最新的develop更改。因此,我们将经常开发。在这里,我不想获取其他队友的功能分支--也不想获取他们的提交历史。
现在,如果我拉develop,这个操作是否会带来发生在其他功能分支下的提交历史,如果它们可以从develop访问(通过合并提交)?
提前感谢:-)
1.我们在本地使用了rebase,这样在develop分支上的pull请求是可以合并的。我们不使用合并,因为它可能会在执行代码审查时“污染”功能分支。如果pull请求被接受,我们将合并一个非快速提交。
1.我知道我可以“得到来源开发”。以下是我的问题:git pull origin develop会只“获取”蓝色提交还是绿色提交?见图git-pull-
2条答案
按热度按时间nbysray51#
我开始了一个完整的答案,但它太长了。
为了回答一些细节,你的担忧是真实的,但有点误导(不是你的错,因为Git文档很糟糕)。关键的问题不是
git fetch
获取了什么,1而是你与git merge
合并的提交的提交图中的内容;当你选择运行git rebase
时,哪些提交会被复制,这同样取决于commit graph,以及你提供给git rebase
的参数。关键的概念是“可达性”。像
origin/master
这样的名字(git fetch
更新)使提交可达,但提交(git fetch
带来的)也使其他提交可达。一个可达的提交使得整个提交链在那个提交之前都是可达的。合并提交,列出了多个父提交ID,使 * 两个 *(或更多)提交链可达。1当然,
git fetch
* 没有 * 获取的内容不可能被获取(在你的仓库副本中),因为它不存在(在你的仓库副本中)。我怀疑这就是你在这里的目标,但一般来说很难实现,而且无论如何都是不必要的。请记住:(1)每个提交都由它的SHA-1哈希ID标识,(2)每个提交都包含其父提交的哈希ID,(3)分支名称只是一个提交ID的名称。分支 name 会频繁地被填充一个新的ID,以扩展分支(添加一个常规或合并提交),或者指向由rebase复制的提交。
然后,记住
git rebase
通过 * 复制 * 提交来工作。这些副本具有新的不同ID:只要其他人没有名称(分支或标记名称)或指向任何原始提交
A
、B
或C
的提交,这就保证是好的。如果他们确实有这样的名字,那些现有的名字可能--也可能不--继续 * 指向原始的,而不是新的副本。* 即使这样也很好 * 只要你现在不使用它们。如果名称被更新为指向新提交,那么只要没有仍然可到达的提交指向旧提交,旧的提交就变得无关紧要了。如果现有的 commits 指向“过时的”commit,那么这些commit将永远指向它们,因为commit是永久性的。22没有Git对象可以改变。这是Git提供的一个基本保证。然而,所有Git对象,包括提交,所有完全不可访问的对象最终都会被删除。Git有一个“垃圾收集器”,
git gc
,它可以做到这一点。这有点复杂,因为有许多宽限期技巧来保持对象周围:默认情况下,所有内容都有14天的时间,并且引用(包括分支、标记和远程跟踪分支名称)可能有reflog条目,这使得否则无法访问的提交再次可访问。reflog条目本身默认保存30天或90天,这取决于 * 另一个 * 可达性计算,将引用中的当前哈希值与reflog条目中的哈希值进行比较。垃圾收集器通常会在Git认为这是个好主意时自动调用。在
fetch
上例如,假设你的
git fetch
将origin/BobsBranch
带入你的仓库,它指向一些提交:你可以随时调整你的工作。同时,Bob可以重定BobsBranch的基(尽管他可能需要将结果强制推送到服务器)。假设他完全抛弃了这三个提交,转而支持一个新的
B4
提交。你运行git fetch
,然后选择一个新的不同的origin/BobsBranch
;您的存储库现在具有:仅引用日志的提交不会出现在
git log --all
或gitk --all
视图中,只要你从不使用这些B*
提交,它们就不会以任何方式伤害你(好吧,它们会占用你的仓库中的一点空间)。为了避免将它们带过来 * 即使它们是无害的 *,您可以运行
git fetch
,并提供避免将它们带过来的说明。当你运行git pull
便捷命令时,git pull
运行git fetch
,并带有只带来 * 一个 *origin/*whatever*
分支的可到达提交的指令,这样通常就避免了带来它们--当然,除非它们可以从你的Git * 确实 * 需要的东西中获得,基于一个分支提示。在
merge
上当你合并的提交“到达”一个后来被变基复制的提交时,就会发生“坏”情况。例如,假设你有这个:
现在,您决定是时候将
origin/feature_X
的提交(A
和B
)合并到您的feature_Y
中了,所以您进行一次合并提交:如果其他人(上游)决定重定基并强制推送他们的
feature_X
,以便您的origin/feature_X
指向新的副本,您最终会得到以下结果:即使没有 name 附加到rebase复制的提交,如果你用 its name拾取了其他东西,也会发生这种情况。例如,如果其他人推送了
feature_F
并承诺完成:然后你合并它,你得到这个:
现在假设他们,或者第三个人,然后重新建立一个分支 * 他们 * 拥有的指向
B
的基础,而没有意识到/记住commitF
本身 * 也 * 指向B
。也就是说,* 他们 * 以这样的方式开始(注意他们没有你的feature_Y
):然后决定将
myhacks
重基到commitE
上会更好,所以他们运行:其产生:
最后当你取回来的时候(可能通过
git pull
)并获得他们的myhacks
最终版本-无论它当时是否有名称,只要它提交了A'
和B'
-您将获得(并保留)原始的A--B
提交,通过提交F
,并添加A'-B'
链,即使你可能从来没有见过他们的分支-namemyhacks
。总结
我们在上面看到的“坏”情况发生在
git fetch
通过名称(在您要提取的存储库中,可能是存储在中央服务器上的存储库)feature_F
引入提交F
时。(您和您的Git将其重命名为origin/feature_F
。)问题不是feature_F
(或origin/feature_F
)本身,而是myhacks
:一个你和中央服务器都没见过的名字!有这个名字的人--或者甚至可能是事后编造的--用它来 * 复制 * 提交A
和B
,而没有考虑谁有原始的。然后他推了副本,也许是在另一个名字下。名称在
fetch
和push
时很重要,因为git fetch
和git push
通过 refspecs 传输提交(大多数只是引用名称对,加上一些辅助内容)。然而,在这一点之前和之后,这些名字主要是分散注意力的:重要的是提交集(由它们的ID命名)以及它们的可达性状态。dnph8jn42#
git pull origin develop会只“获取”蓝色提交还是绿色提交?
Git 2.19(2018年第3季度)增加了两个改进,一个在客户端,一个在服务器端,当获取提交时(提醒,fetch由
git pull
调用)。这会影响“reachability”的实现方式,但不会解决torek提到的问题。
第一:
“
git fetch
“学习了一个新的选项“--negotiation-tip
“来限制它告诉另一端的提交集为“have”,以减少浪费的带宽和周期,当接收仓库有很多refs,而这些refs与它正在提取的远程历史没有什么关系时,这将是很有帮助的。参见commit 3390e42(2018年7月2日)。(由Junio C Hamano --
gitster
--合并至commit 30bf8d9,2018年8月2日)fetch-pack
:支持协商提示白名单在协商过程中,fetch-pack最终会将所有refs中的所有提交报告为“have”行。允许用户通过提供提示的白名单来限制以这种方式发送的提交;将仅发送提示本身及其祖先。
支持全局对象和单个对象。
只有支持connect或stateless-connect的协议(例如具有协议v2的HTTP)才支持此功能。
当仓库有多个相对独立的分支时(例如,当仓库与多个仓库交互时,如
linux-next
和torvalds/linux
),这将加速协商,并且用户知道哪个本地分支可能与他们正在获取的上游分支有共同的提交。其次,Git会一次获取更多的提交:
Git增加了一个服务器端旋钮来跳过指数/fibbonacci步幅的提交,试图用更少的迭代次数覆盖更宽的历史范围,可能接受更大的包文件传输,而不是在“git fetch”事务期间的共同祖先发现期间一次返回一个提交。
参见commit 42cc748(2018年7月16日),作者Jonathan Tan (
jhowtan
)。(由Junio C Hamano --gitster
--合并至commit 7c85ee6,2018年8月2日)协商者/跳过:在提取期间跳过提交
引入一个新的协商算法,在获取过程中使用,跳过提交,以更快地找到共同的祖先。
当提交遍历远离提示时,跳过的增长类似于斐波那契序列。跳过可能会导致包文件中包括不必要的提交,但协商步骤通常结束得更快。
该算法的使用被保护在配置标志
fetch.negotiationAlgorithm
后面。注:如Git 2所示。24,像
fetch.negotiationAlgorithm
这样的设置仍然是实验性的。参见commit aaf633c、commit c6cc4c5、commit ad0fb65、commit 31b1de6、commit b068d9a、commit 7211b9e(2019年8月13日)by Derrick Stolee (
derrickstolee
)。(由Junio C Hamano --
gitster
--合并至commit f4f8dfe,2019年9月9日)repo-settings
:创建feature.experimental
设置“
feature.experimental
”设置包括未提交为默认值的配置选项,但可以使用其他测试。更新以下配置设置以采用新的默认值,并使用
repo_settings
结构(如果尚未使用):在
fetch.negotiationAlgorithm
的情况下,现有逻辑仅在将要使用该设置时加载config选项,因此die()
语句对未知字符串值进行了描述。这被删除,因为现在配置在
prepare_repo_settings()
下解析。使用Git 2。24(2019年第4季度),引入了一种影响(相关)配置变量组默认设置的机制。
参见commit aaf633c、commit c6cc4c5、commit ad0fb65、commit 31b1de6、commit b068d9a、commit 7211b9e(2019年8月13日)by Derrick Stolee (
derrickstolee
)。(由Junio C Hamano --
gitster
--合并至commit f4f8dfe,2019年9月9日)repo-settings
:创造特色。实验装置签字人:德里克·斯托利
”的特点。“实验性”设置包括未提交为默认值的配置选项,但可以使用其他测试。
更新以下配置设置以采用新的默认值,并使用
repo_settings
结构(如果尚未使用):pack.useSparse=true
'fetch.negotiationAlgorithm=skipping
'在
fetch.negotiationAlgorithm
的情况下,现有的逻辑只会在将要使用该设置时加载config选项,因此在未知字符串值上有一个die()
语句。这被删除,因为现在配置在
prepare_repo_settings()
下解析。一般来说,这个
die()
很可能放错了地方,没有价值。已删除检查此die()
语句执行情况的测试。Git 2.29(2020年第4季度)更新了延迟克隆存储库中的按需获取代码。
参见commit db3c293(2020年9月2日)和commit 9dfa8db、commit 7ca3c0a、commit 5c3b801、commit abcb7ee、commit e5b9421、commit 2b713c2、commit cbe566a(2020年8月17日)。
(由Junio C Hamano --
gitster
--合并至commit b4100f3,2020年9月3日)negotiator/noop
:添加noop
获取协商器签字人:陈宗泽
添加**
noop
获取协商器**。引入此功能是为了允许部分克隆在使用“
git fetch
”(man)子进程获取丢失的对象时跳过不需要的协商步骤。(The生成“
git fetch
”(man)子进程的实现将在后续补丁中完成。)但这对最终用户也很有用,例如。例如作为对象损坏的钝修复。
git config
现在在其手册页中包括:fetch.negotiationAlgorithm
:控制在协商要由服务器发送的包文件的内容时,如何发送有关本地存储库中提交的信息。
设置为“
skipping
”以使用跳过提交以努力更快地收敛的算法,但可能导致大于必要的包文件;或设置为“
noop
“以根本不发送任何信息,这几乎肯定会导致包文件比必要的大,但会跳过协商步骤。在Git 2.32(2021年第2季度)中,“
git push
”(man)学习通过协议v2发现与接收端的共同祖先。参见commit 6db01a7(2021年4月8日)。
参见Jonathan Tan (
jhowtan
)的commit 477673d、commit 9c1e657(2021年5月4日)和commit 6871d0c、commit 57c3451、commit 8102570(2021年4月8日)。(由Junio C Hamano --
gitster
--合并于commit 644f4a2,2021年5月16日)fetch
:示教独立协商(无包文件)签字人:陈宗泽
目前,Git fetch中的packfile协商步骤不能独立于发送packfile来完成,即使至少有一个应用程序在其中这是有用的。
因此,可以独立完成此协商步骤。
随后的提交将使用此用于一个这样的应用-推送协商。
此功能仅适用于协议v2。
(An协议v0的实现将需要在获取、传输和传输助手代码中的单独实现。)
在协议中,独立协商的主要障碍是服务器可以单方面决定发送包文件。
这可以通过一个“等待完成”的论点来解决:然后,服务器将等待客户端说“完成”。
在实践中,客户永远不会说;相反,一旦满足请求,它将停止请求。
在客户端中,主要的变化在于传输和传输帮助器代码。
fetch_refs_via_pack()
执行所需的一切-协议版本和能力检查,以及协商本身。有2个代码路径不通过
fetch_refs_via_pack()
,需要单独排除:bundle transport(通过要求bundle transport不支持的smart_options,
排除)和不支持接管的transport helper。如果或者当我们支持协议v0的独立协商时,我们将需要修改这两个代码路径来支持它。
但现在,如果在这些情况下请求独立协商,则报告失败。
technical/protocol-v2
现在在其手册页中包括:如果'
wait-for-done
'特性被通告,则以下参数可以被包括在客户端的请求中。wait-for-done
向服务器表明它不应该发送“ready”,而应该等待客户端在发送packfile之前说“done”。
在Git 2之前。33(2021年第三季度),最近添加的代码在“
git push
”(man)期间支持公共祖先协商,但没有足够仔细地对其参数进行健全性检查。参见commit eff4045(2021年7月8日)和commit 60fadf8、commit 1e5b5ea(2021年6月30日)by Ævar Arnfjörð Bjarmason (
avar
)。(由Junio C Hamano --
gitster
--合并至commit b2fc822,2021年7月16日)fetch
:修复segfault in --negotiate-only without --negotiation-tip=*签字人:埃瓦尔·阿恩菲约德·比亚马逊
最近的
--negotiate-only
选项将在negotiate_using_fetch()
中对oid_array_for_each()
的调用中segfault,除非提供一个或多个--negotiation-tip=* 选项。针对该特性的所有其他测试合并了这两种情况,但是没有任何测试能够检查这个假设,让我们这样做并为它添加一个测试。
修复了9c1e657(“
fetch
:教学独立协商(无包文件)”,2021-05-04,Git v2。32.0-rc0 -- merge)。并且:
fetch
:记录--negotiate-only选项签字人:埃瓦尔·阿恩菲约德·比亚马逊
9c1e657中没有添加
--negotiate-only
选项的文档(“fetch
:教学独立协商(无包文件)”,2021-05-04,Git v2。32.0-rc 0--merge),仅提供相关推送的文档。在477673d(“send-pack
:支持推送协商”,2021-05-04,Git v2.32.0-rc0 -- merge)。让我们记录它,并更新我在--negotiation-tip=* 和'fetch之间添加的交叉链接。在5266082(“fetch doc:交叉链接两个新的谈判选项”,2018-08-01,Git v2。19.0-rc 0--merge列于batch #7中)。
我认为在这里说“与远程共同”比“。.. the server”,但是上面的--consultation-tip =* 的文档谈到了“the server”,所以让我们在这个相关的选项中继续这样做。
参见3390e42(“
fetch-pack
:支持谈判提示白名单”,2018-07-02,Git v2.19.0-rc0 -- merge)。git config
现在在其手册页中包括:另请参见
git fetch
的--negotiate-only
和--negotiation-tip
选项。fetch-options
现在在其手册页中包括:另请参阅
git config
中记录的fetch.negotiationAlgorithm
和push.negotiate
配置变量,以及下面的--negotiate-only
选项。--negotiate-only
不要从服务器获取任何东西,而是打印所提供的
--negotiation-tip=*
参数的祖先,这是我们与服务器共有的。在内部,它用于实现
push.negotiate
选项,请参阅git config
。在Git 2.34(2021年第4季度)中,最近在“
git push
”(man)代码路径中引入的共同祖先协商已得到修复。参见commit 8282311,commit 54a03bc,commit 74fab8f(2021年7月15日)by Jonathan Tan (
jhowtan
)。(由Junio C Hamano --
gitster
--合并到commit 066f6cd,2021年8月24日)fetch
:在无效的协商提示哈希上死亡签字人:陈宗泽
如果一个完整的十六进制散列被指定为
--negotiation-tip
togit fetch
“(man),并且该散列不对应于一个对象,则如果指定了--negotiate-only
,则“git fetch
“将segfault,否则将默默忽略该散列。使这些情况成为致命错误,就像给定无效的引用名称或缩写哈希一样。
Git 2.41(Q2 2023)修复了涉及
git fetch --negotiation-tip
的segfaulting循环。参见commit c5773dc(2023年2月11日),作者Eric Wong (
ele828
)。(由Junio C Hamano --
gitster
--合并到commit b0d2440,2023年3月19日)commit-reach
:避免NULL解引用签字人:黄耀威
can_all_from_reach_with_flag()
顶部的循环已经说明了from->objects[i].item' being
NULL, so it follows the cleanup loop should also account for a
NULL `` from_one '。我在这里使用
git fetch --negotiation-tip=... --negotiation-only
(man)成功地在我的一个巨大的、多远程的repos上进行了segfault,其中--negotiation-tip=
参数是一个glob,它(无意中)捕获了比我想要的更多的引用。我没有在一个独立的测试用例中重现这一点。