git命令詳解( 七 )
此為git命令詳解的第七篇
這章我們可以來逐漸揭開 git push、fetch 和 pull 的神秘面紗了。我們會逐個介紹這幾個命令,它們在理念上是非常相似的。
git push的參數
git fetch 的參數
git push:
首先來看 git push
。在遠程跟蹤課程中,你已經學到了 Git 是通過當前檢出分支的屬性來確定遠程倉庫以及要 push 的目的地的。這是未指定參數時的行為,我們可以為 push 指定參數,語法是:
git push <remote> <place>
<place>
參數是什麽意思呢?我們稍後會深入其中的細節, 先看看例子, 這個命令是:
git push origin master
把這個命令翻譯過來就是:
切到本地倉庫中的“master”分支,獲取所有的提交,再到遠程倉庫“origin”中找到“master”分支,將遠程倉庫中沒有的提交記錄都添加上去,搞定之後告訴我。
我們通過“place”參數來告訴 Git 提交記錄來自於 master, 要推送到遠程倉庫中的 master。它實際就是要同步的兩個倉庫的位置。
需要註意的是,因為我們通過指定參數告訴了 Git 所有它需要的信息, 所以它就忽略了我們所檢出的分支的屬性!
我們來看看指定參數的例子,註意下我們當前檢出的位置
執行命令:git checkout C0
git push origin master
好了! 通過指定參數, 遠程倉庫中的 master
分支得到了更新。
如果不指定參數會發生什麽呢?
執行命令:git checkout C0
git push
命令失敗了(正如你看到的,什麽也沒有發生)! 因為我們所檢出的 HEAD 沒有跟蹤任何分支
<place>
參數詳解
還記得之前課程說的吧,當為 git push 指定 place 參數為 master
時,我們同時指定了提交記錄的來源和去向。
你可能想問 —— 如果來源和去向分支的名稱不同呢?比如你想把本地的 foo
分支推送到遠程倉庫中的 bar
分支。
哎,很遺憾 Git 做不到…… 開個玩笑,別當真!當然是可以的啦 :) Git 擁有超強的靈活性(有點過於靈活了)
接下來咱們看看是怎麽做的……
要同時為源和目的地指定 <place>
的話,只需要用冒號 :
將二者連起來就可以了:
git push origin <source>:<destination>
這個參數實際的值是個 refspec,“refspec” 是一個自造的詞,意思是 Git 能識別的位置(比如分支 foo
或者 HEAD~1
)
一旦你指定了獨立的來源和目的地,就可以組織出言簡意賅的遠程操作命令了,讓我們看看演示!
記住,source
可以是任何 Git 能識別的位置:
執行命令:git push origin foo^:master
這是個另人困惑的命令,但是它確實是可以運行的 —— Git 將 foo^
解析為一個位置,上傳所有未被包含到遠程倉庫裏 master
分支中的提交記錄。
如果你要推送到的目的分支不存在會怎麽樣呢?沒問題!Git 會在遠程倉庫中根據你提供的名稱幫你創建這個分支!
執行命令:git push origin master:newBranch
Git fetch 的參數
我們剛學習了 git push 的參數,很酷的 <place>
參數,還有用冒號分隔的 refspecs(<source>:<destination>
)。 這些參數可以用於 git fetch
嗎?
你猜中了!git fetch
的參數和 git push
極其相似。他們的概念是相同的,只是方向相反罷了(因為現在你是下載,而非上傳)
讓我們逐個討論下這些概念……
<place>
參數
如果你像如下命令這樣為 git fetch 設置 <place> 的話:
git fetch origin foo
Git 會到遠程倉庫的 foo
分支上,然後獲取所有本地不存在的提交,放到本地的 o/foo
上。
來看個例子(還是前面的例子,只是命令不同了)
執行命令:git fetch origin foo
你可能會好奇 —— 為何 Git 會將新提交放到 o/foo
而不是放到我本地的 foo 分支呢?之前不是說這樣的 <place> 參數就是同時應用於本地和遠程的位置嗎?
好吧, 本例中 Git 做了一些特殊處理,因為你可能在 foo 分支上的工作還未完成,你也不想弄亂它。還記得在 git fetch
課程裏我們講到的嗎 —— 它不會更新你的本地的非遠程分支, 只是下載提交記錄(這樣, 你就可以對遠程分支進行檢查或者合並了)。
“如果我們指定 <source>:<destination>
會發生什麽呢?”
如果你覺得直接更新本地分支很爽,那你就用冒號分隔的 refspec 吧。不過,你不能在當前檢出的分支上幹這個事,但是其它分支是可以的。
這裏有一點是需要註意的 —— source
現在指的是遠程倉庫中的位置,而 <destination>
才是要放置提交的本地倉庫的位置。它與 git push 剛好相反,這是可以講的通的,因為我們在往相反的方向傳送數據。
理論上雖然行的通,但開發人員很少這麽做。我在這裏介紹它主要是為了從概念上說明 fetch
和 push
的相似性,只是方向相反罷了。
來看個瘋狂的例子:
執行命令:git fetch origin foo:bar
哇! 看見了吧, Git 將 foo~1
解析成一個 origin 倉庫的位置,然後將那些提交記錄下載到了本地的 bar
分支(一個本地分支)上。註意由於我們指定了目標分支,foo
和 o/foo
都沒有被更新。
如果執行命令前目標分支不存在會怎樣呢?我們看一下上個對話框中沒有 bar 分支的情況。
執行命令:git fetch origin foo:bar
看見了吧,跟 git push 一樣,Git 會在 fetch 前自己創建立本地分支, 就像是 Git 在 push 時,如果遠程倉庫中不存在目標分支,會自己在建立一樣。
沒有參數呢?
如果 git fetch
沒有參數,它會下載所有的提交記錄到各個遠程分支……
執行:git fetch
古怪的 <source>
Git 有兩種關於 <source>
的用法是比較詭異的,即你可以在 git push 或 git fetch 時不指定任何 source
,方法就是僅保留冒號和 destination 部分,source 部分留空。
git push origin :side
git fetch origin :bugFix
我們分別來看一下這兩條命令的作用……
如果 push 空 <source> 到遠程倉庫會如何呢?它會刪除遠程倉庫中的分支! 例子:執行命令:git push origin :foo
就是這樣子, 我們通過給 push 傳空值 source,成功刪除了遠程倉庫中的 foo
分支, 這真有意思...(所以我們以後要慎用這個,萬一搞丟了分支還得麻煩)
如果 fetch 空 <source> 到本地,會在本地創建一個新分支。
執行命令:git fetch origin :bar
很神奇吧!但無論怎麽說, 這就是 Git!
git命令詳解( 七 )