五、遠(yuǎn)程倉(cāng)庫(kù)的使用
為了能在任意 Git 項(xiàng)目上協(xié)作,你需要知道如何管理自己的遠(yuǎn)程倉(cāng)庫(kù)。 遠(yuǎn)程倉(cāng)庫(kù)是指托管在因特網(wǎng)或其他網(wǎng)絡(luò)中的你的項(xiàng)目的版本庫(kù)。 你可以有好幾個(gè)遠(yuǎn)程倉(cāng)庫(kù),通常有些倉(cāng)庫(kù)對(duì)你只讀,有些則可以讀寫。 與他人協(xié)作涉及管理遠(yuǎn)程倉(cāng)庫(kù)以及根據(jù)需要推送或拉取數(shù)據(jù)。 管理遠(yuǎn)程倉(cāng)庫(kù)包括了解如何添加遠(yuǎn)程倉(cāng)庫(kù)、移除無(wú)效的遠(yuǎn)程倉(cāng)庫(kù)、管理不同的遠(yuǎn)程分支并定義它們是否被跟蹤等等。
1. 查看遠(yuǎn)程倉(cāng)庫(kù)
如果想查看你已經(jīng)配置的遠(yuǎn)程倉(cāng)庫(kù)服務(wù)器,可以運(yùn)行 git remote 命令。
它會(huì)列出你指定的每一個(gè)遠(yuǎn)程服務(wù)器的簡(jiǎn)寫。
如果你已經(jīng)克隆了自己的倉(cāng)庫(kù),那么至少應(yīng)該能看到 "origin -" 這是 Git 給你克隆的倉(cāng)庫(kù)服務(wù)器的默認(rèn)名字:
$ git clone https://github.com/schacon/ticgit
Cloning into 'ticgit'...
remote: Reusing existing pack: 1857, done.
remote: Total 1857 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (772/772), done.
Checking connectivity... done.
$ cd ticgit
$ git remote
origin
你也可以指定選項(xiàng) -v,會(huì)顯示需要讀寫遠(yuǎn)程倉(cāng)庫(kù)使用的 Git 保存的簡(jiǎn)寫與其對(duì)應(yīng)的 URL。
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
如果你的遠(yuǎn)程倉(cāng)庫(kù)不止一個(gè),該命令會(huì)將它們?nèi)苛谐觥?例如,與幾個(gè)協(xié)作者合作的,擁有多個(gè)遠(yuǎn)程倉(cāng)庫(kù)的倉(cāng)庫(kù)看起來(lái)像下面這樣:
$ cd grit
$ git remote -v
bakkdoor https://github.com/bakkdoor/grit (fetch)
bakkdoor https://github.com/bakkdoor/grit (push)
cho45 https://github.com/cho45/grit (fetch)
cho45 https://github.com/cho45/grit (push)
defunkt https://github.com/defunkt/grit (fetch)
defunkt https://github.com/defunkt/grit (push)
koke git://github.com/koke/grit.git (fetch)
koke git://github.com/koke/grit.git (push)
origin git@github.com:mojombo/grit.git (fetch)
origin git@github.com:mojombo/grit.git (push)
這樣我們可以輕松拉取其中任何一個(gè)用戶的貢獻(xiàn)。 此外,我們大概還會(huì)有某些遠(yuǎn)程倉(cāng)庫(kù)的推送權(quán)限。
注意這些遠(yuǎn)程倉(cāng)庫(kù)使用了不同的協(xié)議。
2. 添加遠(yuǎn)程倉(cāng)庫(kù)
我在之前的章節(jié)中已經(jīng)提到并展示了如何添加遠(yuǎn)程倉(cāng)庫(kù)的示例,不過(guò)這里將告訴你如何明確地做到這一點(diǎn)。
運(yùn)行 git remote add <shortname> <url> 添加一個(gè)新的遠(yuǎn)程 Git 倉(cāng)庫(kù),同時(shí)指定一個(gè)你可以輕松引用的簡(jiǎn)寫:
$ git remote
origin
$ git remote add pb https://github.com/paulboone/ticgit
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)
現(xiàn)在你可以在命令行中使用字符串 pb 來(lái)代替整個(gè) URL。 例如,如果你想拉取 Paul 的倉(cāng)庫(kù)中有但你沒(méi)有的信息,可以運(yùn)行 git fetch pb:
$ git fetch pb
remote: Counting objects: 43, done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 43 (delta 10), reused 31 (delta 5)
Unpacking objects: 100% (43/43), done.
From https://github.com/paulboone/ticgit
* [new branch] master -> pb/master
* [new branch] ticgit -> pb/ticgit
現(xiàn)在 Paul 的 master 分支可以在本地通過(guò)pb/master 訪問(wèn)到 - 你可以將它合并到自己的某個(gè)分支中,或者如果你想要查看它的話,可以檢出一個(gè)指向該點(diǎn)的本地分支。
3. 從遠(yuǎn)程倉(cāng)庫(kù)中抓取與拉取
就如剛才所見(jiàn),從遠(yuǎn)程倉(cāng)庫(kù)中獲得數(shù)據(jù),可以執(zhí)行:
$ git fetch [remote-name]
這個(gè)命令會(huì)訪問(wèn)遠(yuǎn)程倉(cāng)庫(kù),從中拉取所有你還沒(méi)有的數(shù)據(jù)。 執(zhí)行完成后,你將會(huì)擁有那個(gè)遠(yuǎn)程倉(cāng)庫(kù)中所有分支的引用,可以隨時(shí)合并或查看。
如果你使用 clone 命令克隆了一個(gè)倉(cāng)庫(kù),命令會(huì)自動(dòng)將其添加為遠(yuǎn)程倉(cāng)庫(kù)并默認(rèn)以 “origin” 為簡(jiǎn)寫。 所以,git fetch origin 會(huì)抓取克?。ɑ蛏弦淮巫ト。┖笮峦扑偷乃泄ぷ?。 必須注意 git fetch 命令會(huì)將數(shù)據(jù)拉取到你的本地倉(cāng)庫(kù) - 它并不會(huì)自動(dòng)合并或修改你當(dāng)前的工作。 當(dāng)準(zhǔn)備好時(shí)你必須手動(dòng)將其合并入你的工作。
如果你有一個(gè)分支設(shè)置為跟蹤一個(gè)遠(yuǎn)程分支,可以使用 git pull 命令來(lái)自動(dòng)的抓取然后合并遠(yuǎn)程分支到當(dāng)前分支。這對(duì)你來(lái)說(shuō)可能是一個(gè)更簡(jiǎn)單或更舒服的工作流程;默認(rèn)情況下,git clone 命令會(huì)自動(dòng)設(shè)置本地 master 分支跟蹤克隆的遠(yuǎn)程倉(cāng)庫(kù)的 master 分支(或不管是什么名字的默認(rèn)分支)。運(yùn)行 git pull 通常會(huì)從最初克隆的服務(wù)器上抓取數(shù)據(jù)并自動(dòng)嘗試合并到當(dāng)前所在的分支。
4. 推送到遠(yuǎn)程倉(cāng)庫(kù)
當(dāng)你想分享你的項(xiàng)目時(shí),必須將其推送到上游。
這個(gè)命令很簡(jiǎn)單:git push [remote-name] [branch-name] 。
當(dāng)你想要將 master 分支推送到 origin 服務(wù)器時(shí)(再次說(shuō)明,克隆時(shí)通常會(huì)自動(dòng)幫你設(shè)置好那兩個(gè)名字),那么運(yùn)行這個(gè)命令就可以將你所做的備份到服務(wù)器:
$ git push origin master
只有當(dāng)你有所克隆服務(wù)器的寫入權(quán)限,并且之前沒(méi)有人推送過(guò)時(shí),這條命令才能生效。 當(dāng)你和其他人在同一時(shí)間克隆,他們先推送到上游然后你再推送到上游,你的推送就會(huì)毫無(wú)疑問(wèn)地被拒絕。 你必須先將他們的工作拉取下來(lái)并將其合并進(jìn)你的工作后才能推送。
Debug: 解決github push錯(cuò)誤The requested URL returned error: 403 Forbidden while accessing
github push錯(cuò)誤:
error: The requested URL returned error: 403 Forbidden while accessing https://github.com/changdapeng/zhuiyinggu.git/info/refs
解決方案:
修改
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = https://github.com/changdapeng/zhuiyinggu.git
為:
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = https://changdapeng@github.com/changdapeng/zhuiyinggu.git
然后重新push輸入密碼即可
5. 查看遠(yuǎn)程倉(cāng)庫(kù)
如果想要查看某一個(gè)遠(yuǎn)程倉(cāng)庫(kù)的更多信息,可以使用 git remote show [remote-name] 命令。如果想以一個(gè)特定的縮寫名運(yùn)行這個(gè)命令,例 origin ,會(huì)得到像下面類似的信息:
$ git remote show origin
* remote origin
Fetch URL: https://github.com/schacon/ticgit
Push URL: https://github.com/schacon/ticgit
HEAD branch: master
Remote branches:
master tracked
dev-branch tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
它同樣會(huì)列出遠(yuǎn)程倉(cāng)庫(kù)的 URL 與跟蹤分支的信息。 這些信息非常有用,它告訴你正處于 master 分支,并且如果運(yùn)行 git pull,就會(huì)抓取所有的遠(yuǎn)程引用,然后將遠(yuǎn)程 master 分支合并到本地 master 分支。 它也會(huì)列出拉取到的所有遠(yuǎn)程引用。
這是一個(gè)經(jīng)常遇到的簡(jiǎn)單例子。 如果你是 Git 的重度使用者,那么還可以通過(guò) git remote show 看到更多的信息。
$ git remote show origin
* remote origin
URL: https://github.com/my-org/complex-project
Fetch URL: https://github.com/my-org/complex-project
Push URL: https://github.com/my-org/complex-project
HEAD branch: master
Remote branches:
master tracked
dev-branch tracked
markdown-strip tracked
issue-43 new (next fetch will store in remotes/origin)
issue-45 new (next fetch will store in remotes/origin)
refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove)
Local branches configured for 'git pull':
dev-branch merges with remote dev-branch
master merges with remote master
Local refs configured for 'git push':
dev-branch pushes to dev-branch (up to date)
markdown-strip pushes to markdown-strip (up to date)
master pushes to master (up to date)
這個(gè)命令列出了當(dāng)你在特定的分支上執(zhí)行 git push 會(huì)自動(dòng)地推送到哪一個(gè)遠(yuǎn)程分支。 它也同樣地列出了哪些遠(yuǎn)程分支不在你的本地,哪些遠(yuǎn)程分支已經(jīng)從服務(wù)器上移除了,還有當(dāng)你執(zhí)行 git pull 時(shí)哪些分支會(huì)自動(dòng)合并。
6. 遠(yuǎn)程倉(cāng)庫(kù)的移除與重命名
如果想要重命名引用的名字可以運(yùn)行 git remote rename 去修改一個(gè)遠(yuǎn)程倉(cāng)庫(kù)的簡(jiǎn)寫名。
例如,想要將 pb 重命名為 paul ,可以用 git remote rename 這樣做:
$ git remote rename pb paul
$ git remote
origin
paul
值得注意的是這同樣也會(huì)修改你的遠(yuǎn)程分支名字。 那些過(guò)去引用 pb/master 的現(xiàn)在會(huì)引用 paul/master 。
如果因?yàn)橐恍┰蛳胍瞥粋€(gè)遠(yuǎn)程倉(cāng)庫(kù) - 你已經(jīng)從服務(wù)器上搬走了或不再想使用某一個(gè)特定的鏡像了,又或者某一個(gè)貢獻(xiàn)者不再貢獻(xiàn)了 - 可以使用 git remote rm :
$ git remote rm paul
$ git remote
origin
六、 打標(biāo)簽
像其他版本控制系統(tǒng)(VCS)一樣,Git 可以給歷史中的某一個(gè)提交打上標(biāo)簽,以示重要。 比較有代表性的是人們會(huì)使用這個(gè)功能來(lái)標(biāo)記發(fā)布結(jié)點(diǎn)(v1.0 等等)。
1. 列出標(biāo)簽
在 Git 中列出已有的標(biāo)簽是非常簡(jiǎn)單直觀的。 只需要輸入 git tag:
$ git tag
v0.1
v1.3
這個(gè)命令以字母順序列出標(biāo)簽;但是它們出現(xiàn)的順序并不重要。
你也可以使用特定的模式查找標(biāo)簽。 例如,Git 自身的源代碼倉(cāng)庫(kù)包含標(biāo)簽的數(shù)量超過(guò) 500 個(gè)。 如果只對(duì) 1.8.5 系列感興趣,可以運(yùn)行:
$ git tag -l 'v1.8.5*'
v1.8.5
v1.8.5-rc0
v1.8.5-rc1
v1.8.5-rc2
v1.8.5-rc3
v1.8.5.1
v1.8.5.2
v1.8.5.3
v1.8.5.4
v1.8.5.5
2. 創(chuàng)建標(biāo)簽
Git 使用兩種主要類型的標(biāo)簽:輕量標(biāo)簽(lightweight) 與 附注標(biāo)簽(annotated)。
一個(gè)輕量標(biāo)簽很像一個(gè)不會(huì)改變的分支 - 它只是一個(gè)特定提交的引用。
然而,附注標(biāo)簽是存儲(chǔ)在 Git 數(shù)據(jù)庫(kù)中的一個(gè)完整對(duì)象。 它們是可以被校驗(yàn)的;其中包含打標(biāo)簽者的名字、電子郵件地址、日期時(shí)間;還有一個(gè)標(biāo)簽信息;并且可以使用 GNU Privacy Guard (GPG)簽名與驗(yàn)證。 通常建議創(chuàng)建附注標(biāo)簽,這樣你可以擁有以上所有信息;但是如果你只是想用一個(gè)臨時(shí)的標(biāo)簽,或者因?yàn)槟承┰虿幌胍4婺切┬畔?,輕量標(biāo)簽也是可用的。
2.1 附注標(biāo)簽
在 Git 中創(chuàng)建一個(gè)附注標(biāo)簽是很簡(jiǎn)單的。 最簡(jiǎn)單的方式是當(dāng)你在運(yùn)行 tag 命令時(shí)指定 -a 選項(xiàng):
$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4
-m 選項(xiàng)指定了一條將會(huì)存儲(chǔ)在標(biāo)簽中的信息。 如果沒(méi)有為附注標(biāo)簽指定一條信息,Git 會(huì)運(yùn)行編輯器要求你輸入信息。
通過(guò)使用 git show 命令可以看到標(biāo)簽信息與對(duì)應(yīng)的提交信息:
$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
輸出顯示了打標(biāo)簽者的信息、打標(biāo)簽的日期時(shí)間、附注信息,然后顯示具體的提交信息。
2.2 輕量標(biāo)簽
另一種給提交打標(biāo)簽的方式是使用輕量標(biāo)簽。 輕量標(biāo)簽本質(zhì)上是將提交校驗(yàn)和存儲(chǔ)到一個(gè)文件中 - 沒(méi)有保存任何其他信息。 創(chuàng)建輕量標(biāo)簽,不需要使用 -a、-s 或 -m 選項(xiàng),只需要提供標(biāo)簽名字:
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
這時(shí),如果在標(biāo)簽上運(yùn)行g(shù)it show,你不會(huì)看到額外的標(biāo)簽信息。命令只會(huì)顯示出提交信息:
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
3. 后期打標(biāo)簽
你也可以對(duì)過(guò)去的提交打標(biāo)簽。 假設(shè)提交歷史是這樣的:
$ git log --pretty=oneline
15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment'
a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support
0d52aaab4479697da7686c15f77a3d64d9165190 one more thing
6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment'
0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function
4682c3261057305bdd616e23b64b0857d832627b added a todo file
166ae0c4d3f420721acbb115cc33848dfcc2121a started write support
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
現(xiàn)在,假設(shè)在 v1.2 時(shí)你忘記給項(xiàng)目打標(biāo)簽,也就是在 “updated rakefile” 提交。 你可以在之后補(bǔ)上標(biāo)簽。 要在那個(gè)提交上打標(biāo)簽,你需要在命令的末尾指定提交的校驗(yàn)和(或部分校驗(yàn)和):
$ git tag -a v1.2 9fceb02
可以看到你已經(jīng)在那次提交上打上標(biāo)簽了:
$ git tag
v0.1
v1.2
v1.3
v1.4
v1.4-lw
v1.5
$ git show v1.2
tag v1.2
Tagger: Scott Chacon <schacon@gee-mail.com>
Date: Mon Feb 9 15:32:16 2009 -0800
version 1.2
commit 9fceb02d0ae598e95dc970b74767f19372d61af8
Author: Magnus Chacon <mchacon@gee-mail.com>
Date: Sun Apr 27 20:43:35 2008 -0700
updated rakefile
...
6. 共享標(biāo)簽
默認(rèn)情況下,git push命令并不會(huì)傳送標(biāo)簽到遠(yuǎn)程倉(cāng)庫(kù)服務(wù)器上。在創(chuàng)建完標(biāo)簽后你必須顯式地推送標(biāo)簽到共享服務(wù)器上。這個(gè)過(guò)程就像共享遠(yuǎn)程分支一樣 - 你可以運(yùn)行 git push origin [tagname] 。
$ git push origin v1.5
Counting objects: 14, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done.
Total 14 (delta 3), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new tag] v1.5 -> v1.5
如果想要一次性推送很多標(biāo)簽,也可以使用帶有 --tags 選項(xiàng)的 git push 命令。 這將會(huì)把所有不在遠(yuǎn)程倉(cāng)庫(kù)服務(wù)器上的標(biāo)簽全部傳送到那里。
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new tag] v1.4 -> v1.4
* [new tag] v1.4-lw -> v1.4-lw
現(xiàn)在,當(dāng)其他人從倉(cāng)庫(kù)中克隆或拉取,他們也能得到你的那些標(biāo)簽。
7. 檢出標(biāo)簽
在Git中你并不能真的檢出一個(gè)標(biāo)簽,因?yàn)樗鼈儾⒉荒芟穹种б粯觼?lái)回移動(dòng)。 如果你想要工作目錄與倉(cāng)庫(kù)中特定的標(biāo)簽版本完全一樣,可以使用 git checkout -b [branchname] [tagname] 在特定的標(biāo)簽上創(chuàng)建一個(gè)新分支:
$ git checkout -b version2 v2.0.0
Switched to a new branch 'version2'
當(dāng)然,如果在這之后又進(jìn)行了一次提交,version2 分支會(huì)因?yàn)楦膭?dòng)向前移動(dòng)了,那么 version2 分支就會(huì)和 v2.0.0 標(biāo)簽稍微有些不同,這時(shí)就應(yīng)該當(dāng)心了。
七、 Git 別名
Git 并不會(huì)在你輸入部分命令時(shí)自動(dòng)推斷出你想要的命令。
如果不想每次都輸入完整的 Git 命令,可以通過(guò) git config 文件來(lái)輕松地為每一個(gè)命令設(shè)置一個(gè)別名。
這里有一些例子你可以試試:
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
這意味著,當(dāng)要輸入 git commit 時(shí),只需要輸入 git ci。 隨著你繼續(xù)不斷地使用 Git,可能也會(huì)經(jīng)常使用其他命令,所以創(chuàng)建別名時(shí)不要猶豫。
在創(chuàng)建你認(rèn)為應(yīng)該存在的命令時(shí)這個(gè)技術(shù)會(huì)很有用。 例如,為了解決取消暫存文件的易用性問(wèn)題,可以向 Git 中添加你自己的取消暫存別名:
$ git config --global alias.unstage 'reset HEAD --'
這會(huì)使下面的兩個(gè)命令等價(jià):
$ git unstage fileA
$ git reset HEAD -- fileA
這樣看起來(lái)更清楚一些。 通常也會(huì)添加一個(gè) last 命令,像這樣:
$ git config --global alias.last 'log -1 HEAD'
這樣,可以輕松地看到最后一次提交:
$ git last
commit 66938dae3329c7aebe598c2246a8e6af90d04646
Author: Josh Goebel <dreamer3@example.com>
Date: Tue Aug 26 19:48:51 2008 +0800
test for current head
Signed-off-by: Scott Chacon <schacon@example.com>
可以看出,Git 只是簡(jiǎn)單地將別名替換為對(duì)應(yīng)的命令。 然而,你可能想要執(zhí)行外部命令,而不是一個(gè) Git 子命令。 如果是那樣的話,可以在命令前面加入 ! 符號(hào)。 如果你自己要寫一些與 Git 倉(cāng)庫(kù)協(xié)作的工具的話,那會(huì)很有用。 我們現(xiàn)在演示將 git visual 定義為 gitk 的別名:
$ git config --global alias.visual '!gitk'
Git使用手冊(cè)系列教程:
Git使用手冊(cè)1—— Git 簡(jiǎn)介與安裝配置
Git使用手冊(cè)2 —— 基礎(chǔ)操作(上)
Git使用手冊(cè)2 —— 基礎(chǔ)操作(中)
Git使用手冊(cè)2 —— 基礎(chǔ)操作(下)
Git使用手冊(cè)3 —— Git 分支(上)
Git使用手冊(cè)3 —— Git 分支(下)
本教程參照Git的官方文檔編寫,如有不明與錯(cuò)誤之處,敬請(qǐng)指正。