关于linux:在git branch上工作

working on git branch

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

首先,我必须在分支机构工作的原因是我确实有一个"上游"回购,我需要不时地将其重新调整到我的master中。所以为了让我的插件远离上游,我需要在Git分支上工作。

更新2:

好啊。这比我现在想象的要复杂得多。我从源位置执行的方式是,git checkout -b newfeature,然后推到git push -u origin newfeature,这是在"上游"回购的基础上完成的,再加上我自己的master回购,按照

  • 更新Github fork并
  • 如何更新Github分叉存储库?

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

当我从第二个位置开始做git pull时,我得到了Already up-to-date。也就是说,我要处理的远程分支对我来说不可用。

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

If you want to create a local branch based on a remote-tracking branch (i.e. in order to actually work on it) you can do that with git branch –track or git checkout –track -b, which is similar but it also switches your working tree to the newly created local branch. For example, if you see in git branch -r that there’s a remote-tracking branch called origin/refactored that you want, you would use the command:

1
git checkout --track -b refactored origin/refactored

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

1
2
3
$ git branch -r
  origin/HEAD -> origin/master
  origin/master

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

1
2
3
4
5
6
7
$ git status .
On branch newfeature
nothing to commit, working directory clean

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

由于-r表示远程跟踪分支,所以我在第二个位置也得到了同样的结果。

更新3:

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

首先,我目前的坏消息来源:

1
2
3
4
5
6
7
$ git branch -r
  origin/HEAD -> origin/master
  origin/master

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

第二,它应该是什么:

1
2
3
4
5
6
7
8
9
$ 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相同,在两个站点:

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

最终更新:

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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中的说明。我能用那个小演示获得高于正确的结果。也就是说,我一直遵循的方向

  • 更新Github fork并
  • 如何更新Github分叉存储库?

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

最终更新结束

所以,让我问最后一个问题——是否可以纠正我的坏消息来源?

根据签出跟踪的远程分支,我认为问题出在我的源端,也就是说,我没有看到我的分支在跟踪的远程分支部分中列出。这是我的:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git remote show origin
* remote origin
  Fetch URL: [email protected]:me/myproj.git
  Push  URL: [email protected]: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操作时,我看不到这里列出的新功能。

更新:

我从我的第二个位置看到了newfeaturegit ls-remote中:

1
2
3
4
5
6
$ git ls-remote
From [email protected]:me/myproj.git
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        HEAD
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        refs/heads/master
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/heads/newfeature
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/tags/v1

但是,我不知道如何从第二个位置使用它:

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

git log没有显示我向Github发布的承诺。

也许我不该使用-b?嗯,我必须:

1
2
3
4
5
$ 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.


根据下面的评论,这是最后一个(我希望)拼图。我要求输出来自:好的。

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

这是一条单行线:好的。

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

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

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

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

1
git config --edit

这会在该存储库的git配置文件(通常是.git/config中)上打开编辑器。在这里,您将看到这三行:好的。

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

第三行应该是:好的。

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

也就是说,两次出现的master都应替换为*。好的。

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

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

(前面的加号告诉Git这些引用应该被复制,即使复制操作不是快速转发的。对于远程跟踪分支,这是您想要的。)好的。

一旦确定了这一点,git fetch origin将接管所有的github分支,剩下的就是确保每个存储库中的newfeature都将origin/newfeature设置为其上游。在newfeaturemaster设置为其上游的存储库中,运行:好的。

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

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

新答案主要基于最新更新中的新问题(这可能真的应该是一个新问题)。这又是一个(新的)问题,因为否则我就不能直截了当地说出哪个部分是哪个:好的。

UPDATE:

Ok.

I see the newfeature in the git ls-remote from my second place:

Ok.

1
2
3
4
5
6
$ git ls-remote
From [email protected]:me/myproj.git
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        HEAD
55e1d6fd9048336c7f0b178fbbf78231ca28ff06        refs/heads/master
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/heads/newfeature
8c4266a6a98f498c129a2a9e806e00e6c6d196b1        refs/tags/v1

However, I don't know how to use it from my second place:

Ok.

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

and git log is not showing the commits I've published to github.

Ok.

Maybe I shouldn't have used the -b?

Ok.

事实上,这就是(新)问题的根源。好的。

由于第二行和第三行的输出,我们可以看出:好的。

埃多克斯1〔17〕埃多克斯1〔18〕好的。

我在这里添加了三种不同的强调(斜体、粗体和粗体斜体),以便我可以讨论三个不同的点。好的。

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

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

命令git checkout -b newbranch告诉git创建一个新的本地分支newbranch,没有上游设置。添加--track可以修改命令,让git创建带有一些上游集的newbranch,但是git集的上游与当前分支无关。好的。

使用git checkout --track newbranch,不使用-b,会有很大的不同;使用git checkout newbranch,既不使用--track,也不使用-b,会有第三种不同。我们是如何来到这里的,这是另一种长期乏味的历史错误,但事实上,这通常是我们想要的第三种不同的东西。好的。

通常我们只使用git checkout somebranch切换到现有的somebranch分支。这很简单:我们现在可能在EDOCX1上(11),在开始工作之前,我们应该在EDOCX1上(12),所以我们EDOCX1上(13),从EDOCX1上(11)切换到EDOCX1上(12)。(但后来Git试图提供帮助,让我们先更改代码,然后切换到develop。这基本上是可行的,而且很有帮助,但是这会导致初学者的困惑:为什么Git现在允许我切换,但是如果我再做一次更改,它不会允许我切换?有关详细信息,请参阅git-在当前分支上有未提交的更改时签出另一个分支。)好的。

在另一个有帮助的尝试中,Git给git checkout添加了一个"按我的意思做"(dwim)选项,这样,如果你在没有newfeature的情况下写git checkout newfeature,它将为你创建newfeature,基于origin/newfeature的上游集合。(这过于简单化;见下文。)因此:好的。

1
$ git checkout newfeature

调用dwim代码("做我想说的,而不是我实际说的"):git猜测您打算使用命令:好的。

1
git checkout -b newfeature --track origin/newfeature

这是一个非常明确的请求:"根据origin/newfeature现在所指的承诺创建newfeature,并将origin/newfeature设置为newfeature的上游。好的。

也就是说,这通常都是为你做的。DWIM代码很聪明,但并不完美。为此,必须满足以下所有条件:好的。

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

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

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

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

如果我们现在在工作机器上,在存储库w中,我们已经设置了两个远程服务器githublaptop,我们可以运行git fetch github来联系github并从存储库g(它显示在git ls-remote输出中)中获取newfeature,并创建或更新远程跟踪分支github/newfeature。好的。

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

如果我们这样做,我们就击败了git checkout中的dwim代码,因为现在我们有两个可能的git checkout newfeature上游。好的。拥有多个遥控器和两个或更多可能的上游系统没有任何问题

这个设置,使用具有远程githublaptop的存储库w,是可以的。它只是破坏了DWIM代码。你可以写出你真正的意思,让Git做你说的,而不是依靠Git来猜测你想说什么:好的。

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

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

很高兴能只做一件事。要做到这一点,你必须小心你有多少个遥控器。只有一个普通的origin遥控器使这些便利功能发挥作用。当只有一个信息源时,情况也就更加清楚了,比如"最新版本总是GitHub上的任何内容"。好的。

缺点是你必须通过Github来回铲平所有东西。(通常都是正常工作的,但还记得Github倒下的那一天吗?)好的。吉特很困惑,因为…

维护git的人似乎喜欢将尽可能多的功能插入到一个命令中,比如git checkout,即使这样会导致奇怪和混乱的结果。注意,git checkout可以:好的。

  • 切换到现有分支
  • 切换到特定提交("分离头"模式)
  • 创建新分支
  • 创建新的"孤立"分支(尚未创建的分支)
  • 创建分支的reflog
  • 从提交中提取文件
  • 从索引/临时区域提取文件
  • 恢复合并冲突(从git add撤消合并解决)
  • 以交互方式修补工作树中的文件

这些都是相关的,但它们也与诸如移动分支(git reset甚至进行差异(git checkout --patch必须进行差异)之类的操作有关。那么,为什么它们都在一个单独的git checkout命令中呢?尤其是在"有时允许分支切换,有时不允许分支切换"这样的复杂情况下,git checkout otherbranch是非破坏性的,但git checkout otherbranch path/to/file具有高度破坏性。好的。下面的答案是针对原始问题,而不是更新。

根据您的评论回复,您正在寻找使用远程、远程跟踪分支和远程分支的方法。似乎这些东西应该是相似的,如果不是一样的话,不是吗?但它们都有很大的不同,我认为许多介绍也很难解释它们。其中一些无疑是历史原因造成的(Git的远程和远程跟踪分支机构是2008-2012年的新发明;它们在2013年中后期妥善安置)。如果您的Git版本至少是1.8.4,最好是2.0或更高版本,您可以忽略一些历史问题。(如果没有,请显示您的Git版本运行git --version-将有解决方法,或要设置的配置旋钮,或其他东西。)好的。

首先,一些定义:好的。

  • 远程只是一个名称,比如origin,在这个名称下,您的Git可以存储一些项目。最重要的一个是一个URL,命名从何处推送和获取。
  • 一个分支是不明确的(看看我们所说的"分支"到底是什么意思?).好的。

    分支名称是类似于masternewfeature的名称;它包含(单个)git commit的ID。常规(本地)分支名称是更通用的Git引用的特定形式。引用有前缀:本地分支的前缀都是refs/heads/,所以master实际上是refs/heads/master,等等。好的。

    有关"分支"的其他含义,请参见相关问题。注意,分支名称会自动更新:在该分支上进行新的提交会导致分支名称指向新的提交。这就是树枝生长的机制。好的。

  • 远程跟踪分支是一个引用,至少在内部是从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会发送commit a1234567,加上其他必要的,让他们设置name指向a1234567。(你的Git和他们的Git在推送开始时就讨论了哪些对象是必需的。注意,你的Git,他们的Git,实际上世界上的每一个Git,总是在每个提交的ID上达成一致!这是编写分布式VCS时比较棘手的部分之一。)好的。

通常,您将使用自己的分支名称之一,在这种情况下,您可以省略:theirname部分,您的Git将要求他们的Git将其分支设置为相同的名称。也就是说,你可以选择git push origin newfeature,你的Git会将你的分支机构newfeature的小费承诺,加上完成分支机构所需的任何额外承诺和文件发送给他们,然后礼貌地要求他们设置newbranch。好的。

通常,如果此设置是一个快进操作的更新,或者它创建了名称,或者为此删除了名称,则会遵循礼貌的请求。不过,接收Git有机会出于任何原因拒绝。(有关详细信息,请参阅其他SO日志。)如果推送在远程服务器上创建了一个分支,那么它也应该在您的存储库中创建一个新的远程跟踪分支,因为现在远程服务器上有一个新的(本地、远程)分支,您的Git应该跟踪它。如果远程上已经存在分支,并且接受了更新,那么您的Git应该更新远程跟踪分支。好的。

推送操作可以,但默认情况下不会设置本地分支的上游。更多信息请参见链接答案。好的。

一旦分支存在于远程服务器上,您就可以使用git push,从您更新它的任何地方(笔记本或工作或其他)将新的提交推送到远程服务器,然后使用git fetch,然后使用git mergegit rebase从远程服务器复制提交。如果您已经设置了一个上游,并且以其他方式正确配置了所有历史行李配置旋钮,那么您不需要对这些旋钮使用很多参数。(尽管您需要使用--force-with-lease--force-f或refspecs中的+加符号前缀语法来强制推送不是快速前进操作的更新。)好的。

请注意,您可以有多个遥控器。如果您将笔记本电脑设置为工作机器的远程设备,反之亦然,则可以在这些机器在网络上彼此连接时直接在它们之间传输提交(前提是您可以通过Linux设备进行ssh或类似访问,这通常非常容易)。换句话说,您不必经过Github或其他集中的位置(尽管您仍然可以在任何方便的时候这样做)。好的。

在Git的情况下,他们是非常独立的。在Mercurial中,存储库被强制紧密地连接在一起,因为分支名称是全局的,这与Git的标记是全局的方式非常相似。好的。

其他可以"同时看到两个"的方法是git ls-remotegit remote show,但这两种方法都是严格只读的。fetch步骤写入存储库,push步骤写入存储库。好的。好啊。


试试这个

1
git push --set-upstream origin BRANCHNAME