>---基礎篇html
遠程倉庫並不複雜, 在現在的雲計算盛行的世界很容易把遠程倉庫想象成一個富有魔力的東西, 但實際上它們只是你的倉庫在另個一臺計算機上的拷貝。你能夠經過因特網與這臺計算機通訊 —— 也就是增長或是獲取提交記錄git
話雖如此, 遠程倉庫卻有一系列強大的特性github
如今用網站來對遠程倉庫進行可視化操做變得愈加流行了(像 Github ), 但遠程倉庫永遠是這些工具的頂樑柱, 所以理解其概念很是的重要!shell
使用clone
命令將遠程倉庫中的項目克隆到本地。ide
$ git clone [remoteName]
remoteName
: 遠程倉庫的地址(名稱)工具
Git
遠程倉庫至關的操做實際能夠概括爲兩點:向遠程倉庫傳輸數據以及從遠程倉庫獲取數據。既然咱們能與遠程倉庫同步,那麼就能夠分享任何能被 Git
管理的更新(所以能夠分享代碼、文件、想法、情書等等)。學習
本節課咱們將學習如何從遠程倉庫獲取數據 —— 命令如其名,它就是 git fetch
。測試
你會看到當咱們從遠程倉庫獲取數據時, 遠程分支也會更新以反映最新的遠程倉庫。在上一了咱們已經說起過這一點了。fetch
虛線爲遠程倉庫,實線爲本地倉庫。網站
$ git fetch
git fetch
完成了僅有的可是很重要的兩步:
o/master
)git fetch
實際上將本地倉庫中的遠程分支更新成了遠程倉庫相應分支最新的狀態。
若是你還記得上一節課程中咱們說過的,遠程分支反映了遠程倉庫在你最後一次與它通訊時的狀態,git fetch
就是你與遠程倉庫通訊的方式了!但願我說的夠明白了,你已經瞭解 git fetch
與遠程分支之間的關係了吧。
git fetch
一般經過互聯網(使用 http://
或 git://
協議) 與遠程倉庫通訊。
git fetch
並不會改變你本地倉庫的狀態。它不會更新你的 master
分支,也不會修改你磁盤上的文件。
理解這一點很重要,由於許多開發人員誤覺得執行了 git fetch
之後,他們本地倉庫就與遠程倉庫同步了。它可能已經將進行這一操做所需的全部數據都下載了下來,可是並無修改你本地的文件。咱們在後面的課程中將會講解能完成該操做的命令。
因此, 你能夠將 git fetch
的理解爲單純的下載操做。
既然咱們已經知道了如何用 git fetch
獲取遠程的數據, 如今咱們學習如何將這些變化更新到咱們的工做當中。
其實有不少方法的 —— 當遠程分支中有新的提交時,你能夠像合併本地分支那樣來合併遠程分支。也就是說就是你能夠執行如下命令:
git cherry-pick o/master
git rebase o/master
git merge o/master
實際上,因爲先抓取更新再合併到本地分支這個流程很經常使用,所以 Git
提供了一個專門的命令來完成這兩個操做。它就是咱們要講的 git pull
。
$ git pull
git pull
就是 git fetch
和 git merge <just-fetched-branch>
的縮寫!
這裏有一件棘手的事 —— 爲了接下來的課程, 咱們須要先教你如何製造遠程倉庫的變動。
這意味着,咱們須要「僞裝」你的同事、朋友、合做夥伴更新了遠程倉庫,有多是某個特定的分支,或是幾個提交記錄。
爲了作到這點,咱們引入一個自造命令 git fakeTeamwork
!它的名稱已經說明了一切,先看演示..
$ git clone local branch "master" set to track remote branch "o/master" $ git commit -m "c2" $ git commit -m "c3" $ git push $ git checkout c1 $ git commit -m "c4" 警告!如今是分離 HEAD 狀態 $ git checkout master $ git merge c4
OK,咱們已經學過了如何從遠程倉庫獲取更新併合併到本地的分支當中。這很是棒……可是我如何與你們分享個人成果呢?
嗯,上傳本身分享內容與下載他人的分享恰好相反,那與 git pull
相反的命令是什麼呢?git push
!
git push
負責將你的變動上傳到指定的遠程倉庫,並在遠程倉庫上合併你的新提交記錄。一旦 git push
完成, 你的朋友們就能夠從這個遠程倉庫下載你分享的成果了!
你能夠將 git push
想象成發佈你成果的命令。它有許多應用技巧,稍後咱們會了解到,可是我們仍是先從基礎的開始吧……
注意 —— git push
不帶任何參數時的行爲與 Git 的一個名爲 push.default
的配置有關。它的默認值取決於你正使用的 Git 的版本,可是在教程中咱們使用的是 upstream
。 這沒什麼太大的影響,可是在你的項目中進行推送以前,最好檢查一下這個配置。
$ git push
過去了, 遠程倉庫接收了 C2
,遠程倉庫中的 master
分支也被更新到指向 C2
了,咱們的遠程分支 (``o/master`) 也一樣被更新了。全部的分支都同步了!
git push
失敗是由於你最新提交的 C3
基於遠程分支中的 C1
。而遠程倉庫中該分支已經更新到 C2
了,因此 Git
拒絕了你的推送請求。
$ git fakeTeamwork $ git fetch $ git commit -m "c3" $ git rebase c2 $ git push
用 git fetch
更新了本地倉庫中的遠程分支,而後用 rebase
將咱們的工做移動到最新的提交記錄下,最後再用 git push
推送到遠程倉庫。
既然你應該很熟悉 fetch
、``pull、
push` 了,如今咱們要經過一個新的工做流來測試你的這些技能。
在大型項目中開發人員一般會在(從 master
上分出來的)特性分支上工做,工做完成後只作一次集成。這跟前面課程的描述很相像(把 side
分支推送到遠程倉庫),不過本節咱們會深刻一些.
可是有些開發人員只在 master
上作 push
、pull
—— 這樣的話 master
老是最新的,始終與遠程分支 (o/master
) 保持一致。
對於接下來這個工做流,咱們集成了兩個步驟:
master
上$ git pull -rebase $ git push
執行了兩個命令:
rebase
到遠程分支的最新提交記錄fetch
遠程倉庫的更新到本地倉庫,進行rebase
合併,最後push
到遠程倉庫中。
$ git fetch $ git rebase o/master side1 $ git rebase side1 side2 $ git rebase side2 side3 $ git rebase side3 master $ git push
爲了 push
新變動到遠程倉庫,你要作的就是包含遠程倉庫中最新變動。意思就是隻要你的本地分支包含了遠程分支(如 o/master
)中的最新變動就能夠了,至於具體是用 rebase
仍是 merge
,並無限制。
那麼既然沒有規定限制,爲什麼前面幾節都在着重於 rebase
呢?爲何在操做遠程分支時不喜歡用 merge
呢?
在開發社區裏,有許多關於 merge
與 rebase
的討論。如下是關於 rebase
的優缺點:
優勢:
Rebase
使你的提交樹變得很乾淨, 全部的提交都在一條線上缺點:
Rebase
修改了提交樹的歷史好比, 提交 C1
能夠被 rebase
到 C3
以後。這看起來 C1
中的工做是在 C3
以後進行的,但其實是在 C3
以前。
一些開發人員喜歡保留提交歷史,所以更偏心 merge
。而其餘人(好比我本身)可能更喜歡乾淨的提交樹,因而偏心 rebase
。仁者見仁,智者見智。
$ git fetch $ git checkout side1 $ git merge o/master $ git merge side2 $ git merge side3 $ git checkout master $ git merge side1 $ git push
在前幾節課程中有件事兒挺神奇的,Git
好像知道 master
與 o/master
是相關的。固然這些分支的名字是類似的,可能會讓你以爲是依此將遠程分支 master
和本地的 master
分支進行了關聯。這種關聯在如下兩種狀況下能夠清楚地獲得展現:
pull
操做時, 提交記錄會被先下載到 o/master
上,以後再合併到本地的 master
分支。隱含的合併目標由這個關聯肯定的。push
操做時, 咱們把工做從 master
推到遠程倉庫中的 master
分支(同時會更新遠程分支 o/master
) 。這個推送的目的地也是由這種關聯肯定的!直接了當地講,master
和 o/master
的關聯關係就是由分支的「remote tracking
」屬性決定的。master
被設定爲跟蹤 o/master
—— 這意味着爲 master
分支指定了推送的目的地以及拉取後合併的目標。
你可能想知道 master
分支上這個屬性是怎麼被設定的,你並無用任何命令指定過這個屬性呀!好吧, 當你克隆倉庫的時候, Git
就自動幫你把這個屬性設置好了。
當你克隆時, Git
會爲遠程倉庫中的每一個分支在本地倉庫中建立一個遠程分支(好比 o/master
)。而後再建立一個跟蹤遠程倉庫中活動分支的本地分支,默認狀況下這個本地分支會被命名爲 master
。
克隆完成後,你會獲得一個本地分支(若是沒有這個本地分支的話,你的目錄就是「空白」的),可是能夠查看遠程倉庫中全部的分支(若是你好奇心很強的話)。這樣作對於本地倉庫和遠程倉庫來講,都是最佳選擇。
這也解釋了爲何會在克隆的時候會看到下面的輸出:
local branch "master" set to track remote branch "o/master"
固然能夠啦!你可讓任意分支跟蹤 o/master
, 而後該分支會像 master
分支同樣獲得隱含的 push
目的地以及 merge 的目標。 這意味着你能夠在分支 totallyNotMaster
上執行 git push
,將工做推送到遠程倉庫的 master
分支上。
有兩種方法設置這個屬性,第一種就是經過遠程分支檢出一個新的分支,執行:
git checkout -b totallyNotMaster o/master
就能夠建立一個名爲 totallyNotMaster
的分支,它跟蹤遠程分支 o/master
。
在不檢出 master
分支的狀況下將工做推送到的遠程倉庫中的 master
分支上。
$ git branch side $ git checkout side $ git commit -m "c3" $ git fetch $ git rebase c2 side $ git push
很好! 既然你知道了遠程跟蹤分支,咱們能夠開始揭開 git push
、fetch
和 pull
的神祕面紗了。咱們會逐個介紹這幾個命令,它們在理念上是很是類似的。
首先來看 git push
。在遠程跟蹤課程中,你已經學到了 Git
是經過當前檢出分支的屬性來肯定遠程倉庫以及要 push
的目的地的。這是未指定參數時的行爲,咱們能夠爲 push
指定參數,語法是:
git push <remote> <place>
<place>
參數是什麼意思呢?咱們稍後會深刻其中的細節, 先看看例子, 這個命令是:
git push origin master
把這個命令翻譯過來就是:
切到本地倉庫中的「master」分支,獲取全部的提交,再到遠程倉庫「origin」中找到「master」分支,將遠程倉庫中沒有的提交記錄都添加上去,搞定以後告訴我。
咱們經過place
參數來告訴 Git
提交記錄來自於 master
, 要推送到遠程倉庫中的 master
。它實際就是要同步的兩個倉庫的位置。
須要注意的是,由於咱們經過指定參數告訴了 Git
全部它須要的信息, 因此它就忽略了咱們所檢出的分支的屬性!
$ git push origin master $ git push origin foo
還記得以前課程說的吧,當爲 git push
指定 place
參數爲 master
時,咱們同時指定了提交記錄的來源和去向。
你可能想問 —— 若是來源和去向分支的名稱不一樣呢?好比你想把本地的 foo
分支推送到遠程倉庫中的 bar
分支。
哎,很遺憾 Git
作不到…… 開個玩笑,別當真!固然是能夠的啦 😃 Git
擁有超強的靈活性(有點過於靈活了)
接下來我們看看是怎麼作的……
要同時爲源和目的地指定 <place>
的話,只須要用冒號 :
將兩者連起來就能夠了:
git push origin <source>:<destination>
這個參數實際的值是個 refspec
,refspec
是一個自造的詞,意思是 Git
能識別的位置(好比分支 foo
或者 HEAD~1
)
一旦你指定了獨立的來源和目的地,就能夠組織出言簡意賅的遠程操做命令了,讓咱們看看演示!
$ git push origin foo^:master
若是你要推送到的目的分支不存在會怎麼樣呢?沒問題!Git
會在遠程倉庫中根據你提供的名稱幫你建立這個分支!
$ git push origin master^:foo $ git push origin foo:master
咱們剛學習了 git push
的參數,很酷的 <place>
參數,還有用冒號分隔的 refspecs
(<source>:<destination>
)。 這些參數能夠用於 git fetch
嗎?
你猜中了!git fetch
的參數和 git push
極其類似。他們的概念是相同的,只是方向相反罷了(由於如今你是下載,而非上傳)
讓咱們逐個討論下這些概念……
若是你像以下命令這樣爲 git fetch
設置 place
的話:
$ git fetch origin foo
Git
會到遠程倉庫的 foo
分支上,而後獲取全部本地不存在的提交,放到本地的 o/foo
上。
來看個例子(仍是前面的例子,只是命令不一樣了)
咱們只下載了遠程倉庫中 foo
分支中的最新提交記錄,並更新了 o/foo
。
你可能會好奇 —— 爲什麼 Git 會將新提交放到 o/foo
而不是放到我本地的 foo
分支呢?以前不是說這樣的 place
參數就是同時應用於本地和遠程的位置嗎?
好吧, 本例中 Git
作了一些特殊處理,由於你可能在 foo
分支上的工做還未完成,你也不想弄亂它。還記得在 git fetch
課程裏咱們講到的嗎 —— 它不會更新你的本地的非遠程分支, 只是下載提交記錄(這樣, 你就能夠對遠程分支進行檢查或者合併了)。
「若是咱們指定 <source>:<destination>
會發生什麼呢?」
若是你以爲直接更新本地分支很爽,那你就用冒號分隔的 refspec
吧。不過,你不能在當前檢出的分支上幹這個事,可是其它分支是能夠的。
這裏有一點是須要注意的 —— source
如今指的是遠程倉庫中的位置,而 <destination>
纔是要放置提交的本地倉庫的位置。它與 git push 恰好相反,這是能夠講的通的,由於咱們在往相反的方向傳送數據。
理論上雖然行的通,但開發人員不多這麼作。我在這裏介紹它主要是爲了從概念上說明 fetch
和 push
的類似性,只是方向相反罷了。
使用 fetch
時, 你必須指定source
和 destination
。 注意一下目標窗口, 由於提交對象的 ID
可能會變哦!
$ git fetch origin master^1:foo $ git fetch origin foo:master $ git checkout foo $ git merge master
Git
有兩種關於 source
的用法是比較詭異的,即你能夠在 git push
或 git fetch
時不指定任何 source
,方法就是僅保留冒號和 destination
部分,source
部分留空。
git push origin :side
若是 push
空 source
到遠程倉庫會如何呢?它會刪除遠程倉庫中的分支!慎重使用,刪除別人的遠程分支可能會捱揍。
git fetch origin :bugFix
若是 fetch
空 source
到本地,會在本地建立一個新分支。
既然你已經掌握關於 git fetch
和 git push
參數的方方面面了,關於 git pull
幾乎沒有什麼能夠講的了 😃
由於 git pull
到頭來就是 fetch
後跟 merge
的縮寫。你能夠理解爲用一樣的參數執行 git fetch
,而後再 merge
你所抓取到的提交記錄。
還能夠和其它更復雜的參數一塊兒使用, 來看一些例子:
如下命令在 Git
中是等效的:
git pull origin foo
至關於:
$ git fetch origin foo $ git merge o/foo
還有...
git pull origin bar~1:bugFix
至關於:
$ git fetch origin bar~1:bugFix $ git merge bugFix
看到了? git pull
實際上就是 fetch
+ merge
的縮寫, git pull
惟一關注的是提交最終合併到哪裏(也就是爲 git fetch
所提供的 destination
參數)。
經過指定 master
咱們更新了 o/master
。而後將 o/master
merge
到咱們的檢出位置,不管咱們當前檢出的位置(checkout
的位置、HEAD
所在位置)是哪。
須要下載一些提交,而後建立一些新分支,再合併這些分支到其它分支, 但這用不了幾個命令。
$ git pull origin bar:foo $ git pull origin master:side