“下游”和“上游”的定义

我开始使用Git并遇到了“上游”和“下游”这两个术语。我以前见过这些,但从未完全理解它们。在SCM(软件配置管理工具)和源代码的上下文中,这些术语是什么意思?

350844 次浏览

就源代码控制而言,当您从存储库复制(克隆、签出等)时,您处于下游。信息“下游”流向您。

当你进行更改时,你通常希望将它们发送回“上游”,这样它们就会进入那个存储库,这样来自同一源的每个人都在处理相同的更改。这主要是一个社会问题,每个人如何协调他们的工作,而不是源代码控制的技术要求。你希望将你的更改发送到主项目中,这样你就不会跟踪不同的开发线。

有时你会读到包或发布经理(人员,而不是工具)谈论将更改提交到“上游”。这通常意味着他们必须调整原始来源,以便为他们的系统创建一个包。他们不想继续做这些更改,所以如果他们将它们“上游”发送到原始来源,他们应该不必在下一个版本中处理相同的问题。

这是一个非正式的术语。

就Git而言,其他所有存储库都只是一个远程存储库。

一般来说,上游是你克隆的源头。下游是任何将你的作品与其他作品集成在一起的项目。

这些术语不限于Git存储库。

例如,Ubuntu是Debian的衍生产品,因此Debian是Ubuntu的上游。

当你读到git tag时:

git的一个重要方面是它是分布式的,分布式在很大程度上意味着系统中没有固有的“上游”或“下游”。

,这仅仅意味着没有绝对上游存储库或下游存储库。
这些概念在两个仓库之间总是相对的,并且取决于数据流的方式:

如果“你的回购”已经声明“其他回购”为远程回购,那么

  • 你是从上游拉动的“其他回购”(“其他回购”是“上游你”,你是“下游进行其他回购”)。
  • 你是向上游推进(“其他回购”仍然是“上游”,信息现在回到那里)。

注意“from”和“for”:你不仅仅是“下游”,你是“下游从/为”,因此是相对的方面。


DVCS(分布式版本控制系统)的扭曲是:除了您自己的存储库相对于您声明的远程存储库之外,您不知道下游实际上是什么。

  • 你知道上游是什么(你正在拉取或推到的repos)
  • 你不知道下游是由什么组成的(其他repos从您的回购拉出或推到您的回购)。

基本上:

在“数据流”中,您的存储库位于来自上游存储库(“拉出”)并返回(相同或其他)上游存储库(“推送到”)的流的底部(“下游”)。


您可以在git-rebase中看到一个示例,其中包含“从上游重建中恢复”:

这意味着你是从发生rebase的“上游”存储库中提取,你(“下游”存储库)被结果卡住了(大量重复提交,因为分支重新基于上游重新创建了你在本地的同一分支的提交)。

这很糟糕,因为对于一个“上游”存储库,可能有许多个下游存储库(即从上游存储库中提取的存储库,具有rebase分支),所有这些都有可能处理重复提交。

同样,使用“数据流”类比,在DVCS中,一个错误的命令“上游”可能会在下游产生“连锁反应”。


注意:这并不限于数据。
它也适用于参数,因为git命令(如“瓷器”命令)经常在内部调用其他git命令(“管道”命令)。见rev-parse

许多git porcelainish命令混合了标志(即以破折号“-”开头的参数)和它们内部使用的底层git rev-list命令和git rev-list的参数。此命令用于区分它们。

上游(与之相关)跟踪

术语上游在GIT工具套件中也有一些明确的含义,特别是相对于跟踪

例如:

   $git rev-list --count --left-right "@{upstream}"...HEAD>4   12

将打印(最后缓存的值)当前工作分支后面(左)和前面(右)的提交数,相对于此本地分支的(如果有正在跟踪远程分支。否则它将打印一条错误消息:

    >error: No upstream branch found for ''
  • 如前所述,一个本地存储库可能有任意数量的远程存储,例如,如果您从github分叉一个存储库,然后发出“拉取请求”,您肯定至少有两个:origin(您在github上分叉的存储库)和upstream(您从github上分叉的存储库)。这些只是可互换的名称,只有“git@…”url标识它们。

你的.git/config阅读:

   [remote "origin"]fetch = +refs/heads/*:refs/remotes/origin/*url = git@github.com:myusername/reponame.git[remote "upstream"]fetch = +refs/heads/*:refs/remotes/upstream/*url = git@github.com:authorname/reponame.git
  • 另一方面,@@@@徐凯对GIT的意义是独一无二的:

它是'上述远程'上的'分支'(如果有的话),它正在跟踪您的'本地存储库'上的'当前分支'

每当你发出一个没有参数的普通git fetch/git pull时,它就是你获取/拉取的分支。

假设要将远程分支起源/主分支设置为您已签出的本地主分支的跟踪分支。只需发出:

   $ git branch --set-upstream  master origin/master> Branch master set up to track remote branch master from origin.

这在.git/config中添加了2个参数:

   [branch "master"]remote = originmerge = refs/heads/master

现在尝试(提供'上游'远程有一个'开发'分支)

   $ git branch --set-upstream  master upstream/dev> Branch master set up to track remote branch dev from upstream.

.git/config现在读取:

   [branch "master"]remote = upstreammerge = refs/heads/dev

git-push(1)

   -u--set-upstream

对于每个最新或成功推送的分支,添加上游(跟踪)引用,由无参数的git-ull(1)和其他命令使用。有关更多信息,请参阅git-config(1)中的branch.<name>.merge

git-config(1)

   branch.<name>.merge

branch.<name>.remote一起定义给定分支的上游分支。它告诉git Fedch/git Pull/git rebase要合并哪个分支,也可以影响git Push(参见push.default)。\(……)

   branch.<name>.remote

当在分支中时,它告诉git提取和git推送要从/推送到哪个远程。如果没有配置远程,它默认为原点。如果你不在任何分支上,也使用原点。

上游和推送(Gotcha)

看看git-config(1)

   git config --global push.default upstreamgit config --global push.default tracking  (deprecated)

这是为了防止意外推送到您尚未准备好推送的分支。

上游称为有害

唉,这里的其他答案没有得到“上游”的另一个用法,即指repo中提交的父子关系。Pro Git书中的Scott Chacon特别容易出现这种情况,结果很不幸。不要模仿这种说话方式。

例如,他说合并导致快进,这是因为

您合并的分支指向的提交直接被您正在提交的上游

他想说,提交B是提交A的唯一子级的唯一子级,所以要将B合并到A中,就足以将引用A移动到提交B。为什么这个方向应该被称为“上游”而不是“下游”,或者为什么这样一个纯直线图的几何形状应该被描述为“直接上游”,这是完全不清楚的,可能是武断的。(git-merge的手册页更好地解释了这种关系,它说“当前分支头是命名提交的祖先。”这是Chacon应该说的。)

事实上,当Chacon谈到重写已删除提交的所有子提交时,他自己后来似乎使用“下游”来表示完全相同的事情:

您必须重写6df76下游的所有提交才能完全删除这个文件来自您的Git历史记录

基本上,当提到随时间推移的提交历史时,他似乎不清楚他所说的“上游”和“下游”是什么意思。然后,这种用法是非正式的,不应该被鼓励,因为它只是令人困惑。

很明显,每个提交(除了一个)都至少有一个父级,因此父级的父级是祖先;而在另一个方向,提交有子级和后代。这是公认的术语,并且明确地描述了图的方向性,所以当你想描述在repo的图几何结构中提交如何相互关联时,这就是说话的方式。在这种情况下不要松散地使用“上游”或“下游”。

[补充说明:我一直在思考我上面引用的第一个Chacon句子和git-merge手册页之间的关系,在我看来,前者可能是基于对后者的误解。手册页确实继续描述了使用“上游”是合法的情况:快进通常发生在“你正在跟踪上游存储库,你没有提交任何本地更改,现在你想更新到一个更新的上游版本。”所以也许Chacon使用“上游”是因为他在手册页中看到了它。但是在手册页中有一个远程存储库;在Chacon引用的快速转发示例中没有远程存储库,只有几个本地创建的分支。]

使用河流的类比,我们可以跟踪我们的资源上游,直到我们找到源头(溪流或河流的源头)。

继续用河流类比,下游是河流中的水流动的方向。下坡。

所以,如果我某人的项目,我分叉的项目是上游。我的分叉是下游。

如果有人分叉了我的分叉项目,那么我的分叉相对于我的项目的分叉变得上游。

我的叉子的叉子变成了下游。

示例时间!

假设Project B分叉了Project AProject C分叉了Project B

然后,Project A是上游项目。

Project B是相对于Project A的下游项目。

Project B是相对于Project C的上游项目。

Project C是相对于Project B的下游项目。

生命的循环还在继续。

注:请注意,这是开源项目中相当常见的开发风格,用于创建项目的分支,修复bug或在该分支中添加功能,然后向原始项目提交补丁。

另请注意,从“质量运动”和统计过程控制中得到的一个明确教训是,从源头上解决质量问题的干预措施几乎总是比重复工作来解决可预防的问题更好的投资。所以请贡献补丁(发送Pull requests)。