[英]How to make local master a remote branch with git?
我從克隆存儲庫開始(git clone https:// blahblah_repository )。 然后,我進行了一些更改並進行了提交。 我沒有先分支,但現在我想推送到尚不存在的分支。
我如何在服務器上創建一個分支,然后假設自克隆以來,主頭尚未移動,則將我的非分支本地提交推送到新分支?
如果主控頭自克隆以來確實移動了,我該如何在服務器上分支以前的主控提交,然后將更改推送到那里?
我假設您當前正在掌握其他提交信息。
首先結帳到新分支
git checkout -b new_branch
new_branch
將具有您在master分支中完成的其他提交
將新分支推送到服務器(例如github)。 如果不存在該名稱的分支,它將自動創建到服務器的新分支。
git push origin new_branch
成功推送后,立即結帳至master分支
git checkout master
現在從管理員那里刪除額外的最高提交
git reset --hard HEAD~1
如果您已經在master分支中推送了其他提交,則在重置后執行強制推送
git push origin master -f
。
即使使用本地主機,它也將成為遠程主機
干杯!!
對於您的問題:
1.您的意思是您在本地master分支上提交了本地更改,但是現在您想要在另一個分支上進行更改,並在git服務器上創建相同的分支。 您可以使用以下步驟:
git branch branchname
git reset --hard origin/master
git push -u origin branchname
2.對於這種情況,您希望將本地主更改重新放置在主頂部,然后將本地主更改推送到遠程。 您可以使用以下步驟:
git checkout master
git pull origin master --rebase
git push origin master
您的問題分為兩個部分:
我如何在服務器上創建一個分支,然后假設自克隆以來,主頭尚未移動,則將我的非分支本地提交推送到新分支?
如果主控頭自克隆以來確實移動了,我該如何在服務器上分支以前的主控提交,然后將更改推送到那里?
但實際上,它揭示了每個人對Git的普遍困惑,這就是分支與分支之間(或也許是分支,分支與分支)之間的區別。 Git使用一個詞來表示至少兩個不同的事物。 (此后,Git的分布式特性使並發症變得復雜。)
讓我們首先考慮問題1,並確定“分支”可能意味着的不同事物。 我們可以為其中之一使用短語分支名稱 。 像master
這樣的名稱是分支名稱 ,並且分支名稱指向一個特定的提交。
我們也還沒有真正定義提交 ,但是到目前為止,您已經非常了解提交的含義。 為了以防萬一,讓我們確定一下。 提交是一個Git對象,它可以:
最后一點至關重要,我們將在下一段中再次討論。 現在,讓我們注意每個提交都有自己的唯一哈希ID,即8e2df81...
或ac0ffee...
或badbead...
或類似的哈希。 像master
這樣的分支名稱是這些哈希ID中的一個(並且一次只能一個,或者一次只能一個)的可讀名稱 。 我們稱其為branch tip ,或branch的tip commit ,但是最后一句話有點讓人不滿意:如果master
是分支,那么master
怎么能成為分支tip的名稱呢? 那么實際的分支是什么?
讓我們想象一個只有幾個提交的存儲庫。 讓我們從三個開始,而不是使用笨拙的哈希ID,讓我們使用單字母名稱來寫下它們。 我們進行的第一個提交是提交A
因為它是第一次提交,所以不能有父提交。 這個無父母的提交有一個特殊的名字:叫做根提交。
現在我們進行第二次提交,並將其命名為B
,將A
的實際哈希ID作為其父級存儲在其中。 我們說B
指向 A
我們使C
與父B
並說C
指向 B
為了跟蹤所有內容,我們將名稱master
指向C。讓我們畫一下:
A <- B <- C <-- master
Git的所有內部箭頭都是這樣向后的-名稱master
找到了最后一個提交,找到了一個較早的提交,依此類推-但是用這種方式繪制(至少在StackOverflow上的文本中)太麻煩了,所以讓我們從現在開始只使用連接線:
A--B--C <-- master
要添加新的提交,我們從其內容(快照,作者和提交者,日志消息及其父ID C
)計算其哈希ID(確實是一個大的丑陋哈希,但我們僅將其稱為D
)。 我們將此提交寫入存儲庫數據庫:
A--B--C <-- master
\
D
然后將名稱master
移至新的提交D
:
A--B--C [C used to be master]
\
D <-- master
通過添加新的提交(完全不接觸任何現有的提交),然后更改分支名稱以指向新的分支提示 ,分支就是這樣增長的。 因此,分支的其他必要含義,無論我們可能給它起什么名字,我都建議使用名稱“ DAGlet”。 看到“分支”到底是什么意思? - 是從分支尖端開始並向根向后工作而發現的提交的子集 。
這是最初令人困惑的地方,因為Git在所有這些事情上都只使用一個單詞:像ABCD
這樣的DAGlet是“一個分支”,分支master
的tip commit D
是“一個分支”,而master
本身是“分店”。 但是它們都是不同的東西。 Git只是希望我們知道我們的意思-經過一番練習,您至少在大多數時候確實知道,但是在需要時使用branch name , branch tip和DAGlet這兩個詞很高興。分開他們。
因此,現在我們可以仔細研究第一個問題的前半部分:您需要在服務器上創建一個分支名稱 。 我們也可以同時查看第二個問題:您可能想在自己的存儲庫中創建一個分支名稱 。
Git是Git,它提供了兩種標准的用戶界面方法來在您自己的存儲庫中創建分支名稱: git branch
和git checkout -b
。 我們已經看到,分支名稱僅指向一個特定的提交。 您進行了一次新的提交D
而Git對該新D
做出了自己的master
:
A--B--C
\
D <-- master
我之所以在D
上畫線是因為我想為在C
上留的筆記留出空間。 讓我們留出空間來添加更多指向C
名稱,僅就此而已,讓我們現在命名為C
的新名稱old-master
。 我們這樣做的方法是使用git branch
:
git branch old-master <hash-ID-of-commit-C>
結果是:
A--B--C <-- old-master
\
D <-- master
但是請記住,這一切都是在您的存儲庫中進行的,其中包含您的分支名稱。 服務器上還有另一個Git和另一個存儲庫。 那 Git仍然只有ABC
,他的master
仍然指向C
這就是Git變得聰明的地方: 您的 Git會為您記住您的 Git擁有他的名字的地方,使用您的存儲庫專有的名稱。 這些名稱是您的遠程跟蹤分支名稱 。 (哦,這是另一種分支!)
遠程跟蹤分支名稱的前綴是遠程名稱,通常是origin
。 因此, 您的 Git為您記住了Origin origin/master
,即他們的 Git的master
指向提交C
讓我們來畫一下:
A--B--C <-- old-master, origin/master
\
D <-- master
需要注意的是,我們不知道我們的Git使origin/master
名字:它是對自己,通過尋找其 master
,並添加origin/
前面我們。 當我們將Git連接到他們的Git時,我們的Git可以從他們那里獲取任何更新,並根據需要移動origin/*
名稱。 這就是遠程跟蹤分支的全部含義:它們為您記住了其他一些Git的名稱到哈希ID的映射。
還要注意,到目前為止,所有帶有名稱的東西都具有識別一個特定commit的簡單目標。 如果我們想要一個分支技巧 ,一旦找到提交,就完成了。 如果我們需要DAGlet(通過反向處理父ID找到了一些提交集),那么在這里也很不錯,因為提示提交有父ID,而那個父有另一個父ID,依此類推。 (我們可能需要告訴Git 何時停止向后退,但我將其留給其他SO發布。)
但是,現在我們需要告訴Git要求其他Git命名一個新的分支。 在我們的 Git中,我們使用了git branch
或(這里未顯示) git checkout -b
,但這並沒有告訴他們 Git任何東西。 除了實際登錄服務器(這將起作用!)之外,我們還需要一種方法讓Git調用其Git並要求服務器(即服務器)執行此操作。 而我們這樣做的方法是使用git push
。
當我們運行git push
,我們給它:
origin
:查找URL並使用該URL調用Internet電話上的另一個Git,以及 簡化太多了, refspec基本上是分支名稱 ,但在它們之間用冒號配對:
git push origin master:blah
左邊的名稱是我們的名稱,右邊的名稱blah
是我們希望其 Git更新,重置或創建的名稱。 我們的Git調用了自己的Git,有一個小的談話,找出犯(S),我們需要他們,那些送我們,他們不這樣做,像我們的新承諾D
1 -和要求他們建立自己的名字。 如果我們不使用:blah
一部分,我們的Git使用我們的名字:“請設置您的master
以同樣的方式,我有我master
集,以指向這個新的提交D
我給你。”
1 Git弄清楚這一點的方法是執行那些DAGlet動作。 如果我們添加了D
以及E
和F
,那么我們的Git將從F
到E
再到D
到C
。 當到達C
,他們的Git會說:“停下來,我有那個!” 然后我們的Git會發送DEF
鏈。
現在,我們可以完全回答問題1,這也是問題2的完整答案! 假設我們要為服務器提供新的提交D
並讓它們設置新的分支名稱test
:
git push origin master:test
這會向他們發送提交D
,然后要求他們設置對他們來說是新的test
以指向D
他們的master
可能仍然指向C
,所以他們得到了:
A--B--C <-- master
\
D <-- test
我們的git push
首先傳輸DAGlet,然后要求他們設置名稱,而我們沒有要求他們設置其master
。 因此,假設您的主人確實移動了,就像您的問題2一樣。他們有:
A--B--C--E <-- master
首先。 我們將新的提交D
發送給他們-記住,每個提交都有自己神奇的2哈希ID,因此我們的D
有一個不同於其E
-並要求他們設置分支名稱test
,從而為他們提供:
A--B--C--E <-- master
\
D <-- test
2魔術在於使用良好的哈希函數。 Git當前使用SHA-1,這已經足夠好了,但是現在...很好,它仍然足夠好,但是有點令人討厭 。
那一個git push
命令完成了服務器的全部工作,但它使我們的存儲庫變得一團糟。 由於我們有origin/master
我將不再使用old-master
origin/master
。
A--B--C <-- origin/master
\
D <-- master, origin/test
我們可能不想要這樣:我們也想擁有自己的test
,以匹配剛創建的Git來記住他們的 test
新origin/test
test
。 因此,現在我們可以使用git checkout -b
或git branch
,或使用一些特殊的Git魔術和簡單的舊git checkout
:
git checkout test
請注意,我們還沒有名為test的分支 ,或者至少還沒有。 此checkout命令即將失敗! 但是,在此之前,Git對自己說: 3 等一下,也許您打算基於origin
分支創建一個新分支! 它檢查並確定現在有一個origin/test
, 4因此它進行指向相同分支提示提交的新test
,並且副作用是,將新分支的上游設置為origin/test
:
A--B--C <-- origin/master
\
D <-- master, test, origin/test
現在,我們只需要修復master
即可指向commit C
,就像它在服務器上執行5一樣。 Git的是Git的,有多種方法可以做到這一點,但一個初學者使用是git reset --hard
,這是一個有點不幸的,因為git reset --hard
是有點危險的, 並且需要將第一開關回到分支master
:
git checkout master && git reset --hard origin/master
正如git status
所說,這首先將您的Git on branch master
,然后更改當前分支(您on branch
以指向與origin/master
相同的提交:
A--B--C <-- master (HEAD), origin/master
\
D <-- test, origin/test
請注意,我已將此(HEAD)
添加到圖形中:這是為了記住我們所在的分支。 既然有了master
和test
這兩個,我們總是需要知道git commit
和git reset
等會移動哪一個。
我在這里完全跳過了git checkout -b
,但是它的作用是將git branch
與git checkout
結合在一起。 它創建一個新的分支名稱,就像git branch
一樣; 然后切換到新分支,就像git checkout
一樣。 如果在此過程中所有問題出在哪里,它都會神奇地設法跳過創建新分支名稱的過程。 在內部,它通過“作弊”來實現:首先執行提交級別的檢出步驟。 如果成功, 現在它將創建分支名稱並更改您所在的分支。 當您手動執行此操作時,您將被迫以更明智的順序執行操作:首先為提交提供一個名稱,然后檢查名稱,即分支提示。
您最多可以混合使用這些不同的步驟為各種其他的訂單,如果你還記得,使一個新的分支第一 , git checkout -b
是要走的路。 但是,保持所有這些一致的關鍵是要記住,它是圖形 –由繪制提交及其父級構成的“ DAG” –是方程式的永久部分,而分支名稱(例如master
和test
只是標簽,您可以隨意整理所有內容。 您需要使用名稱來查找提交,因為哈希ID太笨拙了。
3不要將計算機擬人化; 他們討厭那個。
4這假定您的Git版本為1.8.4或更高。
5還是? 如果有E
承諾怎么辦? 請參閱下一節。
E
回到問題2:
如果主控頭自克隆以來確實移動了,我該如何在服務器上分支以前的主控提交,然后將更改推送到那里?
我們已經看到,你不必拿起新的提交E
可言,讓自己的新承諾D
放到一個新的側枝。 但是您可能想看看commit E
您可以隨時通過運行git fetch
來執行此操作。 Git的fetch
- 不是 git pull
; 我建議避免git pull
—與Git與push
相反。 像git push
一樣,它需要一個遠程的名稱和一些可選的refspecs,但是通常您只是命名該遠程,或者讓Git為您找出它,因為反正可能只有一個遠程:
git fetch
這會調出其他的Git(使用遙控器照常URL)的網絡電話,但這個時候,而不是你自己的Git送他們的Git 你的提交,你的Git都有他們的Git發送給您的提交。 和以前一樣,一旦Git到達您已經擁有的DAGlet,您的Git就會立即停止它們,因此這只會獲取新的提交(以及完成這些新提交所需的任何其他數據)。 然后,您的Git通過更新所有遠程跟蹤分支名稱來記住其分支名稱。 因此,如果它們確實具有提交E
並且您運行git fetch
,則您的圖形將來自:
A--B--C <-- origin/master
\
D [whatever name(s) you have here at this point]
至:
A--B--C--E <-- origin/master
\
D [whatever]
運行git fetch
始終是安全的 ,因為git fetch
僅向您的存儲庫添加新的提交 。 它並不─ 不能 -改變任何舊的:一個提交的哈希值ID是其內容的加密校驗,因此任何試圖改變一個新的,不同的哈希ID 任何結果。 相反,它會添加出現的所有新提交,然后更改您的origin/*
名稱以匹配其他Git中的內容。
(我會注意到,順便在這里,那git push
可以看出,他們的origin/master
點提交E
,但它不會改變你的origin/master
,原因是git push
正在發送的東西,不接受他們。這將更新或創建您發送給他們,他們再接受遠程跟蹤分支名稱為分支機構名稱創建有或更新,但不會更新任何其他人,這是一個設計選擇了一堆理由作出,包括Git不允許您設置名稱以指向您沒有的提交的事實,如果您還沒有其E
,則不能設置自己的origin/master
來指向它。 )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.