推送到git时出现非快进错误 [英] Non-fast-forward error when pushing to git

查看:245
本文介绍了推送到git时出现非快进错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当尝试推送到wordpress git repo时出现non-fast-forward错误,但是像错误消息中所说的那样拉动会给我一条消息,指示一切都是最新的.这是在拉,合并和提交之后.这是我的日志: http://pastebin.com/6M4qLqjG

简而言之,我尝试推动:

ajh$ git push staging master

我得到这个错误,告诉我先拉:

To git@git.wpengine.com:staging/gordo.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@git.wpengine.com:staging/gordo.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and 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.

但是如果我尝试拉扯,它将说它是最新的:

ajh$ git pull staging master
From git.wpengine.com:staging/gordo
 * branch            master     -> FETCH_HEAD
Already up-to-date.

这会循环,不知道发生了什么.有什么想法可以使我的repo和本地排队吗?我以前从未见过此non-fast-forward错误,不确定该怎么做.它还告诉我要结帐母版,但是我只是拉了一下并与母版合并,所以我不认为我应该再尝试一次.

=========使用fix进行编辑============ 这是一个pastebin,其中包含我用来正确推送内容的终端命令.我仍然可以使用关于到底发生了什么的解释.我可以重复这些步骤,但是我真的不明白为什么它们会起作用,而常规的推/拉却不起作用.

http://pastebin.com/u9DAiU5P

基本上,我创建了一个新分支,从master签出,它快速转发了我.在我必须执行git push staging staging的地方有些奇怪的事情,这上面的分支令人困惑

解决方案

我查看了您的第二个pastebin链接,发现很多困惑(这并不奇怪,因为git的术语似乎故意故意混淆了 ing )

我认为最好的选择是退后一步,首先看看git术语,并从pastebin中举一些例子.

让我们从远程"开始.

什么是遥控器?

远程只是一个名称,例如originstagingupstream,它为git(和您)提供对应git仓库的完整URL的简称.但是git利用了这个短名称,为您提供了远程跟踪分支",我们尚无法描述.首先,我们需要谈论分支".

什么是分支?

以下是粘贴框的一部分:

 1.      The-Dorfchester:gordo.dev ajh$ git checkout -b trouble
2.      M       .idea/workspace.xml
3.      M       wp-content/themes/goTheme2015/blog-loadMore.php
4.      M       wp-content/themes/goTheme2015/home.php
5.      M       wp-content/themes/goTheme2015/stylesheets/layout.css
6.      M       wp-content/themes/goTheme2015/stylesheets/layout.scss
7.      Switched to a new branch 'trouble'
8.      The-Dorfchester:gordo.dev ajh$ git push trouble
9.      warning: push.default is unset; ...
 

在第1行,您创建了一个新的分支名称trouble.

在git中,分支"一词至少具有两个不同的含义. 1 有分支名称,例如trouble,然后在存储在存储库中的提交图,形成了实际的分支.为了与分支名称​​ 区别开来,我们称它们为提交图片段".由于这些都是笨拙的术语,因此请注意,从技术上来讲,提交图是有向无环图或"DAG".因此,此图的一部分是"DAGlet". 2

DAGlet很重要,因为来自git的投诉:

 ! [rejected]        master -> master (non-fast-forward)

在您要求git进行将忘记" DAG的一部分(即丢失DAGlet")的推送时发生.我们待会儿会再讲.

分支与提交

我将假设您有一个合理的提交"概念,该概念在git中保存了您工作的完整快照,更准确地说,是索引"或临时区域"中任何内容的副本—以及提交消息,您的姓名和电子邮件以及进行提交的时间.不过,他们还有另外一件非常重要的事情,我们将在下一节中介绍.

现在让我们看一下2-7行.当您执行此git checkout -b trouble时,git指出它会将一堆未修改的文件保留为未修改的文件.

我知道您正在尝试执行git push,并且git push会推送 commits ,而不是文件.因此,如果您已修改但未提交的文件,则 不能提交那些未提交的更改.

(您没有在其中显示git status,但是git status确实是用于查看修改和未提交文件情况的最佳命令.它告诉您您在哪个分支现在(在这里是trouble,如果您的分支正在跟踪"另一个分支,那么分支的前和/或后是多远.不过,您的git checkout -b实际上为我们运行了git status.)

这意味着在某个时候,您可能应该运行git commit进行新的提交.当您执行进行新提交时,它会去哪里?

提交添加到分支

每当您进行新提交时,您的新提交都具有上面的另一件事":它具有父ID .对于大多数新提交,其父ID为当前提交".这会将新的提交链接回它之前的提交,我们可以将其绘制为一个小箭头:

A <- B <- C <- D

在这里,我们从最近一次(也是当前的)提交开始,我将其称为D. D存储其父提交C的ID; C存储其父级B的ID;和B存储其父级A的ID.

我们刚刚绘制了一个DAGlet:我们选择一个起始提交(在本例中为D),该提交使我们获得了一系列较早的提交.如果我们进行新提交(我们将其称为E),它将指向D:

A <- B <- C <- D <- E

我们有更长的DAGlet.

分支名称从何而来?

分支 name 使我们可以找到特定的提交.几乎所有的分支名称都是:它是提交的指针.如果您在分支master上并且进行了新的提交,则git首先查找当前的提交-它有一个丑陋的40个字符的SHA-1真名",有时您会看到的缩写版本就像b66c9f0一样,然后从暂存区域,您的姓名和电子邮件,您的提交消息以及此父ID进行一次新提交.然后-这是棘手的部分-git将 new 提交的SHA-1写入分支名称.

以这种方式,分支本身已经增长,并且分支 name 指向分支末尾的新"tip commit".如果它过去以D结尾,则现在您的D <- E的名称为master指向E而不是D.提交E现在是最顶端"的,您的分支(名称)指向E,整个链从E开始形成分支(DAGlet).这是之前和之后的:

[before]
A <- B <- C <- D   <-- master

[after]
A <- B <- C <- D <- E   <-- master

为什么这一切都重要?

当您进入git push某些提交时,您的git手将提交到另一个git的提交-监听远程存储的URL的git-然后要求该git设置它的分支到您要推送的最尖端的提交.

但是,假设您要求git将您的master(提交E)推到他们的一边,并使他们的master也指向E.但是,无论出于何种原因,它们的master现在都存在,但指向不同的提交:

A <- B <- C <- D <- F   <-- master (in their repo)
                 \
                   E   <-- (your proposed replacement)

如果他们的git在回购中将其master设置为指向提交E,则将使他们使用与您相同的DAGlet:E指向D,指向C,等等.提交F-他们拥有的,而您没有的-将丢失.

这是non-fast-forward的意思.这意味着它们的分支名称指向您在

推入的DAGlet中具有的提交. .该承诺指向一些父母,这些父母指向更多的父母,依此类推.最终(或什至立即)这些历史提交合并在一起,但是至少有一个您没有的提交,如果它们将分支名称指向您的DAGlet(其副本),则会丢失.

到目前为止的评论:

  • git push:这需要一个远程名称,即像originstaging这样的短名称,该名称提供用于推送的URL.这是push之后的第一个单词.任何附加词都是"refspecs",我们尚未定义,但现在让我们说它们由分支名称组成(多数情况下是正确的).您给git一个分支名称,如mastertrouble,它会尝试使用远程服务器上的另一个分支名称将该名称下的提交推送到远程服务器. (哪个分支名称在远程?好了,我们稍后会看到其他名称.)

  • 您推送的DAGlet应该简单地 extend 扩展其分支,并向其添加新的提交.从技术上讲,您要求他们将分支设置为的提交应该是他们已经拥有的尖端提交(这是没有实际推动"的情况),或者最终应该指向该提交.您可以添加一个或多个提交,但是在序列中的某个位置,您的一个新提交必须指向其现有的技巧提交.

  • 或者,您可以推送他们根本没有的分支名称.如果您在遥控器上创建该名称,则不会丢失任何提交.

侧边栏:push.default

让我们考虑第9行,warning: push.default is unset.此警告一直贯穿第28行.每次使用远程但没有其他refspec参数运行git push时,都会发出此警告.要关闭git,建议将push.default设置为simpleupstream.

您可以在每个存储库中执行一次此操作,或在您的个人全局配置(通常是在其中设置用户名和电子邮件)中进行设置:

$ git config --global push.default simple

例如.

如果您确实使用simple,则git会将您当前的分支(例如trouble)推送到远程,要求远程更新其 trouble.也就是说,这些按分支名称​​ simple进行的推送要求此处的两个不同git(您的系统上的您和他们的远程系统上的git)使用相同的分支名称.

这回答了您的git要求其git更新哪个分支名称"的问题:如果您推送分支trouble,您的git将要求其git更新名为trouble的分支.如果您的git正在推送您的master,它将要求他们的git更新其master.如果您未命名分支,则要推送的分支是您当前的分支,并且没有棘手的东西,例如在您的存储库中有一个拼写为 35. The-Dorfchester:gordo.dev ajh$ git push trouble trouble 36. fatal: 'trouble' does not appear to be a git repository 37. fatal: Could not read from remote repository.

git push命令将遥控器作为push之后的第一个单词.单词trouble被当作遥控器使用,不起作用(您没有名为trouble的遥控器). push代码充满了历史负担,因此之后尝试使用trouble作为URL,但这也不起作用.

(我将跳过git show-branch输出,因为某些内容已经弄乱了它,删除了前导空白,使其难以阅读.)

git checkout,这里出了什么问题

Git的checkout命令(在我看来)不必要地复杂,因为它具有太多的操作模式.如果git使用单独的命令切换到不同的分支"与在不更改当前分支的情况下从某个分支中检查特定文件"相比,将不会造成混淆.但是这些都集中在一个git checkout命令中,所以让我们看一下第75–79行:

 75.     The-Dorfchester:gordo.dev ajh$ git checkout staging master
76.     error: pathspec 'staging' did not match any file(s) known to git.
77.     error: pathspec 'master' did not match any file(s) known to git.
78.     The-Dorfchester:gordo.dev ajh$ git checkout staging
79.     error: pathspec 'staging' did not match any file(s) known to git.
 

更常见的结帐形式是git checkout branch-name,但是在这种情况下,您要调用其他git checkout,即git checkout [ branch-name ] [ -- ] path1 path2 ... pathN,但是可以省去--.由于staging不是有效的分支名称,因此将其解释为 path . (master 是有效的分支名称并不重要,因为staging处于git checkout允许分支名称的唯一参数位置.)

在第80行,您遇到了另一个错误:

 80.     The-Dorfchester:gordo.dev ajh$ git checkout master
81.     error: Your local changes to the following files would be overwritten by checkout:
82.             .idea/workspace.xml
83.             wp-content/themes/goTheme2015/blog-loadMore.php
84.             wp-content/themes/goTheme2015/home.php
85.             wp-content/themes/goTheme2015/stylesheets/layout.css
86.             wp-content/themes/goTheme2015/stylesheets/layout.scss
87.     Please, commit your changes or stash them before you can switch branches.
 

您当前(仍)在分支trouble上,并且您要求git移至分支master.要从一个分支移动到另一个分支,git必须替换工作树中某些文件的内容.哪些文件?

答案很复杂,但是在这种情况下,(至少)某些文件(例如.idea/workspace.xml)(1)存储在 current的最新提交中,会发生错误. em>分支; (2)同样在 new 分支的提示中进行提交; (3) new 分支中该文件的内容与当前提交中该文件的内容不同.

如果工作树中的文件与当前提交中的文件匹配,则git会感到安全,可以清除工作树版本并将其替换为切换到分支(在这种情况下为master)技巧提交版本.但是您的工作树中的这些文件与当前提交匹配.我们在运行git status的原始git checkout -b中看到了这一点.

因此,git拒绝更改分支,要求您提交更改的文件,或使用git stash提交它们(区别在于git stash no 分支上提交它们而不是当前分支.

好,所以您终于提交了它们

现在我们进入第89–91行:

 89.     The-Dorfchester:gordo.dev ajh$ git commit -am "idk"
90.     [trouble 820decb] idk
91.      5 files changed, 39 insertions(+), 93 deletions(-)
 

这在当前分支trouble上进行了新提交.然后,它将分支移动到指向新提交的位置,该提交的40个字符的SHA-1以820decb开头.

现在我们打第92行:

 92.     The-Dorfchester:gordo.dev ajh$ git push master
 

这要求您的git推送到名为master的远程服务器.没有一个错误,并且您会收到与先前相同的错误.所有这些还吐出了巨大的烦人设置您的push.default"消息,这使我们进入了第119行以及第125行:

 119.    The-Dorfchester:gordo.dev ajh$ git pull master
...
125.    The-Dorfchester:gordo.dev ajh$ git push --set-upstream master trouble
 

这两个都和以前有同样的问题:master字在一个远程名称的插槽中,但不是有效的远程.

这使我们进入第131行:

 131.    The-Dorfchester:gordo.dev ajh$ git push --set-upstream staging trouble
 

最后,一个命令git喜欢! :-)这次,staging在用于远程的插槽中,而trouble在用于"refspec"的插槽中,两者均起作用. (--set-upstream告诉git push,一旦推送成功,它应将stagingtrouble记录为本地staging的上游分支".参见此答案.)

让我们跳过另一次错误的结帐,然后继续执行第154行(及其伴随的成功消息):

 154.    The-Dorfchester:gordo.dev ajh$ git checkout master
155.    Switched to branch 'master'
156.    Your branch is behind 'staging/master' by 16 commits, and can be fast-forwarded.
157.      (use "git pull" to update your local branch)
 

这一作品.但这并不是因为成功的git push:这次成功了,因为您最终在trouble分支上提交了.这样,修改过的文件就安全地存储在存储库中,因为新提交的40个字符的真实名称" SHA-1 ID以820decb开头.

一旦提交它们,以使您的工作树干净,使用git checkout master git就可以了.您还将trouble推送到了名为"staging"的远程服务器上,并在其中也为其命名为trouble,但这对于git checkout master步骤并不重要.

第155行确认成功.第156行是git status的输出,告诉您master位于上游(您的git称为staging/master)落后16次提交-如果您没有,则有16次提交-并且不是领先于其上游.再次,请参阅我的其他答案(已在上方链接)以获取更多信息.

然后运行git pull,实际上是git fetch,然后是git merge(这是这两个步骤的便捷包装,但事实证明第二个是错误对于大多数人来说都是如此,因此它是可配置的). git merge进行了快进"合并,这意味着您没有新的提交,而他们也有新的提交,因此您的git能够将分支向前滑动"到新的分支尖端,并添加了新的DAGlet到您现有的DAG,完全没有大惊小怪.

这使我们一路到达388行(及其响应行):

 388.    The-Dorfchester:gordo.dev ajh$ git commit -am "pull from staging/master to master, idk"
389.    On branch master
390.    Your branch is up-to-date with 'staging/master'.
391.    nothing to commit, working directory clean
 

git commit命令找不到要提交的内容,也没有进行任何新的提交.您的分支master没有添加新的提交,并且分支提示与以前相同.

 392.    The-Dorfchester:gordo.dev ajh$ git push master
 

与以前相同的错误:git push首先需要一个远程名称.关于push.default的大声疾呼使我们一路走到:

 419.    The-Dorfchester:gordo.dev ajh$ git push staging master
 

这是正确的,但我们只是看到您的git commit之前未添加任何新提交.因此,您的git在staging上调用git并发现无事可做:

 420.    Everything up-to-date
 

它什么都不做(并且成功).

(顺便说一句,这里省略了有关push.default的内容,因为您为git push 提供了一个refspec.push.default设置是如果您不给出refspec,则应该执行push;即,如果您仅给出refspec,或者不给出任何内容,则如果您不给出git push,则它将指出基于当前分支的上游设置使用的遥控器.)


1 多少含义取决于您如何计算一些更精细的除法.有关更多信息,请参见此问题.

2 请注意,DAGlet是我自己的发明,因此,如果您开始使用它,则可能必须为您的听众定义它.

I'm getting a non-fast-forward error when trying to push to a wordpress git repo, but pulling like the error message says gives me a message that everything is up to date. This is right after a pull, merge, and commit. Here is my log: http://pastebin.com/6M4qLqjG

In short, I try to push:

ajh$ git push staging master

and I get this error, telling me to pull first:

To git@git.wpengine.com:staging/gordo.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@git.wpengine.com:staging/gordo.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and 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.

But if I try to pull, it will say it's up to date:

ajh$ git pull staging master
From git.wpengine.com:staging/gordo
 * branch            master     -> FETCH_HEAD
Already up-to-date.

And this will loop, don't know what is going on. Any ideas what I can do to git my repo and local lined up? I've never seen this non-fast-forward error before, not sure what to make of this. It is also telling me to checkout the master, but I just pulled and merged with master so I don't think I should try that again.

=========edit with fix============ Here is a pastebin with the terminal commands I used to get things pushed properly. I could still use explanation on what exactly is going on though. I can duplicate these steps but I don't really understand why they work and the regular push/pull didn't.

http://pastebin.com/u9DAiU5P

Basically I created a new branch, checked out from master, and it fast-forwarded me. Something weird going on where I have to push to do git push staging staging, the branches on this are confusing

解决方案

I looked at your second pastebin link and I see a lot of confusion (not surprising since git's terminology seems almost deliberately confusing).

I think the best bet here is to step back and take a look at git terminology first, with some examples from the pastebin.

Let's start with "remote".

What is a remote?

A remote is just a name, like origin or staging or upstream, that provides git (and you) a short name for the full URL of a counterpart git repository. But git takes advantage of this short name to give you "remote-tracking branches", which we can't describe yet. First we need to talk about "branches".

What is a branch?

Here's a bit from the pastebin:

1.      The-Dorfchester:gordo.dev ajh$ git checkout -b trouble
2.      M       .idea/workspace.xml
3.      M       wp-content/themes/goTheme2015/blog-loadMore.php
4.      M       wp-content/themes/goTheme2015/home.php
5.      M       wp-content/themes/goTheme2015/stylesheets/layout.css
6.      M       wp-content/themes/goTheme2015/stylesheets/layout.scss
7.      Switched to a new branch 'trouble'
8.      The-Dorfchester:gordo.dev ajh$ git push trouble
9.      warning: push.default is unset; ...

At line 1, you've created a new branch name, trouble.

In git, the word "branch" has at least two distinct meanings.1 There are branch names, like trouble, and then there are sequences in the graph of commits stored in the repository, which form actual branches. To distinguish these from branch names, let's call them "commit graph fragments". Since these are unwieldy terms, let's note that the commit graph is, technically speaking, a Directed Acyclic Graph or "DAG". A piece of this graph is therefore a "DAGlet".2

DAGlets matter because this complaint from git:

 ! [rejected]        master -> master (non-fast-forward)

happens when you're asking git to do a push that will "forget" part of a DAG, i.e., will "lose a DAGlet". We'll get back to this later.

Branches vs commits

I'm going to assume you have a reasonable notion of "a commit", which in git, saves a complete snapshot of your work—more precisely, a copy of whatever is in the "index" or "staging area"—along with a commit message, your name and email, and the time you make the commit. They have one more thing that's very important, though, which we'll get to in the next section.

Let's take a look at lines 2-7 now. When you did this git checkout -b trouble, git noted that it was retaining a bunch of modified-and-not-committed files as modified-and-not-committed.

I know you're trying to do a git push, and git push pushes commits, not files. So if you have modified but uncommitted files, those uncommitted changes cannot be pushed.

(You don't show a git status in there, but git status is really the best command to use to see what's going on in terms of modified-and-uncommitted files. It tells you what branch you're on now (which would be trouble here, and if your branch is "tracking" another branch, how far ahead and/or behind your branch is. Your git checkout -b effectively ran git status for us, though.)

What this means is that at some point, you probably should run git commit to make a new commit. When you do make a new commit, where does it go?

Commits add to a branch

Whenever you make a new commit, your new commit has that "one more thing" above: it has a parent ID. For most new commits, the parent ID is "the current commit". This links the new commit back to one before it, and we can draw that as a little arrow:

A <- B <- C <- D

Here, we start with the most recent (and current) commit, which I'm calling D. D stores the ID of its parent commit C; C stores the ID of its parent B; and B stores the ID of its parent A.

We've just drawn a DAGlet: we pick a starting commit (in this case, D), and that commit gets us a chain of older commits. If we make a new commit—let's call it E—it will point back to D:

A <- B <- C <- D <- E

and we have a longer DAGlet.

Where does the branch name come in?

A branch name lets us find a specific commit. That's almost all a branch name is: it's a pointer to a commit. If you're on branch master and you make a new commit, git starts by finding the current commit—it has a big ugly 40-character SHA-1 "true name", and sometimes you'll see an abbreviated version of this like b66c9f0—and making a new commit from the staging area, your name and email, your commit message, and this parent ID. Then—this is the tricky part—git writes the new commit's SHA-1 into the branch name.

In this way, the branch itself has grown, and the branch name points to the new "tip commit", at the end of the branch. If it used to end at D, you now have D <- E with the name master pointing to E instead of D. Commit E is now "tip-most", and your branch (name) points to E, with the whole chain starting at E forming the branch (DAGlet). Here's the before-and-after:

[before]
A <- B <- C <- D   <-- master

[after]
A <- B <- C <- D <- E   <-- master

Why does all this matter?

When you go to git push some commit(s), you have your git hand the commits to the other git—the git that listens to the URL stored under the remote—and then ask that git to set its branch to the tip-most commit you're pushing.

Suppose, though, that you ask your git to push your master (commit E) to their side and make their master point to E too. But—for whatever reason—their master exists now but points to a different commit:

A <- B <- C <- D <- F   <-- master (in their repo)
                 \
                   E   <-- (your proposed replacement)

If their git sets their master in their repo to point to commit E, you'll get them to use the same DAGlet you have: E pointing to D, pointing to C, and so on. Commit F—the commit they have, that you don't—will be lost.

This is what non-fast-forward means. It means they have their branch-name pointing to a commit that you don't have in whatever DAGlet you're pushing. That commit points back to some parents, which point to more parents, and so on. Eventually—or even immediately—those historical commits join up, but there's at least one commit they have that you don't, that would be lost if they make their branch-name point to (their copy of) your DAGlet.

Review so far:

  • git push: this needs a remote, i.e., a short name like origin or staging that provides the URL for pushing-to. That's the first word after push. Any additional words are "refspecs", which we haven't defined, but for now let's just say they're made up of branch-names (which is mostly true). You give git a branch name like master or trouble and it tries to push the commits you have under that name, to the remote, using another branch name on the remote. (Which branch name, on the remote? Well, we'll see something else on this in a moment.)

  • The DAGlet you push should simply extend their branch, adding new commits on to it. Technically speaking, the commit you ask them to set their branch to, should either be the tip commit they already have (this is a "no actual push" situation), or should eventually point back to that commit. You can add one commit or many, but somewhere in the sequence, one of your new commits has to point back to their existing tip commit.

  • Or, you can push a branch name that they don't have at all. If you create the name on the remote, there won't be any commits for it to lose.

Sidebar: push.default

Let's consider line 9, the warning: push.default is unset. This warning runs all the way through line 28. This warning comes out every time you run git push with a remote, but with no additional refspec arguments. To make git shut up, I recommend setting push.default, to either simple or upstream.

You can do this once per repository, or set it in your personal global configuration (where you normally set your user name and email):

$ git config --global push.default simple

for instance.

If you do use simple, git will push your current branch (e.g., trouble) to the remote, asking the remote to update its trouble. That is, these pushes work by branch names and simple demands that the two different gits here (yours, on your system, and theirs, on the remote system) use the same branch name.

This answers the question "which branch name does your git ask their git to update": if you're pushing branch trouble, your git will ask their git to update their branch named trouble. If your git is pushing your master, it will ask that their git update their master. The branch you'll push, if you don't name a branch, is your current branch, and there's no tricky stuff like having a branch in your repository that's spelled Raymond-Luxury-Yacht, but on the remote, it's spelled Throatwobbler-Mangrove.

That's pretty simple, and that is why this is called simple. There are four other options but I'll leave them out for this posting.

What went wrong here?

Consider lines 35–37:

35.     The-Dorfchester:gordo.dev ajh$ git push trouble trouble
36.     fatal: 'trouble' does not appear to be a git repository
37.     fatal: Could not read from remote repository.

The git push command takes a remote as its first word after push. The word trouble, treated as a remote, doesn't work (you don't have a remote named trouble). The push code is full of historical baggage so it tried to use trouble as a URL after that, and that didn't work either.

(I'm going to skip the git show-branch output as something has mangled it, deleting leading white space, making it too hard to read.)

git checkout, and what went wrong here

Git's checkout command is (in my opinion) unnecessarily complex as it has too many modes of operation. It would be less confusing if git used separate commands for "switch to a different branch" vs "check specific files out of some branch, without changing the current branch". But these are all lumped into one git checkout command, so let's look at lines 75–79:

75.     The-Dorfchester:gordo.dev ajh$ git checkout staging master
76.     error: pathspec 'staging' did not match any file(s) known to git.
77.     error: pathspec 'master' did not match any file(s) known to git.
78.     The-Dorfchester:gordo.dev ajh$ git checkout staging
79.     error: pathspec 'staging' did not match any file(s) known to git.

The more common form of checkout is git checkout branch-name, but in this case, you're invoking a different git checkout, which is git checkout [ branch-name ] [ -- ] path1 path2 ... pathN, but you can leave out the --. Since staging is not a valid branch name, it's interpreted as a path instead. (It doesn't matter that master is a valid branch name, because staging was in the only argument-position where git checkout allows a branch name.)

On line 80 you got a different error:

80.     The-Dorfchester:gordo.dev ajh$ git checkout master
81.     error: Your local changes to the following files would be overwritten by checkout:
82.             .idea/workspace.xml
83.             wp-content/themes/goTheme2015/blog-loadMore.php
84.             wp-content/themes/goTheme2015/home.php
85.             wp-content/themes/goTheme2015/stylesheets/layout.css
86.             wp-content/themes/goTheme2015/stylesheets/layout.scss
87.     Please, commit your changes or stash them before you can switch branches.

You're currently (still) on branch trouble and you asked git to move to branch master. To move from one branch to another, git must replace the contents of some files in your work-tree. Which files?

The answer to that is a bit complicated, but in this case, the errors occur for (at least) some files like .idea/workspace.xml that (1) are stored on the most recent commit in the current branch; (2) are in the new branch's tip commit as well; and (3) the contents of that file in the new branch are different from the contents of that file in the current commit.

If the file in the work-tree matched the file in the current commit, git would feel safe in wiping out the work-tree version and replacing it with the switch-to branch (master, in this case) tip commit version. But these files in your work-tree don't match the current commit. We saw that in the original git checkout -b when it ran git status.

So, git refused to change branches, requesting that you either commit your changed files, or use git stash to commit them (the difference is that git stash commits them on no branch, rather than on the current branch).

OK, so you finally committed them

Now we get to lines 89–91:

89.     The-Dorfchester:gordo.dev ajh$ git commit -am "idk"
90.     [trouble 820decb] idk
91.      5 files changed, 39 insertions(+), 93 deletions(-)

This made a new commit, on the current branch trouble. It then moved the branch to point to the new commit, whose 40-character SHA-1 starts with 820decb.

Now we hit line 92:

92.     The-Dorfchester:gordo.dev ajh$ git push master

This asks your git to push to the remote named master. There isn't one, and you get the same error as earlier. All of these also spit out that enormous annoying "set your push.default" message, which gets us to line 119, and also 125:

119.    The-Dorfchester:gordo.dev ajh$ git pull master
...
125.    The-Dorfchester:gordo.dev ajh$ git push --set-upstream master trouble

These both have the same problem as before: the word master is in the slot for a remote name, but isn't a valid remote.

This brings us to line 131:

131.    The-Dorfchester:gordo.dev ajh$ git push --set-upstream staging trouble

Finally, a command git likes! :-) This time staging is in the slot for a remote, and trouble is in the slot for a "refspec", and both of those work. (The --set-upstream tells git push that once the push succeeds, it should record staging's trouble as the "upstream branch" for your local staging. For a lot of words on what this all means, see this answer.)

Let's skip one more wrong checkout and proceed to line 154 (and its attendant success messages):

154.    The-Dorfchester:gordo.dev ajh$ git checkout master
155.    Switched to branch 'master'
156.    Your branch is behind 'staging/master' by 16 commits, and can be fast-forwarded.
157.      (use "git pull" to update your local branch)

This one works. It's not because of the successful git push, though: it succeeds this time because you finally committed on your trouble branch. That got the modified files safely stored inside the repository, as that new commit whose 40-character "true name" SHA-1 ID starts with 820decb.

Once they were committed, so that your work-tree was clean, git would have been fine with git checkout master. You also pushed your trouble to your remote named "staging", giving it the name trouble there as well, but that's not important for the git checkout master step.

Line 155 acknowledges the success. Line 156 is the output from git status, telling you that your master is behind its upstream (which your git calls staging/master) by 16 commits—there are 16 commits they had that you didn't—and is not "ahead of" its upstream. Again, see my other answer (already linked above) for more on this.

You then ran git pull, which is really just git fetch followed by git merge (it's meant as a convenience wrapper for these two steps, but it turns out the second is the wrong step for most people, so it's configurable). The git merge did a "fast forward" merge, which means you had no new commits, and they had new commits, so your git was able to just "slide the branch forward" to the new branch-tip, adding their new DAGlet to your existing DAG without any fuss at all.

That gets us all the way to line 388 (and its response lines):

388.    The-Dorfchester:gordo.dev ajh$ git commit -am "pull from staging/master to master, idk"
389.    On branch master
390.    Your branch is up-to-date with 'staging/master'.
391.    nothing to commit, working directory clean

This git commit command found nothing to commit, and did not make any new commits. Your branch master has no new commits added and the branch tip is the same as it was before.

392.    The-Dorfchester:gordo.dev ajh$ git push master

This is the same error as before: git push wants the name of a remote, first. The big spew about push.default gets us all the way to:

419.    The-Dorfchester:gordo.dev ajh$ git push staging master

This one is correct, but we just saw that your git commit earlier added no new commits. So your git calls up the git on staging and finds there's nothing to do:

420.    Everything up-to-date

and it does nothing (and succeeds).

(Incidentally, the big spew about push.default is omitted here because you gave git push both a remote and a refspec. The push.default setting is what push should do if you don't give a refspec, i.e., if you give it only a remote, or give it nothing at all. If you give git push nothing at all, it will figure out the remote to use based on the current branch's upstream setting.)


1How many meanings depends on how you count some finer divisions. See this question for more.

2Be aware that DAGlet is my own invention, so if you start using it, you may have to define it for your audience.

这篇关于推送到git时出现非快进错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆