简体   繁体   English

在仓库更新过程中如何解释git错误?

[英]How to interpret git error during repo update?

I am trying to update my Github repo. 我正在尝试更新我的Github存储库。

OS/config : Using OS X 10.10.5 (Yosemite) on MacBook Air 操作系统/配置 :在MacBook Air上使用OS X 10.10.5(Yosemite)

After doing these commands: 完成以下命令后:

$ git init
$ git add
$ git commit -m "added new stuff"
$ git remote add origin https://github.com/user/repo.git
$ git push -u origin master

I got this error: 我收到此错误:

To https://github.com/user/repo.git>
! [rejected]        master -> master (fetch first)
error: failed to push some refs to
'https://github.com/user/repo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Then I tried... 然后我尝试了...

$ git pull --commit https://github.com/user/repo.git

And I got... 我知道了

Merge https://github.com/user/repo
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Question

What do these errors mean in English? 这些错误在英语中是什么意思? And what should I do next? 接下来我该怎么办?

Is there a way to just "dump" whatever is in queue (without trying to "pull" it) so I can just get on with the new commits? 有没有一种方法可以仅“转储”队列中的所有内容(而无需尝试“拉出”),这样我就可以继续进行新的提交了? I am thoroughly confused about what to do next. 我对下一步该怎么办感到很困惑。

First, let me suggest that you read the Pro Git book , because most of the documentation that comes with git is pretty bad, especially for newbies. 首先,让我建议您阅读Pro Git书 ,因为git随附的大多数文档都非常糟糕,尤其是对于新手。 (It's improved from where it was 5+ years ago, but it still leaves much to be desired.) (与5年前相比有所改进,但仍然有很多不足之处。)

That said, let me try a quick introduction to "what you need to know" here. 就是说,让我在这里尝试快速介绍“您需要知道的内容”。

Introductory stuff 介绍性的东西

  1. When working with other people (including github which counts as "other people" here), you're having your git call up their git over the internet-phone and exhcange work. 当与其他人一起工作时(包括在这里被称为“其他人”的github),您的git会通过互联网电话调出他们的git并进行工作。 These other people are peers , ie, they have the exact same ability to do new work that you do, at least in the general case (github won't itself do new work all on its own). 这些其他人都是同龄人 ,也就是说,他们具有与您所做的新工作完全相同的能力,至少在一般情况下(github本身不会独自完成新工作)。 What this means is that during an exchange, you might have things "they" (whoever they are) don't but they might also have things you don't. 这意味着在交换期间,您可能拥有“他们”(无论他们是什么)所没有的东西,但是他们也可能拥有您所没有的东西。
  2. Git exchanges work with individual commits. Git与单个提交交换工作。 1 Exactly which commits, and how, gets a bit more complicated, so let's hold off on that for a moment. 1确切地说,哪个提交以及如何提交变得更加复杂,所以让我们暂缓一下。
  3. The opposite of git push is not git pull , it's actually git fetch . git push的反义不是git pull ,实际上是git fetch I think the error message you get should not refer directly to git pull ; 我认为您收到的错误消息不应直接引用git pull ; we'll see more on this in a bit as well. 我们也会对此进行详细介绍。
  4. Git keeps track of commits internally by their "true name" SHA-1 IDs, which are the long 40-character-hex things you see in git log output, for instance. Git通过其“真实名称” SHA-1 ID来在内部跟踪提交,例如,这是您在git log输出中看到的长40个字符的十六进制内容。 Every commit has some set of "parent" commits, identified by SHA-1 IDs. 每个提交都有一组由SHA-1 ID标识的“父”提交。 You could use SHA-1 IDs yourself, but they're extremely human-unfriendly, you'd never remember whether you should start with f13c9ab or 0e1d227 or whatever (and these are abbreviated IDs!). 您可以自己使用SHA-1 ID,但是它们对人类非常不友好,您永远不会记住应该以f13c9ab还是0e1d227或其他任何f13c9ab 0e1d227 (这些都是缩写 ID!)。
  5. So, git therefore provides you, the user, with branch names like master . 因此,git因此为用户提供了分支名称,例如master A branch name is simply a name that you tell git to use to keep track of the newest commit you've made on that branch. 分支名称只是您告诉git用来跟踪在该分支上所做的最新提交的名称。
  6. The newest commit has, as its parent, the commit that "used to be newest", which has an even older "newest" as its parent, and so on. 最新的提交具有作为其父级的“过去是最新的”提交,其父级具有甚至更老的“最新”的提交,依此类推。 (The way git achieves this is remarkably simple: when you make a new commit, its parent is "the current commit", and once the commit is safely stored in the repository, git replaces the ID stored in the branch with the ID of the new commit just made.) (git实现此目的的方法非常简单:当您进行新的提交时,其父节点为“当前提交”,并且一旦将提交安全地存储在存储库中,git就会用的ID替换分支中存储的ID。新的提交。)

Given the last three items, let's draw a commit graph fragment: 给定最后三项,让我们绘制一个提交图片段:

... <- 1f3a33c <- 98ab102   <-- branch

Here, the tip of the branch is commit 98ab102 and its parent is 1f3a33c . 在这里,分支的尖端是commit 98ab102 ,其父节点是1f3a33c We can say that the name branch "points to" 98ab102 , which points to its parent, and so on. 我们可以说名称branch “指向” 98ab102 ,它指向其父级,依此类推。

When you make a new repository ( git init , assuming this actually makes one 2 ) it's entirely empty of commits, so the first commit has no parent. 当您创建一个新的存储库( git init ,假设实际上是2 )时,它完全没有提交,因此第一个提交没有父级。 It's the second and third and so on commits that point back to previous commits. 它是第二个和第三个提交,以此类推,它指向以前的提交。

When you do a "merge", you tell git to take two (or more, 3 but let's just say two, for now) existing commits and make a new commit that has both of those as parents, by combining all the changes from some common point. 当您进行“合并”时,您告诉git接受两个(或三个,但现在仅说两个)现有的提交,并通过合并来自某些提交的所有更改来进行一个新的提交,将两者作为父提交共同点。 Merges are not that complicated, but they're something you should generally do after deliberately dividing up work into separate lines of development. 合并不是那么复杂,但是您通常应该在故意将工作划分为不同的开发线之后进行合并。

Now, back to fetch, push, and pull 现在,返回以获取,推动和拉动

You've created a new repository ( git init ), put in at least one commit ( git commit ), and added a "remote" ( git remote add origin ... ). 您已经创建了一个新的存储库( git init ),至少放入了一个提交( git commit ),并添加了一个“远程”( git remote add origin ... )。 This last step says "I have a peer git I want to call origin , so remember the URL under that name." 最后一步说:“我有一个对等git,我想称其为origin ,所以请记住该名称下的URL。”

Then, you asked your git to call up "origin" ( git push ... origin ) and give it your commits as found under your branch-name "master" ( git push ... master ). 然后,您要求您的git调用“ origin”( git push ... origin ),并根据您的分支名称“ master”( git push ... master )找到您提交的提交。 Here's where it gets a little bit tricky. 这是有点棘手的地方。 When your git talks to his git, what name should his git use? 当你的git的会谈,他混帐,应他的混帐使用什么名字? The short answer here is that his git will use the name master too. 简短的答案是, 他的 git也将使用master名称。 This is changeable, but changing it is not what you want here. 这是可变的,但是更改不是您想要的。

(You also asked, via the -u flag, to have your git record this exchange in your git configuration. We'll leave that aside for now.) (您还通过-u标志要求让git在您的git配置中记录此交换。我们暂时将其保留。)

When your git called up his git, your git said "here, look at these shiny new commits" (and he did), and then your git said: "Why not add these new commits exactly as they are to your repository, 4 and make your master point to the tip-most of those commits?" 当您的git调用自己的git时,您的git会说“在这里,查看这些闪亮的新提交”(然后他做了),然后您的git说道:“为什么不将这些新提交完全按原样添加到您的存储库中, 4和使您的master指向这些承诺中最重要的一个?” His answer was: "Well, I could do that, but then I'd lose some commits I have that you don't." 他的回答是:“嗯,我做到这一点,但我会失去一些提交没有。” This is where you see the rejected message. 在这里您可以看到被rejected消息。

Maybe you want them to forget their stuff-so-far. 也许您希望他们到目前为止忘记他们的东西。 If so, you can ask for a "force push", where you have your git tell them to set their master even if that "loses" some commits. 如果是这样,您可以要求“强制推送”,即使您的git“丢失”了某些提交,您也可以让他们的git告诉他们设置master It's still up to them whether to do this, but often it's not what you want. 是否执行此操作仍由他们决定,但通常不是您想要的。

Maybe you want to pick up what they have and add it to your collection, or pick up what they have and toss out your own work-so-far. 也许您想拿起他们拥有的东西并将其添加到您的收藏夹中,或者拿起他们拥有的东西并抛弃自己的工作。 This is where you want git fetch . 这是您要git fetch

What git fetch does, de-complicated as much as possible, 5 is call up the peer over the Internet-phone and find out what they have that you don't. 什么git fetch呢,去复杂尽可能,5是调用通过互联网,手机同行,并找出他们有什么, 不知道。 It brings over all these commits (remember, the exchanges go by commits) and adds them, Borg-like, to your repository. 它带来了所有这些提交(记住,交换是通过提交进行的),并将它们(类似于Borg)添加到您的存储库中。 Then—this is the crucial part—it changes their branch-names so that they won't interfere with your branch-names. 然后,这是至关重要的部分,它将更改分支名称,以便它们不会干扰您的分支名称。

The names that git fetch uses to synchronize with your peers are called "remote-tracking branches" or sometimes "remote branches". git fetch用于与您的同级同步的名称称为“远程跟踪分支”,有时也称为“远程分支”。 One odd thing about "remote branches" is that they're not actually on the remote! 关于“远程分支机构”的一件奇怪的事是它们实际上不在远程! They're kept in your own repository. 它们保存在您自己的存储库中。 The reason is simple: they're a snapshot of what was on the remote, the last time your git talked to that remote. 原因很简单:它们是git上次与该远程通话时的远程快照。 After the two gits hang up the Internet-phone, the remote could get changed. 在两个git挂断Internet电话后,可以更改遥控器。 (How fast a remote actually changes depends, of course, on how busy that remote git is.) (当然,远程实际更改的速度取决于远程git的繁忙程度。)

The renaming-pattern here is simple: take the remote's branch name (like master ) and add the name of the remote ( origin ) in front: your origin/master "tracks" origin 's master . 此处的重命名模式很简单:以遥控器的分支名称(如master )并在前面添加遥控器的名称( origin ):您的origin/master “跟踪” originmaster (There's a full-name form that you can use if you accidentally name one of your own purely-local, not-remote-tracking, branches origin/oops for instance, but your best bet is not to do that in the first place.) (有一种全名表格,如果您意外地命名了自己的纯本地,非远程跟踪分支或origin/oops分支的话,则可以使用,但最好的选择是一开始就不要这样做。 )

Wait, where does git pull come in? 等一下, git pull从哪里来?

Note that so far, it's been all git push and git fetch . 注意,到目前为止,都是git pushgit fetch But suppose you've done a git fetch and picked up their work? 但是,假设您已经完成了git fetch并完成了他们的工作? Now you have a bit of a problem: you have your work, and you have their work, and these two have diverged. 现在你有一个有点问题:你有你的工作,你有自己的工作,而这两个有分歧。

If you both started from a common base, we can draw your commit graph like this: 如果你们都是从一个共同的基础开始,我们可以这样绘制您的提交图:

... base <- yours   <-- HEAD -> master
         \
           theirs   <-- origin/master

I put in the HEAD -> this time to show which branch you're on (run git status and you should see "on branch master" in its output). 这次我放入HEAD ->以显示您所在的分支(运行git status ,您应该在其输出中看到“ on branch master”)。

One easy way to tie these two divergent bits of work together is to use git merge . 将这两个不同的工作联系在一起的一种简单方法是使用git merge If you want to do that, you simply run git merge origin/master (note the slash: you want your git to find your origin/master , which it picked up during git fetch , and merge that into your master , making a new commit on your master ). 如果你想这样做,你只要运行git merge origin/master (注意斜线:你希望你的git找到你的 origin/master ,它在拿起git fetch和合并到这一点你的master ,使一个新的提交在您的master )。 The result looks like this: 结果看起来像这样:

... base <- yours <- merge  <-- HEAD -> master
         \         /
           theirs      <-- origin/master

Another way to handle this—usually the better way, in fact—is to use git rebase , which I won't go into in detail here; 处理此问题的另一种方法(实际上通常是更好的方法)是使用git rebase ,我在这里不做详细介绍。 there are plenty of over StackOverflow answers about using rebase . 关于使用rebase ,有很多StackOverflow答案。 If you do, though, you wind up with: 但是,如果这样做,您将获得:

... base <- theirs <- yours   <-- HEAD -> master
                  \
                   .......... <-- origin/master

(Note that in all cases, origin/master still points to the tip-most "theirs" commit.) (请注意,在所有情况下, origin/master仍然指向最尖端的“其”提交。)

The main point to keep in mind right now is that whatever you do, if you want to get their git to accept your commits without having to force-push, you need to make your work be an add-on to theirs, so that your new commits "point back to" theirs. 现在要牢记的主要一点是,无论您做什么,如果想让他们的git接受您的提交而不必强行按下,则需要使您的工作成为他们的附加内容,以便您新的提交“指向”他们的。 It doesn't matter to the push process whether your work has theirs as a "second parent" of a merge commit, or simply builds directly on their commit(s); push过程并不重要,您的工作是将其作为合并提交的“第二父级”,还是直接在其提交上进行构建; it only needs to point to their commits, by their commit-IDs. 它只需要通过提交ID指向其提交即可。 (But again, rebase is usually better than merge!) (但同样,重新设置通常比合并好!)

So, git pull (finally!)... 所以, git pull (finally!)...

What git pull does, simplified, is just run git fetch and then git merge . 简化的git pull所做的只是运行git fetch然后git merge In short, it's meant as a convenience script: you're always fetching and then merging, so we'll give you a script that fetches, then merges. 简而言之,它是一个方便脚本:您总是先获取然后合并,因此我们将为您提供一个先获取然后合并的脚本。

Of course, git merge is usually wrong. 当然, git merge通常是错误的。 It really should use git rebase by default. 默认情况下,它确实应该使用git rebase

You can make git pull use git rebase , 6 but I think it's wiser, at least (or especially?) for newbies, to use the two separate steps—in part because if something goes wrong, the way you recover from this is different for the two different actions. 您可以使 git pull使用git rebase 6,但是我认为至少(或者特别是对新手)使用两个单独的步骤是明智的,部分原因是如果出现问题,从中恢复的方式会有所不同两种不同的动作。 To get out of a failing merge, you use git merge --abort . 要摆脱失败的合并,请使用git merge --abort To get out of a failing rebase, you use git rebase --abort . 要摆脱失败的rebase,可以使用git rebase --abort (These used to be even more different, now it's just "abort whatever's failing", which is a big improvement. But you need to know which to do, and that's an awful lot clearer if you started with git merge or git rebase .) (这些曾经更加不同,现在只是“中止一切失败”,这是一个很大的改进。但是您需要知道该怎么做,如果您从git mergegit rebase开始,这将变得非常清楚。)

The bottom line 底线

In the end, the action you need to take here depends on what you want to have happen, and what the remote will allow you to do. 最后,您需要在此处执行的操作取决于您要执行的操作以及遥控器允许您执行的操作。 If you want to drop their stuff, use git push -f (force), being aware that you're causing them (whoever they are) pain this way, and that they might forbid it entirely. 如果您想放下它们的东西,请使用git push -f (强制),要知道您正在以这种方式使他们(无论他们为谁)感到痛苦,并且他们可能会完全禁止这样做。 If you want to keep their stuff, use git fetch first, then keep their stuff however you prefer (merge, rebase, rework, whatever). 如果要保留它们的内容,请先使用git fetch ,然后按自己的意愿保留它们的内容(合并,变基,重做等)。


1 Or with patches, which you can exchange with your peers by email. 1或带有补丁,您可以通过电子邮件与同行交换。 It's also possible to "bundle" commits and transfer them by other methods. 也可以“捆绑”提交并通过其他方法转移它们。 But in this case we're doing commit-based exchanges over the Internet-phone. 但是在这种情况下,我们正在通过Internet电话进行基于提交的交换。

2 You can safely run git init in an existing repository. 2您可以在现有存储库中安全地运行git init It has a minor effect but for our purposes here it basically does nothing, hence the need to say "assuming it actually makes one". 它的作用很小,但就我们的目的而言,它基本上什么也没做,因此需要说“假设它确实能做到”。

3 Git calls this an "octopus" merge, even if there are just 3 or 4 parents instead of 8. 3 Git将此称为“章鱼”合并,即使只有3个或4个父级而不是8个。

4 Git mostly only ever adds "more stuff". 4 Git通常只会添加“更多内容”。 I like to refer to this as the "Git Borg" , where git adds your technological distinctiveness to its existing collection. 我喜欢将其称为“ Git Borg” ,其中git在其现有系列中增加了您的技术独特性。

5 A common theme in git is "That wasn't quite what you wanted? OK, we'll keep the existing stuff but make it more complicated so you can do what you want too!" 5 git的一个共同主题是“这是不太你想要什么?没关系,我们会保持现有的东西, 但要更复杂 ,所以你可以做想做什么呢!”

6 See footnote 5. 6见脚注5。

This SO answer suggests: 这样的答案表明:

git fetch --all
git reset --hard origin/master

But I haven't tried it yet, so I can't say for certain whether it solves the problem. 但是我还没有尝试过,所以不能确定它是否可以解决问题。 But it is, at least, one direction to try. 但这至少是一个尝试的方向。

GIT is telling you to fetch first. GIT告诉您先获取。 You can see in the log 您可以在日志中看到

$ git fetch -all

Probably somebody else has pushed to master already, and your commit is behind. 可能其他人已经推动精通,而您的承诺落伍了。 Therefore you have to fetch, merge the change set, and then you'll be able to push again. 因此,您必须获取,合并更改集,然后才能再次推送。

If it says there are changes in the remote make a Pull which will update your working directory. 如果显示遥控器上有更改,请执行“ Pull”操作,这将更新您的工作目录。

$ git pull

Then you push your changes to the remote 然后您将更改推送到遥控器

$ git push -u origin master

I hope this will help you push your changes to the master 我希望这会帮助您将更改推向大师

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM