簡體   English   中英

推送到git時出現非快進錯誤

[英]Non-fast-forward error when pushing to 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編輯=============這是一個粘貼程序,其中包含我用來正確推送內容的終端命令。 我仍然可以使用關於到底發生了什么的解釋。 我可以重復這些步驟,但是我不太了解為什么它們起作用,而常規的推/拉卻不能。

http://pastebin.com/u9DAiU5P

基本上,我創建了一個新分支,並從master簽出,它快速轉發了我。 我必須在哪里執行git push staging staging奇怪的事情發生了,這方面的分支令人困惑

我看着你的第二個引擎收錄鏈接,我看到了很多混亂的(並不奇怪,因為Git的術語似乎是故意confus 荷蘭國際集團 )。

我認為最好的選擇是退后一步,首先了解一下git術語,並提供pastebin中的一些示例。

讓我們從“遠程”開始。

什么是遙控器?

遠程只是一個名稱,例如originstagingupstream ,為git(和您)提供對應git倉庫的完整URL的簡稱。 但是git利用了這個短名稱,為您提供了“遠程跟蹤分支”,我們尚無法描述。 首先,我們需要談論“分支”。

什么是分支?

這是來自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; ...

在第1行,您創建了一個新的分支名稱trouble

在git中,“分支”一詞至少具有兩種不同的含義。 1trouble分支名稱 ,例如trouble ,然后在存儲庫中的提交圖中有序列,這些序列構成了實際的分支。 為了將它們與分支名稱區分開,我們稱它們為“提交圖片段”。 由於這些術語比較笨拙,因此請注意,從技術上來講,提交圖是有向無環圖或“ DAG”。 因此,該圖的一部分是“ DAGlet”。 2

DAGlets很重要,因為來自git的投訴:

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

當您要求git進行將“忘記” DAG的一部分(即“丟失DAGlet”)的推送時,就會發生這種情況。 我們稍后會再講。

分支與提交

我假設您有一個合理的“提交”概念,它在git中保存了您工作的完整快照,更准確地說,是“索引”或“臨時區域”中所有內容的副本提交消息,您的姓名和電子郵件以及提交時間。 不過,他們還有另外一件非常重要的事情,我們將在下一節中介紹。

現在讓我們看一下2-7行。 當您執行git checkout -b trouble ,git指出它會將一堆未修改和未提交的文件保留為已修改和未提交的文件。

我知道您正在嘗試執行git push ,而git push pushs 提交而不是文件。 因此,如果您已修改但未提交的文件, 則無法推送那些未提交的更改。

(您沒有在其中顯示git status ,但是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。

分支名稱從何而來?

分支名稱使我們可以找到特定的提交。 幾乎所有的分支名稱都是:它是提交的指針。 如果您在分支master並且進行了新的提交,則git首先查找當前的提交-它有一個丑陋的40個字符的SHA-1“真名”,有時您會看到這樣的縮寫版本b66c9f0並從暫存區域,您的姓名和電子郵件,您的提交消息以及此父ID進行一次新提交。 然后,這是棘手的部分,git將提交的SHA-1寫入分支名稱。

這樣,分支本身就已增長,並且分支名稱指向分支末尾的新“ 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 push自己的git手提交給另一個git(即偵聽遠程存儲的URL的git),然后要求git將分支設置為最頂端承諾你要推動。

但是,假設您要求git將您的master (commit 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 ,它提供了push-to的URL。 那是push之后的第一個單詞。 任何其他單詞都是“ refspecs”,我們尚未定義,但現在讓我們只說它們由分支名稱組成(多數情況下是正確的)。 您給git一個分支名稱,例如mastertrouble ,然后嘗試使用遠程上的另一個分支名稱將您在該名稱下的提交推送到遠程。 (遠程上的哪個分支名稱?嗯,我們稍后會看到其他名稱。)

  • 您推送的DAGlet應該僅擴展其分支,並向其添加新的提交。 從技術上講,您要求他們將分支設置為的提交應該是他們已經擁有的尖端提交(這是“沒有實際推動”的情況),或者最終應該指向該提交。 您可以添加一個或多個提交,但是在序列中的某個位置,您的新提交之一必須指向其現有的技巧提交。

  • 或者,您可以推送他們根本沒有的分支名稱。 如果您在遙控器上創建該名稱,則不會丟失任何提交。

邊欄: 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 你會推,如果你不命名一個分支的分支,是當前分支,而且也沒有棘手的東西就像在你的倉庫一個分支,它的拼寫雷蒙德-豪華游艇,但在遙控器上,它的拼寫Throatwobbler-紅樹林

那很簡單,這就是為什么將其稱為simple 還有其他四個選項,但我將在本發布中保留它們。

這里出了什么問題?

考慮第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.

git push命令需要一個遠程如后其第一個字push trouble這個詞被視為遠程,它不起作用(您沒有名為trouble的遠程)。 push代碼充滿了歷史包bag,因此在此之后,它嘗試將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)存儲在當前分支的最新提交中; (2)也在分支的尖端提交; (3) 分支中該文件的內容與當前提交中該文件的內容不同

如果工作樹中的文件與當前提交中的文件匹配,則git會感到安全,可以清除工作樹版本並將其替換為switch-to分支(在本例中為master )技巧提交版本。 但是,工作樹中的這些文件與當前提交匹配。 我們在原來的git checkout -b看到它運行git status

因此,git拒絕更改分支,要求您要么提交更改的文件,要么使用git stash提交它們(不同之處在於git stash 不在任何分支上提交它們,而不是在當前分支上提交它們)。

好了,所以你終於承諾了

現在我們進入第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 checkout master正常。 您還將trouble推送到名為“ staging”的遠程站點,並在其中也給它命名為trouble ,但這對於git checkout master步驟並不重要。

第155行確認成功。 第156行是git status的輸出,告訴您您的master在其上游(您的git稱為staging/master )落后16次提交-共有16次提交,而您沒有這樣做-並且不“超前”它的上游。 再次,請參閱我的其他答案(已在上面鏈接)以獲取更多信息。

然后運行git pull ,實際上只是git fetchgit 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的大push.default讓我們一路走到:

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

這是正確的,但我們只是看到您的git commit之前未添加任何新的提交。 因此,您的git會在staging調用git並發現無事可做:

420.    Everything up-to-date

它什么都不做(並且成功了)。

(順便說一下,這里省略了關於push.default的大push.default ,因為您同時給git push 一個遠程一個push.default設置是在不提供push.default情況下push應該執行的操作 ,即,如果給了它只是一個遠程,或者什么都不給。如果您根本不給git push ,它將根據當前分支的上游設置確定要使用的遠程。)


1多少含義取決於您如何計算一些更精細的划分。 有關更多信息,請參見此問題

2請注意,DAGlet是我自己的發明,因此,如果您開始使用它,則可能必須為您的聽眾定義它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM