鍍金池/ 教程/ Java/ <span class="docs"> </span> 分享與更新項(xiàng)目
<span class="docs"> <a target="new" href="http://git-
<span class="docs"> </span> 分享與更新項(xiàng)目
Git 手冊(cè)簡(jiǎn)介
<span class="docs"> </span> 分支與合并
獲取與創(chuàng)建項(xiàng)目
<span class="docs"> </span> 基本快照

<span class="docs"> </span> 分享與更新項(xiàng)目

Git 并不像 Subversion 那樣有個(gè)中心服務(wù)器。 目前為止所有的命令都是本地執(zhí)行的,更新的知識(shí)本地的數(shù)據(jù)庫(kù)。 要通過(guò) Git 與其他開發(fā)者合作,你需要將數(shù)據(jù)放到一臺(tái)其他開發(fā)者能夠連接的服務(wù)器上。 Git 實(shí)現(xiàn)此流程的方式是將你的數(shù)據(jù)與另一個(gè)倉(cāng)庫(kù)同步。在服務(wù)器與客戶端之間并沒(méi)有實(shí)質(zhì)的區(qū)別 —— Git 倉(cāng)庫(kù)就是 Git 倉(cāng)庫(kù),你可以很容易地在兩者之間同步。

一旦你有了個(gè) Git 倉(cāng)庫(kù),不管它是在你自己的服務(wù)器上,或者是由 GitHub 之類的地方提供, 你都可以告訴 Git 推送你擁有的遠(yuǎn)端倉(cāng)庫(kù)還沒(méi)有的數(shù)據(jù),或者叫 Git 從別的倉(cāng)庫(kù)把差別取過(guò)來(lái)。

聯(lián)網(wǎng)的時(shí)候你可以隨時(shí)做這個(gè),它并不需要對(duì)應(yīng)一個(gè) commit 或者別的什么。 一般你會(huì)本地提交幾次,然后從你的項(xiàng)目克隆自的線上的共享倉(cāng)庫(kù)提取數(shù)據(jù)以保持最新,將新完成的合并到你完成的工作中去,然后推送你的改動(dòng)會(huì)服務(wù)器。

簡(jiǎn)而言之 使用 git fetch 更新你的項(xiàng)目,使用 git push 分享你的改動(dòng)。 你可以用 git remote 管理你的遠(yuǎn)程倉(cāng)庫(kù)。

git remote 羅列、添加和刪除遠(yuǎn)端倉(cāng)庫(kù)別名

不像中心化的版本控制系統(tǒng)(客戶端與服務(wù)端很不一樣),Git 倉(cāng)庫(kù)基本上都是一致的,并且并可以同步他們。 這使得擁有多個(gè)遠(yuǎn)端倉(cāng)庫(kù)變得容易 —— 你可以擁有一些只讀的倉(cāng)庫(kù),另外的一些也可寫的倉(cāng)庫(kù)。

當(dāng)你需要與遠(yuǎn)端倉(cāng)庫(kù)同步的時(shí)候,不需要使用它詳細(xì)的鏈接。Git 儲(chǔ)存了你感興趣的遠(yuǎn)端倉(cāng)庫(kù)的鏈接的別名或者昵稱。 你可以使用 git remote 命令管理這個(gè)遠(yuǎn)端倉(cāng)庫(kù)列表。

git remote 列出遠(yuǎn)端別名

如果沒(méi)有任何參數(shù),Git 會(huì)列出它存儲(chǔ)的遠(yuǎn)端倉(cāng)庫(kù)別名了事。默認(rèn)情況下,如果你的項(xiàng)目是克隆的(與本地創(chuàng)建一個(gè)新的相反), Git 會(huì)自動(dòng)將你的項(xiàng)目克隆自的倉(cāng)庫(kù)添加到列表中,并取名“origin”。 如果你執(zhí)行時(shí)加上 -v 參數(shù),你還可以看到每個(gè)別名的實(shí)際鏈接地址。

$ git remote
origin
$ git remote -v
origin  git@github.com:github/git-reference.git (fetch)
origin  git@github.com:github/git-reference.git (push)

在此你看到了該鏈接兩次,是因?yàn)?Git 允許你為每個(gè)遠(yuǎn)端倉(cāng)庫(kù)添加不同的推送與獲取的鏈接,以備你讀寫時(shí)希望使用不同的協(xié)議。

git remote add 為你的項(xiàng)目添加一個(gè)新的遠(yuǎn)端倉(cāng)庫(kù)

如果你希望分享一個(gè)本地創(chuàng)建的倉(cāng)庫(kù),或者你想要獲取別人的倉(cāng)庫(kù)中的貢獻(xiàn) —— 如果你想要以任何方式與一個(gè)新倉(cāng)庫(kù)溝通,最簡(jiǎn)單的方式通常就是把它添加為一個(gè)遠(yuǎn)端倉(cāng)庫(kù)。 執(zhí)行 git remote add [alias] [url] 就可以。 此命令將 [url][alias] 的別名添加為本地的遠(yuǎn)端倉(cāng)庫(kù)。

例如,假設(shè)我們想要與整個(gè)世界分享我們的 Hello World 程序。 我們可以在一臺(tái)服務(wù)器上創(chuàng)建一個(gè)新倉(cāng)庫(kù)(我以 GitHub 為例子)。 它應(yīng)該會(huì)給你一個(gè)鏈接,在這里就是“git@github.com:schacon/hw.git”。 要把它添加到我們的項(xiàng)目以便我們推送以及獲取更新,我們可以這樣:

$ git remote
$ git remote add github git@github.com:schacon/hw.git
$ git remote -v
github  git@github.com:schacon/hw.git (fetch)
github  git@github.com:schacon/hw.git (push)

像分支的命名一樣,遠(yuǎn)端倉(cāng)庫(kù)的別名是強(qiáng)制的 —— 就像“master”,沒(méi)有特別意義,但它廣為使用, 因?yàn)?git init 默認(rèn)用它;“origin”經(jīng)常被用作遠(yuǎn)端倉(cāng)庫(kù)別名,就因?yàn)?git clone 默認(rèn)用它作為克隆自的鏈接的別名。此例中,我決定給我的遠(yuǎn)端倉(cāng)庫(kù)取名“github”,但我叫它隨便什么都可以。

git remote rm 刪除現(xiàn)存的某個(gè)別名

Git addeth and Git taketh away. 如果你需要?jiǎng)h除一個(gè)遠(yuǎn)端 —— 不再需要它了、項(xiàng)目已經(jīng)沒(méi)了,等等 —— 你可以使用 git remote rm [alias] 把它刪掉。

$ git remote -v
github  git@github.com:schacon/hw.git (fetch)
github  git@github.com:schacon/hw.git (push)
$ git remote add origin git://github.com/pjhyett/hw.git
$ git remote -v
github  git@github.com:schacon/hw.git (fetch)
github  git@github.com:schacon/hw.git (push)
origin  git://github.com/pjhyett/hw.git (fetch)
origin  git://github.com/pjhyett/hw.git (push)
$ git remote rm origin
$ git remote -v
github  git@github.com:schacon/hw.git (fetch)
github  git@github.com:schacon/hw.git (push)

簡(jiǎn)而言之 你可以用 git remote 列出你的遠(yuǎn)端倉(cāng)庫(kù)和那些倉(cāng)庫(kù)的鏈接。 你可以使用 git remote add 添加新的遠(yuǎn)端倉(cāng)庫(kù),用 git remote rm 刪掉已存在的那些。

git fetch 從遠(yuǎn)端倉(cāng)庫(kù)下載新分支與數(shù)據(jù)


git pull 從遠(yuǎn)端倉(cāng)庫(kù)提取數(shù)據(jù)并嘗試合并到當(dāng)前分支

Git 有兩個(gè)命令用來(lái)從某一遠(yuǎn)端倉(cāng)庫(kù)更新。 git fetch 會(huì)使你與另一倉(cāng)庫(kù)同步,提取你本地所沒(méi)有的數(shù)據(jù),為你在同步時(shí)的該遠(yuǎn)端的每一分支提供書簽。 這些分支被叫做“遠(yuǎn)端分支”,除了 Git 不允許你檢出(切換到該分支)之外,跟本地分支沒(méi)區(qū)別 —— 你可以將它們合并到當(dāng)前分支,與其他分支作比較差異,查看那些分支的歷史日志,等等。同步之后你就可以在本地操作這些。

第二個(gè)會(huì)從遠(yuǎn)端服務(wù)器提取新數(shù)據(jù)的命令是 git pull。 基本上,該命令就是在 git fetch 之后緊接著 git merge 遠(yuǎn)端分支到你所在的任意分支。 我個(gè)人不太喜歡這命令 —— 我更喜歡 fetchmerge 分開來(lái)做。少點(diǎn)魔法,少點(diǎn)問(wèn)題。 不過(guò),如果你喜歡這主意,你可以看一下 git pull[官方文檔]()

假設(shè)你配置好了一個(gè)遠(yuǎn)端,并且你想要提取更新,你可以首先執(zhí)行 git fetch [alias] 告訴 Git 去獲取它有你沒(méi)有的數(shù)據(jù),然后你可以執(zhí)行 git merge [alias]/[branch] 以將服務(wù)器上的任何更新(假設(shè)有人這時(shí)候推送到服務(wù)器了)合并到你的當(dāng)前分支。 那么,如果我是與兩三個(gè)其他人合作 Hello World 項(xiàng)目,并且想要將我最近連接之后的所有改動(dòng)拿過(guò)來(lái),我可以這么做:

$ git fetch github
remote: Counting objects: 4006, done.
remote: Compressing objects: 100% (1322/1322), done.
remote: Total 2783 (delta 1526), reused 2587 (delta 1387)
Receiving objects: 100% (2783/2783), 1.23 MiB | 10 KiB/s, done.
Resolving deltas: 100% (1526/1526), completed with 387 local objects.
From github.com:schacon/hw
   8e29b09..c7c5a10  master     -> github/master
   0709fdc..d4ccf73  c-langs    -> github/c-langs
   6684f82..ae06d2b  java       -> github/java
 * [new branch]      ada        -> github/ada
 * [new branch]      lisp       -> github/lisp

可以看到自從上一次與遠(yuǎn)端倉(cāng)庫(kù)同步以后,又新贈(zèng)或更新了五個(gè)分支。 “ada”與“l(fā)isp”分支是新的,而“master”、“clang”與“java”分支則被更新了。 在此例中,我的團(tuán)隊(duì)在合并入主分支之前,將提議的更新推送到遠(yuǎn)端分支以審核。

你可以看到 Git 做的映射。遠(yuǎn)端倉(cāng)庫(kù)的主分支成為了本地的一個(gè)叫做“github/master”的分支。 這樣我就可以執(zhí)行 git merge github/master 將遠(yuǎn)端的主分支和并入我的本地主分支。 或者,我可以 git log github/master ^master 看看該分支上的新提交。 如果你的遠(yuǎn)端倉(cāng)庫(kù)叫做“origin”,那遠(yuǎn)端主分支就會(huì)叫做 origin/master。幾乎所有能在本地分支上執(zhí)行的命令都可以在遠(yuǎn)端分支上用。

如果你有多個(gè)遠(yuǎn)端倉(cāng)庫(kù),你可以執(zhí)行 git fetch [alias] 提取特定的遠(yuǎn)端倉(cāng)庫(kù), 或者執(zhí)行 git fetch --all 告訴 Git 同步所有的遠(yuǎn)端倉(cāng)庫(kù)。

簡(jiǎn)而言之 執(zhí)行 git fetch [alias] 來(lái)將你的倉(cāng)庫(kù)與遠(yuǎn)端倉(cāng)庫(kù)同步,提取所有它獨(dú)有的數(shù)據(jù)到本地分支以合并或者怎樣。

git push 推送你的新分支與數(shù)據(jù)到某個(gè)遠(yuǎn)端倉(cāng)庫(kù)

想要與他人分享你牛鼻的提交,你需要將改動(dòng)推送到遠(yuǎn)端倉(cāng)庫(kù)。 執(zhí)行 git push [alias] [branch],就會(huì)將你的 [branch] 分支推送成為 [alias] 遠(yuǎn)端上的 [branch] 分支。 讓我們?cè)囋囃扑臀覀兊闹鞣种У较惹疤砑拥摹癵ithub”遠(yuǎn)端倉(cāng)庫(kù)上去。

$ git push github master
Counting objects: 25, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (25/25), done.
Writing objects: 100% (25/25), 2.43 KiB, done.
Total 25 (delta 4), reused 0 (delta 0)
To git@github.com:schacon/hw.git
 * [new branch]      master -> master

挺簡(jiǎn)單?,F(xiàn)在如果有人從該倉(cāng)庫(kù)克隆,他會(huì)得到我提交的完完全全的一份歷史記錄了。

如果有個(gè)像之前創(chuàng)建的“erlang”分支那樣的主題分支,想只分享這個(gè),該怎么辦呢?你可以相應(yīng)的只推送該分支。

$ git push github erlang
Counting objects: 7, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 652 bytes, done.
Total 6 (delta 1), reused 0 (delta 0)
To git@github.com:schacon/hw.git
 * [new branch]      erlang -> erlang

現(xiàn)在當(dāng)人們從該倉(cāng)庫(kù)克隆時(shí),他們就會(huì)得到一個(gè)“erlang”分支以查閱、合并。 用這種方式,你可以推送任何分支到任何你有寫權(quán)限的倉(cāng)庫(kù)。 如果你的分支已經(jīng)在該倉(cāng)庫(kù)中了,它會(huì)試著去更新,如果它不再,Git 會(huì)把它加上。

最后一個(gè)當(dāng)你推送到遠(yuǎn)端分支時(shí)會(huì)碰到的主要問(wèn)題是,其他人在此期間也推送了的情況。 如果你和另一個(gè)開發(fā)者同時(shí)克隆了,又都有提交,那么當(dāng)她推送后你也想推送時(shí),默認(rèn)情況下 Git 不會(huì)讓你覆蓋她的改動(dòng)。 相反的,它會(huì)在你試圖推送的分支上執(zhí)行 git log,確定它能夠在你的推送分支的歷史記錄中看到服務(wù)器分支的當(dāng)前進(jìn)度。 如果它在在你的歷史記錄中看不到,它就會(huì)下結(jié)論說(shuō)你過(guò)時(shí)了,并打回你的推送。 你需要正式提取、合并,然后再次推送 —— 以確定你把她的改動(dòng)也考慮在內(nèi)了。

當(dāng)你試圖推送到某個(gè)以被更新的遠(yuǎn)端分支時(shí),會(huì)出現(xiàn)下面這種情況:

$ git push github master
To git@github.com:schacon/hw.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:schacon/hw.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

你可以修正這個(gè)問(wèn)題。執(zhí)行 git fetch github; git merge github/master,然后再推送

簡(jiǎn)而言之 執(zhí)行 git push [alias] [branch] 將你的本地改動(dòng)推送到遠(yuǎn)端倉(cāng)庫(kù)。 如果可以的話,它會(huì)依據(jù)你的 [branch] 的樣子,推送到遠(yuǎn)端的 [branch] 去。 如果在你上次提取、合并之后,另有人推送了,Git 服務(wù)器會(huì)拒絕你的推送,知道你是最新的為止。