【问题标题】:working on git branch在 git 分支上工作
【发布时间】:2016-10-14 09:22:42
【问题描述】:

我已经做了很多阅读,但仍然不太清楚如何在不同地方的 git 分支上工作。怎么做?

首先,我必须在分支机构工作的原因是我确实有一个“上游”存储库,我需要不时将其重新设置为我的master。所以为了让我的插件从上游保持干净,我需要在一个 git 分支上工作。

更新 2:

好的。这比我现在想的要复杂得多。我从源位置做的方式是,git checkout -b newfeature 然后用git push -u origin newfeature 推送,这是在“上游”存储库以及我自己的master 存储库之上完成的,按照以下方向设置

问题是我想在这样的 git 分支上工作,就像在普通 git 中工作一样——即,当我执行某种git push 时,我希望从另一个执行某种git pull位置以获取最新更新。

当我从第二名开始做git pull 时,我得到了Already up-to-date。即,我想要处理的远程分支对我不可用。

PS。我发现的信息,来自 http://longair.net/blog/2009/04/16/git-fetch-and-merge/

如果你想基于远程跟踪分支创建一个本地分支(即为了实际工作),你可以使用 git branch –track 或 git checkout –track -b 来实现,这很相似,但它还将您的工作树切换到新创建的本地分支。例如,如果您在 git branch -r 中看到您想要一个名为 origin/refactored 的远程跟踪分支,您可以使用以下命令:

git checkout --track -b refactored origin/refactored

但是,这是我从源位置的git branch -r 得到的。

$ git branch -r
  origin/HEAD -> origin/master
  origin/master

也就是说,没有名为 origin/something 的远程跟踪分支,但我显然在一个分支中工作:

$ git status . 
On branch newfeature
nothing to commit, working directory clean

$ git branch -vv
  master     55e1d6f [origin/master] Remove ...
* newfeature 8c4266a - [+] add ...

由于-r 表示远程跟踪分支,我也从第二位获得了git branch -r 相同的结果。

更新 3

最后,我可以确认问题出在我的源端,即没有列出远程跟踪分支。再次将它们并排列出。

首先,我目前的错误来源:

$ git branch -r
  origin/HEAD -> origin/master
  origin/master

$ git branch -vv
  master     55e1d6f [origin/master] Remove ...
* newfeature 8c4266a - [+] add ...

第二,应该是什么:

$ git branch -r
  origin/HEAD -> origin/master
  origin/master
  origin/newfeature

$ git branch -vv
  master     7b1fc0f [origin/master] Add readme
* newfeature 7b1fc0f [origin/newfeature] Add readme
                     ^^^^^^^^^^^^^^^^^^^

git config --get-all remote.origin.fetch 的输出在两个站点上是相同的,+refs/heads/master:refs/remotes/origin/master

$ git config --get-all remote.origin.fetch
+refs/heads/master:refs/remotes/origin/master

最终更新

感谢@torek 的不懈帮助,我终于把事情弄清楚了。以下是按照@torek 的指示修复.git/config 文件之后的最后步骤:

git checkout master
# then fix the `.git/config` file
git config --edit

$ git branch -vv
* master     55e1d6f [origin/master] Remove ...
  newfeature 8c4266a [origin/newfeature: gone] - [+] add ...
                                         ^^^^

$ git branch -r
  origin/HEAD -> origin/master
  origin/master
  upstream/master
# The "origin/newfeature" is missing

$ git checkout newfeature
Switched to branch 'newfeature'
Your branch is based on 'origin/newfeature', but the upstream is gone.
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  (use "git branch --unset-upstream" to fixup)

$ git branch --set-upstream-to origin/newfeature
error: the requested upstream branch 'origin/newfeature' does not exist
hint: 
hint: If you are planning on basing your work on an upstream
hint: branch that already exists at the remote, you may need to
hint: run "git fetch" to retrieve it.
hint: 
hint: If you are planning to push out a new local branch that
hint: will track its remote counterpart, you may want to use
hint: "git push -u" to set the upstream config as you push.

$ git push -u origin newfeature
Branch newfeature set up to track remote branch newfeature from origin.
Everything up-to-date

$ git branch -r
  origin/HEAD -> origin/master
  origin/master
  origin/newfeature
  upstream/master
# The "origin/newfeature" is now listed

$ git branch -vv
  master     55e1d6f [origin/master] Remove ...
* newfeature 8c4266a [origin/newfeature] - [+] add ...

# Horay!!!

所以回顾一下,首先要让事情正确,请按照http://www.gitguys.com/topics/adding-and-removing-remote-branches 中的说明进行操作。通过那个小演示,我能够获得正确的结果。即,我一直遵循的方向

可能是也可能不是原因。但是,如果您遇到类似情况,现在我们有办法解决它。

最终更新结束

那么,让我问最后一个问题——是否可以纠正我的错误来源?

根据
checkout tracked remote branch,我认为问题出在我的源端,即,我没有在跟踪的远程分支部分中看到我的分支。这是我的:

$ git remote show origin
* remote origin
  Fetch URL: git@github.com:me/myproj.git
  Push  URL: git@github.com:me/myproj.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local branches configured for 'git pull':
    master     merges with remote master
    newfeature merges with remote newfeature
  Local refs configured for 'git push':
    master     pushes to master     (up to date)
    newfeature pushes to newfeature (up to date)

当我从第二个位置执行git remote show origin 时,我没有看到那里列出的新功能。

更新:

我在第二位看到git ls-remote 中的newfeature

$ git ls-remote
From git@github.com:me/myproj.git
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        HEAD
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        refs/heads/master
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/heads/newfeature
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/tags/v1

但是,我不知道如何从我的第二个地方使用它:

$ git checkout --track -b newfeature
Branch newfeature set up to track local branch master.
Switched to a new branch 'newfeature'

git log 没有显示我已发布到 github 的提交。

也许我不应该使用-b?好吧,我必须:

$ git checkout --track newfeature
fatal: Missing branch name; try -b

$ git checkout newfeature
error: pathspec 'newfeature' did not match any file(s) known to git.

【问题讨论】:

  • 你所说的地方是什么意思?我看到了两种明显的可能性。也许您希望在您的笔记本电脑或其他任何设备上拥有两个不同的工作树。或者,也许您有时会随身携带一台笔记本电脑并想在分支newfeature 上工作,但在其他时候您在工作而不使用笔记本电脑并想继续在newfeature 上工作。
  • @torek,是的,你的第二种情况正是我的情况。
  • 简短回答,发布上次编辑:git fetch 应该在您的本地仓库中创建或更新远程跟踪分支,从 GitHub 上的仓库中的分支获得。然后它将显示在git branch -r 输出中,然后您可以git checkout newfeature 基于远程跟踪分支创建本地分支,自动设置新本地分支的上游;或者,如果您已经拥有newfeature,您可以通过git checkout newfeature 获取onto 它,然后git branch --set-upstream-to origin/newfeature 将远程跟踪分支设置为其上游。
  • 嗯,没有newfeature 远程跟踪分支 (git branch -r) 即使在 git fetchgit fetch origin 之后列出,即使 git ls-remote 表明他们(github)有吗?这意味着remote.origin.fetch 行丢失或损坏。通常origin 将此设置为+refs/heads/*:refs/remotes/origin/*,但如果它错误或缺失,则可以解释问题。如果您使用 git remote add 创建 origin 遥控器,可能会出现这种情况。

标签: linux git github version-control


【解决方案1】:

根据下面的评论,这是拼图的最后一部分(我希望如此)。我要求输出:

git config --get-all remote.origin.fetch

那是一行:

+refs/heads/master:refs/remotes/origin/master

此输出不是正常设置(尽管它是允许的)。正常设置是:

+refs/heads/*:refs/remotes/origin/*

我认为修复它的最简单方法是运行:

git config --edit

这会在此存储库的 Git 配置文件上打开您的编辑器(通常为 .git/config)。在那里你会看到这三行:

[remote "origin"]
    url = [whatever the URL is]
    fetch = +refs/heads/master:refs/remotes/origin/master

第三行应该是:

    fetch = +refs/heads/*:refs/remotes/origin/*

即,master 的两次出现都应替换为 *

这些fetch = 行控制git fetch 的行为。每行提供一个refspec,它只不过是一对引用名称。现有的(功能失调的)refspec 说您的 Git 应该从 origin(在本例中为 GitHub)获取分支 master,并将其复制到您的远程跟踪分支 origin/master

更正后的 refspec 说你的 Git 应该从 origin 中选择 每个 分支 (*),并将每个分支复制到相应的远程跟踪分支 (origin/*)。

(前面的加号告诉 Git,即使复制操作不是快进,也应该复制这些引用。对于远程跟踪分支,这就是你想要的。)

一旦解决此问题,git fetch origin 将获取 所有 GitHub 分支,剩下的就是确保在您的每个存储库中 newfeature 具有 origin/newfeature设置为其上游。在newfeaturemaster 设置为其上游的存储库中,运行:

git checkout newfeature
git branch --set-upstream-to origin/newfeature

(在任何还没有newfeature 分支的存储库中,请参见下文。)


新答案主要基于最新更新中的新问题(这可能真的应该成为一个新问题)。这又是一个(新)问题,否则我无法弄清楚哪一部分是哪一部分:

更新:

我在第二位看到git ls-remote 中的newfeature

$ git ls-remote
From git@github.com:me/myproj.git
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        HEAD
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        refs/heads/master
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/heads/newfeature
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/tags/v1

但是,我不知道如何从我的第二个地方使用它:

$ git checkout --track -b newfeature
Branch newfeature set up to track local branch master.
Switched to a new branch 'newfeature'

git log 没有显示我已发布到 github 的提交。

也许我不应该使用-b

确实,这就是(新)问题的根源。

我们可以通过第二行和第三行输出来判断:

Branch newfeature set up to track <em>local</em> branch <strong><em>master</em></strong>.
Switched to a <strong>new</strong> branch 'newfeature'

我在这里添加了三种不同类型的强调(italicboldbold-italic)这样我就可以谈谈三个不同的点了。

首先,Git 告诉我们这是一个 分支。没关系:这就是我们想要的!我们想在这个存储库中创建一个新的(和本地)分支名称。

但我们不希望新的本地分支跟踪另一个本地 分支。 Git 我们告诉我们它正在跟踪(本地)分支 master。我们希望它跟踪一个远程跟踪分支,可能是origin/newfeature

git checkout -b <em>newbranch</em> 命令告诉 Git 创建一个新的本地分支 newbranch,没有设置上游。添加--track 会修改命令以告诉Git 创建带有一些上游集的newbranch,但Git 设置的上游是当前 分支。

使用git checkout --track <em>newbranch</em>,不使用-b,会做一些完全不同的事情;并使用git checkout <em>newbranch</em>neither --track nor -b,做了第三个不同的事情。我们是如何走到这一步的,是另一种长期无聊的历史错误,但实际上,这通常是我们想要的第三种不同的东西。

通常我们只使用git checkout somebranch 来切换到一些现有的分支somebranch。这很简单:我们现在可能在master,在我们开始工作之前我们应该在develop,所以我们git checkout develop并从master切换到develop。 (但随后 Git 试图提供帮助,让我们先开始更改代码,然后切换到 develop。这实际上很有效, 很有帮助,但它导致让初学者感到困惑:为什么 Git 让我 现在 让我切换,但如果我再做一次更改,它不会让我切换?详情请参阅 Git - checkout another branch when there are uncommitted changes on the current branch .)

为了提供帮助,Git 向git checkout 添加了一个“按我的意思做”(DWIM)选项,这样如果你写git checkout newfeature没有newfeature然而,它会为您创建 newfeature带有一个上游集,基于origin/newfeature。 (这过于简单了;见下文。)因此:

$ git checkout newfeature

调用 DWIM 代码(“做我想说的,而不是我实际说的”):Git 猜你 打算使用命令:

git checkout -b newfeature --track origin/newfeature

这是完整的请求:“创建newfeature,基于origin/newfeature 现在指向的提交,并将origin/newfeature 设置为newfeature 的上游。

也就是说,它通常会为你做这一切。 DWIM 代码很聪明,但并不完美。为此,必须满足以下条件:

  • 您的存储库至少有一个遥控器。它可以有多个遥控器,例如,您可以将githublaptop 作为您的两个遥控器(在本例中都不 被命名为originorigin 只是标准远程名称)。
  • 您的存储库至少有一个远程跟踪分支,该分支正在跟踪该远程上名为newfeature 的分支。在本例中,如果存在远程跟踪分支github/newfeature,则满足此要求。
  • 最后——当你有多个遥控器时,事情就会变得一团糟——你的存储库必须只有一个这样的远程跟踪分支。在这种情况下,如果github/newfeature laptop/newfeature 都存在,则 DWIM 代码将失败!

确保只有一个远程跟踪分支存在

目前尚不清楚origin/newfeature 是否真的作为远程跟踪分支存在于您当前的存储库中。

请记住,每个 Git 存储库都完全独立于其他所有 Git 存储库。这意味着 GitHub 上的仓库 G 是否有 newfeature 并不能告诉我们笔记本电脑上的仓库 L 是否有 newefature 和/或 origin/newfeature。此外,知道其中任何一个并不能告诉我们工作机上的存储库 W 是否有任何一个。

如果我们现在在 Work-machine 上,在存储库 W 中,并且我们已经设置了两个遥控器 githublaptop,我们可以运行 git fetch github 联系 GitHub 并选择从存储库 G 中升级 newfeature(它显示在 git ls-remote 输出中)并创建或更新远程跟踪分支 github/newfeature

我们还可以运行git fetch laptop 联系笔记本电脑(假设笔记本电脑已打开并连接到网络并且可以访问)。如果笔记本电脑的存储库L中有newfeature,我们获取laptop/newfeature

如果我们这样做,我们将击败 git checkout 中的 DWIM 代码,因为现在我们有 两个 可能的 git checkout newfeature 上游。

拥有多个遥控器和两个或多个可能的上游没有什么问题

这个设置,仓库 W 有遥控器 githublaptop,很好。它只是破坏了 DWIM 代码。你可以写出你真正的意思,让 Git 照你说的做,而不是依靠 Git 来猜测你的意思 要说什么:

git checkout -b lapfeature --track laptop/newfeature
git checkout -b hubfeature --track github/newfeature

现在,在您的工作机 W 存储库中,本地分支 lapfeature 跟踪 laptop/newfeature,这是您在笔记本电脑上提交的代码,本地分支 hubfeature 跟踪 @987654416 @,这是您要推送到 github 的版本。 (这些也不必保持同步……但如果你让它们分开太远,你可能会让自己不开心。:-))

DWIM 代码虽然方便

很高兴能够git checkout newfeature。为此,您必须小心您拥有多少个遥控器。只有一个遥控器——通常的origin——使更多这些便利功能发挥作用。当只有一个真相来源时,它也更加更清楚,例如“最新版本总是在 GitHub 上”。

缺点是您必须通过 GitHub 来回铲除所有内容。 (它通常可以正常工作,但请记住the day GitHub went down?

Git 令人困惑,因为...

维护 Git 的人似乎喜欢将尽可能多的功能放入一个命令中,例如 git checkout,即使这会导致像这样奇怪和令人困惑的结果。注意git checkout 可以:

  • 切换到现有分支
  • 切换到特定提交(“分离 HEAD”模式)
  • 创建一个新分支
  • 创建一个新的“孤立”分支(尚未创建的分支)
  • 创建分支的引用日志
  • 从提交中提取文件
  • 从索引/暂存区中提取文件
  • 恢复合并冲突(从git add撤消合并解决方案)
  • 在工作树中以交互方式修补文件

这些都是相关的——但它们也与移动分支 (git reset) 甚至制作差异 (git checkout --patch 必须制作差异) 等操作相关。那么为什么它们都在一个git checkout 命令中呢?尤其是当这导致复杂的情况,例如“有时允许分支切换,有时不允许,git checkout otherbranch 是非破坏性的,但 git checkout otherbranch path/to/file 是高度破坏性的”。


下面的答案是针对原始问题,而不是更新。

根据您的comment reply,您正在寻找使用远程远程跟踪分支远程分支的方法。似乎这些应该是相似的东西,如果不一样,不是吗?但是它们都有很大的不同,而且我认为许多介绍对它们的解释也很差。其中一些毫无疑问是由于历史原因(Git 的遥控器和远程跟踪分支是 2008-2012 年的新发明;它们在 2013 年中后期得到了妥善解决)。如果你的 Git 版本至少是 1.8.4,最好是 2.0 或更高,你可以忽略一些历史问题。 (如果没有,请显示您的 Git 版本 - 运行 git --version - 会有变通方法,或需要设置的配置旋钮等。)

首先,一些定义:

  • remote 只是一个名称,例如 origin,您的 Git 可以在该名称下存储一些项目。最重要的是一个 URL,用于命名推送和获取的位置。
  • 分支不明确(参见What exactly do we mean by "branch"?)。

    分支名称是像 masternewfeature 这样的名称;它包含(单个)Git 提交的 ID。常规(本地)分支名称是更通用的 Git reference 的特定形式。引用有前缀:本地分支都以refs/heads/为前缀,所以master真的是refs/heads/master,以此类推。

    有关“分支”的其他含义,请参阅链接问题。请注意,分支 name 会自动更新:在该分支上进行新提交会导致分支名称指向新提交。这就是分支生长的机制。

  • 远程跟踪分支是至少在内部以refs/remotes/ 开头的引用。这些引用通过远程的名称进一步限定,因此origin 的所有远程跟踪分支都以refs/remotes/origin/ 开头。与常规分支名称一样,Git 通常会去掉前缀,只显示origin/masterorigin/newfeature

接下来,使用 Git——或者实际上是任何分布式版本控制系统;例如,Mercurial 也是如此——您必须偶尔记住,有多个独立的1 存储库,它们并不总是同步的。在 Git 中,两个存储库之间的同步发生在 git fetchgit push 期间。这两个命令是您(和您的 Git)实际上可以同时查看两个不同存储库的要点2。我认为运行git ls-remote origin 很有教育意义,它从远程读取但不进行本地更改:您现在应该尝试一下,看看它会显示什么。

远程跟踪分支有一个重要用途:它在您自己的 Git 存储库中跟踪分支(常规的本地分支名称)指向的位置,以及您的 Git 上次同步的时间和他们的。当你运行 git fetch origin 时,你的 Git 会联系他们的 Git,下载所有必要的东西,然后更新你所有名为 origin/* 的远程跟踪分支,以匹配它刚刚在 origin 上看到的分支。

git push origin yourcommit:theirname 告诉您的 Git 调用他们的 Git,向他们发送所需的任何提交和其他对象,然后(礼貌地)要求他们将他们的分支 theirname 设置为指向您确定的特定提交yourcommit。也就是说,你可以git push origin HEAD:name 或者——假设你的HEAD 提交是a1234567——git push origin a1234567:name 并且你的Git 将发送提交a1234567,加上其他任何必要的东西,让他们设置name 指向a1234567。 (您的 Git 和他们的 Git 在推送开始时就需要哪些对象进行对话。请注意,您的 Git、他们的 Git 以及实际上世界上的每个 Git,总是在每次提交的 ID 上达成一致!这个是编写分布式 VCS 时比较棘手的部分之一。)

通常您会使用自己的分支之一名称,在这种情况下,您可以省略:theirname 部分,您的 Git 会要求他们的 Git 使用 同名。也就是说,你可能会git push origin newfeature,你的 Git 会向他们发送你的分支的提示提交 newfeature,以及完成分支所需的任何其他提交和文件——然后礼貌地请求他们设置他们的 newbranch .

一般来说,如果此设置是一个快进操作的更新,如果它创建名称,或 em>,就此而言,删除名称。不过,接收 Git 有机会以任何理由拒绝。 (有关详细信息,请参阅其他 SO 帖子。)如果推送 创建 在远程分支上,这也应该在您的存储库中创建一个新的远程跟踪分支,因为现在有一个新的(本地,到远程)分支,你的 Git 应该跟踪。如果远程分支已经存在,并且更新被接受,你的 Git 应该更新你的远程跟踪分支。

推送操作可以,但默认不设置本地分支的upstream。有关更多信息,请参阅链接的答案。

一旦分支存在于远程,您可以使用git push 从您更新它的任何地方(笔记本电脑或工作或其他)推送新的提交远程,然后git fetch通过git mergegit rebase 复制提交来自远程。如果您设置了上游,并且正确配置了所有历史行李配置旋钮,则无需对这些参数使用很多参数。 (尽管您需要在 refspecs 中使用 --force-with-lease--force / -f+ 加号前缀语法来强制推送非快进操作的更新。)

请注意,您可以拥有多个遥控器。如果您将笔记本电脑设置为工作机器的远程,反之亦然,只要它们在网络上相互连接,您就可以直接在这些机器之间传输提交(前提是您具有 ssh 或类似的访问权限——来自 Linux 机器,这是通常很容易)。换句话说,您没有必须通过 GitHub 或其他一些集中位置(尽管您仍然可以在方便的时候这样做)。


1在 Git 的情况下,它们是非常独立的。在 Mercurial 中,存储库被强制靠得更近,因为分支名称是全局的,就像 Git 的标签是全局的一样。

2可以“同时查看两者”的其他方式是git ls-remotegit remote show,但它们都是严格只读的。 fetch 步骤写入您的存储库,push 步骤写入他们的存储库。

【讨论】:

  • 确实,这么简单的任务有很多问题。我保证下次会问一个新问题,但在此之前,让我问最后一个问题,因为我终于知道要问什么问题了——是否可以纠正我的错误来源?请参阅我的 update3 了解详情。再次感谢您的辛勤帮助!
  • 重新更新 3:请运行 git config --get-all remote.origin.fetch 并包含其输出。可能有两件事需要解决。 PS:艰辛是错误的词;在这种情况下,我认为您的意思是 extensivecomprehensive(或者可能是 detailed)。它们是相似的,但 arduous 将用于生成帮助的过程,而不是用于帮助输出。 :-)
  • OK:+refs/heads/master:refs/remotes/origin/master 是问题的一部分。
  • 在两个地方以相同的方式修复它,使用您的编辑器和git config --edit,就像编辑后的答案一样。 master-only 设置意味着,一旦您开始从任何其他 repo 推送,当前工作的 repo 就会落后。
  • 天啊!!我不敢相信考验终于结束了!谢谢一千!感谢您的不懈帮助。是的,tireless,这也是我找到的更好的词(比 arduous)。 :-) 还有一些面包屑要拾取,但我设法自己解决了问题,并将在 OP 中记录它。再次感谢!
【解决方案2】:

试试这个

git push --set-upstream origin BRANCHNAME

【讨论】:

  • 欢迎加入@faety_sal,但不,问题不在于推动方面。我可以清楚地看到我的 newfeature 分支已成功推送到 github 上。
  • 虽然第二点,也许你是对的,但这里的文化是要清楚地解释这些建议背后的原因。啊..,不,我推的方式是git push -u origin newfeature,和你的一模一样。
猜你喜欢
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-25
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
  • 2019-10-26
相关资源
最近更新 更多