理解“git remote show”命令输出...“为‘git push’配置的本地引用”的含义是什么?

2024-06-22

我有两个遥控器和两个本地分支机构:

  • 本地分支“master”正在跟踪远程分支“origin/master”
  • 本地分支“mirror”正在跟踪远程分支“github/master”

这是在我的 .git/config 文件中:

...

[remote "origin"]
    url = http://my.gitlab.com/nandoquintana/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
[remote "github"]
    url = https://github.com/nandoquintana/repo.git
    fetch = +refs/heads/*:refs/remotes/github/*
[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "mirror"]
    remote = github
    merge = refs/heads/master
[push]
    default = tracking

这是“git Remote show origin”的输出:

$ git remote show origin 

* remote origin
  Fetch URL: http://my.gitlab.com/nandoquintana/repo.git
  Push  URL: http://my.gitlab.com/nandoquintana/repo.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

$ git remote show github

* remote github
  Fetch URL: https://github.com/nandoquintana/repo.git
  Push  URL: https://github.com/nandoquintana/repo.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    mirror merges with remote master
  Local ref configured for 'git push':
    master pushes to master (local out of date)

“推”和“拉”命令都可以正常工作:

  • “push”命令将本地分支中提交的编辑发送到“她的”远程分支。
  • “pull”命令将提交从远程分支带到“她的”本地分支。

那么,为什么“为‘git Push’配置的本地引用”是“主站推送到主站”?为什么不“镜子推主”? “本地过时”是什么意思?

UPDATED@torek 回答后:

这里我们有一些参考:

$ git ls-remote github
455063a9db09977535ac808af5729181b153f4c7    HEAD
455063a9db09977535ac808af5729181b153f4c7    refs/heads/master

$ cat .git/refs/heads/master
ca9e4399058a4998bd7c993f86d6740cfaec820b
$ cat .git/refs/heads/mirror
455063a9db09977535ac808af5729181b153f4c7
$ cat .git/refs/remotes/github/master
455063a9db09977535ac808af5729181b153f4c7

确切地说,“refs/remotes/github/master”和“refs/heads/master”不相等。这就是为什么出现“本地已过期”消息的原因:

master pushes to master (local out of date)

这对我来说不是问题,我确信“remotes/github/master”中的代码和本地“master”中的代码是不同的。

尽管如此,“remotes/github/master”和本地“mirror”中的代码是相同的。事实上,refs“refs/remotes/github/master”和“refs/heads/mirror”是相等的。

这是让我安心的消息:

mirror pushes to master (up to date)

我如何配置remote/github...或push.default...来获得此输出?


[给我自己和OP的一些提醒:远程origin= GitLab,远程github= GitHub。从根本上来说,使用的主要问题是git remote show是它让假设。这些假设与您将如何运行其他 Git 命令有关 -git fetch and git push——未来,以及每个 Git 命令涉及的第二个 Git 存储库未来将如何布局。显然,每一个古老的丹麦谚语 https://quoteinvestigator.com/2013/10/20/no-predict/: 做出预测是很困难的,尤其是对未来的预测。]

让我在这里解决顶部编辑过的问题:

这是让我安心的消息:

mirror pushes to master (up to date)

我如何配置remote/github...或push.default...来获得此输出?

有件事值得一试:push.default环境,upstream,告诉 Git 默认情况下,git push应该这样做。如果它有效并且达到了您想要的效果,那么您就万事大吉了。但请注意,无论 Git 在这里说什么,它都是谎言。

根本问题是mirror doesn't推到master. 直到您输入git push command,它根本不会推动任何东西;一旦你输入该命令,you控制where它去with that git push命令,它可以完全推翻任何声明git remote show made.

您的选择位于git push时间是:

  • 不提供额外的参数。

    在这种情况下,您的 Git 选择remote从当前的上游。如果上游设置为origin/...遥控器是origin。如果上游设置为github/...遥控器是github。它看起来像是一个简单的字符串替换(通常情况下确实如此,尽管由于历史原因,它实际上是一个非常复杂的字符串替换,usually事实证明很简单:取斜线之前的部分)。

    此时,您的 Git 将继续处理此处列出的第二种情况。

  • 提供一个附加参数。该参数指定要连接的其他 Git。它通常是一个remote (origin or github),不过此时您可以提供一个 URL,例如。

  • 提供两个或多个附加参数。其中第一个名称为远程(或者是 URL)。其余的是refspecs,如下定义。

此时,您的 Git 连接到该远程服务器,并且实际上运行git ls-remote看看他们有什么分支。该列表很重要,因为它与您提供的或未能提供的参考规格一起使用,具体取决于您的push.default设置,以及当您do给出一个 refspec,你可以只给出half参考规格。

“半个参考规范”的情况尤其成问题。不管你做了什么或设置了什么,如果你真的跑了git push github mirror当你在的时候mirror,你的 Git 会询问远程的 Gitgithub设置...好吧,这取决于您是否有上游设置,如果没有,您的push.default环境。详细信息在the git push文档 https://www.kernel.org/pub/software/scm/git/docs/git-push.html,采用 Git 通常的神秘形式。这default不过,默认值是“half refspec”,名称mirror means mirror:mirror.

如果您提供完整的参考规范,例如,git push github mirror:asdf,refspec 的后半部分确定您的 Git 要求其 Git 设置哪个分支名称。如果您给出一半的参考规范,则您给出的一半通常会成为两个名称。默认情况下push.default = simple,你不能意外地推动你的mirror to anyone else's master,您必须使用显式的完整引用规范(然后由您决定是否正确)。

如果你给norefspec,你的 Git 依靠push.default,并且只有五种设置。默认的,simple,让你的 Git 将你的分支集与他们的分支集进行比较(来自git ls-remote)。如果您的分支机构,例如mirror, doesn't那里有任何相应的分支,你的 Git 不会要求他们的 Git 设置any分支机构。

假设您在您的分支上mirror,其上游设置为github/master,并且您已配置push.default to upstream (using git config push.default upstream):

  • 如果你跑git push没有参数,或者git push github没有额外的参数,remotegithub.

  • 如果您不提供 refspec,则push.default设置适用:Git 将构建的 refspec 将是mirror:master.

  • 但是,如果您提供一半的 refspec,即使在多次重新阅读文档之后,我也不确定,什么fullGit 将构建 refspec。我think这将是mirror:mirror,这不是你想要的。

  • 您还可以配置一个remote.github.push提供默认参考规范的变量。这也可能让你得到你想要的东西,尽管push.default = upstream看起来更简单。

我们现在回到原来的答案。 :-)


那么,为什么“为‘git Push’配置的本地引用”是“主站推送到主站”?

这意味着:

  • 假设您当前的分支是master(即,你已经跑了git checkout master)
  • 如果你然后跑git push github (not git push github more-command-words)
  • Git——特别是your ownGit—将尝试推送您当前的master to https://github.com/nandoquintana/repo.git's master

这可能会成功,也可能不会成功,具体取决于 GitHub 上的 Git 服务器对设置的礼貌请求所做的操作its master到您的 Git 通过此推送请求发送的任何哈希 ID。

(如果您在master并运行git push origin,同样没有其他参数,除了名称origin指的是 GitLab 上的 Git。)

另一方面,假设您当前的分支名为mirror:

  • 所以你就跑了git checkout mirror
  • 现在你跑了git push github
  • 你的 Git 会——基于它现在看到的,因此假设这是它再次看到的——not尝试推动anything.

造成这种情况的原因很可能是您有push.default配置或默认为simple. When push.default被设定为simple, a git push没有refspec论证试图推动current分支,但是仅当另一个 Git 有同名分支时。所以如果 Git 在github(我吃https://github.com/...)仍然没有have一个名为mirror,你的 Git 会对自己说:呵呵。没有命名的分支mirror。最好不要推动任何东西。

(如果明天 GitHub 上的另一个 Gitdoes有一个名为mirror,你的 Git 会对自己说:啊哈!有一个分支叫mirror!好的,我会要求其他 Git 更新它的mirror.)

为什么不“镜子推主”?

因为事实并非如此。即使您重新配置push.default,没有默认设置意味着“如果我未能给出git push一份参考规格,制作一个不匹配的规格。”

关于参考规范的简短片段

所有这一切都基于一个概念refspec。在 Git 中,refspec 本质上是一对参考文献.

A 参考是“分支或标签名称”的花哨词。 (它可以不仅仅是这两个,但它们是主要的两个。)像这样的分支名称master是其完整拼写的简写,refs/heads/master. This 参考 name, refs/heads/master,是 Git 表达“不只是master,但是branch master“。一个简短的标签名称,例如v1.2是参考名称的简写refs/tags/v1.2。如果您省略refs/heads/ or refs/tags/部分,Git 通常通过查看您现在拥有的分支和标签来确定您指的是哪一个。

无论如何,一个refspec大多只是two这些带有冒号的东西:在中间:

refs/heads/master:refs/heads/master

例如。你需要其中两个,因为你正在使用两个 Git:一个在你的系统上,你要求它做某事,另一个在某些系统上remote, 例如gitlab or github。您让您的 Git 通过网络电话呼叫另一个 Git。然后你的 Git 和他们的 Git 互相对话,之后你的 Git 将fetch or push things.

获取和推送步骤需要每个 Git 的一个引用,因此这意味着您需要two参考文献:refspec。

refspec 的两半是source目的地。如果你正在跑步git fetch,源是otherGit,目的地是您自己的 Git。如果你正在跑步git push, you是来源;另一个 Git 成为目的地。但无论哪种情况,源都会向目标提供一些提交,然后源的name— refspec 的左半部分 — 用于更改目的地的某些内容name— 参考规格的右半部分。

For git fetch,两边有不同的名字是完全正常的。我们取自 their refs/heads/master and write to我们自己的refs/remotes/origin/master。我们从他们那里获取refs/heads/master并写给我们自己的refs/remotes/mirror/master。这让我们可以从许多不同的地方获取数据,但又保持它们完整。

For git push,不过,使用更正常same每边都有名字。我们从他们那里获取master,进入我们的refs/remotes/.../master。然后我们工作一段时间并确保里面有什么our master是在他们的基础上进行的更新master,例如通过合并或变基。然后我们再次打电话给他们,交付我们的新承诺,并要求他们设置他们的master——不是他们的nando/master,他们甚至没有,但他们master——基于他们之前的提交的最新提交。

我们确保它建立在他们的基础上,先获取,然后工作,然后推送。如果我们输掉了与 Sofia 的“比赛”——我们都在同一时间获取数据,但她工作得更快,然后她在我们之前推动——我们会得到“远程拒绝”“不快进”错误;我们必须再次获取,从 GitHub 或其他地方获取 Sofia 的工作,并使我们的工作构建在她的工作之上,然后再次尝试推送。

“本地过时”是什么意思?

当你的git remote show调出遥控器——具体来说github, i.e., https://github.com/nandoquintana/repo.git——通过网络电话,other吉特 说:

I have these references:
  refs/heads/master  <some big ugly hash ID>

(尝试运行git ls-remote github看看他们有什么,您将获得完整的列表)。

你自己的 Git 有一个名为master,但是又大又难看的哈希IDyourGit 有your refs/heads/master—your master分支——是不同的。

由于两者不同,您的 Git 会假设您要么“领先”(您有一些他们没有的提交),要么“落后”(他们有一些您没有的提交),或者两者都有。你的 Git 无法告诉你如何far落后于你,如果你落后的话,但它can通过查看您的所有提交来了解您“领先”多远。如果你有承诺129bca4f...谁的父母是e033fc12..., and they正在提交e033fc12...,那么您仅领先一次提交。

如果您的 Git 可以在您的 Git 中找到其 Git 的提交哈希 IDmaster分支的历史,你是“领先的”,你可能可以git push现在向他们发送您的新提交,要求他们设置他们的master to 129bca4f...,他们可能会接受提交并更新他们的master.

但如果他们已经承诺930ab988...你呢don't即使有该提交,您的 Git 所知道的只是他们有一些您没有的提交。你一定是“落后”的。你可以git fetch从他们那里获得他们拥有而你没有的所有承诺,并记住它们refs/remotes/github/master。然后你可以做任何需要做的事情add那些对你自己的承诺master,这样你就可以与他们持平——既不领先也不落后——并做任何额外的工作,这样你现在就可以ahead of them.

由您决定这是否是一个好主意,如果是,是否要这样做。全部git remote show就是打电话给他们,使用git ls-remote,通过网络电话,将他们的参考资料与您的参考资料进行比较,以猜测是什么git fetch and git push根据这些结果会做。 (如果您使用git pull,这仅仅意味着run git fetch,然后运行git merge. The git remote show命令也尝试猜测这会做什么。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

理解“git remote show”命令输出...“为‘git push’配置的本地引用”的含义是什么? 的相关文章

  • Visual Studio 代码中的“Git:gpg 未能签署数据”

    全新安装 Linux 后 我尝试设置我的环境 并且不断收到Git gpg failed to sign the data在本地提交更改时出错 我使用的是 Visual Studio Code 专有版本 而不是开源版本 gitconfig u
  • 将环境变量从 fastlane 传递到 Xcode 构建阶段脚本

    是否可以 如果可以 如何 将环境变量从运行 fastlane 的脚本传递到 Xcode 运行脚本阶段 我的最终目标是在运行脚本阶段读取当前的 git 分支名称 我们的 CI 由 Team Foundation Server 运行 它执行以下
  • 如何找出在哪个提交中添加了特定代码?

    我想知道我在哪个提交中添加了下面给出的代码 if getListView getChildCount 0 getActivity findViewById android R id empty setVisibility View VISI
  • git checkout 裸露,并在接收后包含子模块

    如何在包含子模块的接收后挂钩中检出服务器上的裸存储库 我目前将其作为接收后挂钩 bin bash http blog ekynoxe com 2011 10 22 git post receive for multiple remote b
  • dulwich - 从远程仓库身份验证克隆

    我找不到有关此主题的任何资源 我需要通过提供用户名和密码从私有存储库进行克隆 然而 当它们作为关键字参数提供给 dulwich get client from path 时 会出现错误 提示 未知参数 用户名 这似乎是一件简单的事情 但我找
  • git 列出所有可用命令

    有没有命令可以显示 GIT 中所有可用命令的列表 有git help但它显示 usage git version exec path
  • 如何从旧提交创建新的 Git 分支? [复制]

    这个问题在这里已经有答案了 可能重复 最近 不太明确的问题 使用 Git 从先前的提交分支 http stackoverflow com questions 2816715 branch from a previous commit usi
  • Github-pages:下载版本[重复]

    这个问题在这里已经有答案了 我有一个 GitHub 存储库 虽然我已经发布了该项目 但页面上没有出现相应的下载链接 我使用 gh pages 向导创建了此页面 有什么建议可以获取通常的 下载最新的 tarball zip 下载链接吗 您似乎
  • Egit 拒绝接受 id_rsa

    我是第一次尝试在 Eclipse 中设置 egit 的 git 用户 这样我就可以继续通过 Eclipse 轻松编码 问题是 每次我尝试通过 egit 克隆存储库时 都会出现错误 无法列出可用分支 原因 ssh 电子邮件受保护 cdn cg
  • 检查 GitHub 令牌的范围

    我想被动地检查 GitHub 安全令牌的权限 范围 而不将某些内容推送到存储库中 我尝试了以下命令 我替换了 your username 你的访问令牌和我的存储库的 URL 但它显示一个错误 curl 3 URL 使用错误 非法格式或缺少
  • AWS Codepipeline 是否会将符号链接传递到工件中的 Codebuild

    我的 github 存储库中有一些符号链接 当我有一个直接从 github 克隆的 Codebuild 项目时 符号链接会被保留 我进行了切换 以便 Codepipeline 监听我的更改devgithub 中的分支 并将工件传递给 cod
  • 如何快速查看哪个 Git 分支是最新的?

    例如 如果 git 上有 4 个分支 如下所示 branch1 branch2 current branch branch3 newest commits here master oldest 我的问题是 如何从 git 命令行检查我当前的
  • 在 ConEMU 中显示 git 分支

    有没有办法在 ConEmu 中以视觉方式 背景或类似 在 git 中显示分支 Git 分支可以在普通的 cmd 或 Far Manager 提示符中可见 所有魔法都是通过特殊的 ANSI 序列完成的 必须选中 Inject ConEmuHk
  • git lineends redux - Mac OS git 与 Windows 用户的贡献

    我在 Mac OS X 上进行开发 我有一个用户正在贡献带有 CRLF 行结尾的代码 他目前不使用 git 我创建一个分支 然后将我的工作树切换到它 我将他的文件复制到工作树中 当我尝试暂存文件时 收到错误fatal CRLF would
  • 如何在合并期间优先选择一个分支中的文件?

    前段时间我从我的项目中创建了一个分支master分支 我们就这样称呼它吧new feature 当我正在工作时new feature the master分支遵循其正常的演变 现在new feature已准备好合并到master我看到一些冲
  • 我可以通过 ssh 将 ssh 用户名与 git 的提交关联起来吗?

    我正在尝试通过 ssh 设置共享 git 存储库 将用户公钥复制到authorized keys 我真的希望 ssh key 中的 用户名 成为存储库中提交历史记录的一部分 这样用户 joe 就不能将他的名字设置为 kate 我们需要某种责
  • git 压缩并保留上次提交的时间戳

    考虑我有提交 A B C 如果我使用git rebase i将所有三个提交压缩为一个 我们可以 pick A squash B squash C 我看到结果提交A有其原始时间戳 如何让它继承提交的时间戳C 最后一个 我能想到的是git co
  • git 策略将一组提交限制在特定分支

    我需要经常在 dev 和 master 之间进行合并 我还有一个提交 我只需要应用于开发人员 以便在本地工作 早些时候 我只从 dev 合并到 master 所以我有一个分支 production changes 其中包含 dev 特殊提交
  • 如何撤消 git pull?

    由于远程源上不需要的提交 我想撤消 git pull 但我不知道必须重置回哪个版本 我怎样才能回到在远程源上执行 git pull 之前的状态 或者使其比其他答案更明确 git pull whoops git reset keep HEAD
  • Git:如何忽略/指定 *checkout* 文件

    如果我不想跟踪 html 文件 我可以将模式添加到 gitignore 它们将被忽略 我想知道如何做相反的事情 在结账时 我如何要求 git 仅签出某些类型的文件或不签出某些类型的文件 例如 如果我不需要 html 文件 我可以写 git

随机推荐