Git -- 版本控制
git就是一個(gè)版本控制的工具。我們設(shè)置好git之后就可以用它來記錄一個(gè)文件或者是若干個(gè)文件的變化了苏遥。
在將來文件變化后暂雹,若是要查看文件的版本修訂蕴忆,那就可以通過git方便的實(shí)現(xiàn)這一點(diǎn)茧跋。
在寫論文的時(shí)候慰丛,往往會(huì)經(jīng)過很多次的修改。而不同的修改版本瘾杭,會(huì)在windows系統(tǒng)下占用很多個(gè)文件夾。相信這是很多人的經(jīng)驗(yàn)了哪亿。但是如果使用git粥烁,或者是其他的版本控制的系統(tǒng),就可以用簡單的操作來記錄文件的不同更新蝇棉。
這種把不同的版本儲(chǔ)存在本地的備份被稱為本地版本控制讨阻。但是這種情況下,只有自己能夠參與到項(xiàng)目之中篡殷。而現(xiàn)在的項(xiàng)目開發(fā)钝吮,往往有很多人同時(shí)進(jìn)行工作。項(xiàng)目需要分工,而其他人的版本控制無法聯(lián)網(wǎng)同時(shí)進(jìn)行奇瘦。這就讓中心化的版本控制產(chǎn)生了棘催。
中心化的版本控制其實(shí)滿足了不同的人同時(shí)進(jìn)行開發(fā)的需求。但是有一個(gè)致命的弱點(diǎn)耳标,就是如果服務(wù)器宕機(jī)醇坝,那么所有人的工作都不得不停止下來。
于是分布式版本控制系統(tǒng)(Distributed Version Control System次坡,簡稱 DVCS)面世了呼猪。 在這類系統(tǒng)中,像 Git砸琅、Mercurial宋距、Bazaar 以及 Darcs 等,客戶端并不只提取最新版本的文件快照症脂, 而是把代碼倉庫完整地鏡像下來乡革,包括完整的歷史記錄。 這么一來摊腋,任何一處協(xié)同工作用的服務(wù)器發(fā)生故障沸版,事后都可以用任何一個(gè)鏡像出來的本地倉庫恢復(fù)。 因?yàn)槊恳淮蔚目寺〔僮餍苏簦瑢?shí)際上都是一次對代碼倉庫的完整備份视粮。
而這類系統(tǒng)可以通過指定不同的倉庫進(jìn)行交互。而開發(fā)者也可以在同一個(gè)項(xiàng)目中橙凳,分別和不同的工作小組的人一起互動(dòng)協(xié)作蕾殴。
三種狀態(tài)
現(xiàn)在請注意,如果你希望后面的學(xué)習(xí)更順利岛啸,請記住下面這些關(guān)于 Git 的概念钓觉。 Git 有三種狀態(tài),你的文件可能處于其中之一: 已提交(committed)坚踩、已修改(modified) 和 已暫存(staged)荡灾。
- 已修改表示修改了文件,但還沒保存到數(shù)據(jù)庫中瞬铸。
- 已暫存表示對一個(gè)已修改文件的當(dāng)前版本做了標(biāo)記批幌,使之包含在下次提交的快照中。
- 已提交表示數(shù)據(jù)已經(jīng)安全地保存在本地?cái)?shù)據(jù)庫中嗓节。
這會(huì)讓我們的 Git 項(xiàng)目擁有三個(gè)階段:工作區(qū)荧缘、暫存區(qū)以及 Git 目錄。
使用git
$ git init
首先需要對git倉庫進(jìn)行初始化拦宣。我們使用這個(gè)命令截粗,就可以把一個(gè)項(xiàng)目文件夾化為git倉庫信姓。
該命令將創(chuàng)建一個(gè)名為 .git 的子目錄,這個(gè)子目錄含有你初始化的 Git 倉庫中所有的必須文件绸罗,這些文件是 Git 倉庫的骨干意推。 但是,在這個(gè)時(shí)候从诲,我們僅僅是做了一個(gè)初始化的操作左痢,你的項(xiàng)目里的文件還沒有被跟蹤。
如果是需要從云端克隆現(xiàn)有的項(xiàng)目系洛,可以使用該命令:
$ git clone https://github.com/libgit2/libgit2
檢查當(dāng)前文件狀態(tài)
可以用 git status 命令查看哪些文件處于什么狀態(tài)俊性。 如果在克隆倉庫后立即使用此命令,會(huì)看到類似這樣的輸出:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
跟蹤新文件
使用命令 git add 開始跟蹤一個(gè)文件描扯。 所以定页,要跟蹤 README 文件,運(yùn)行:
$ git add README
此時(shí)再運(yùn)行 git status 命令绽诚,會(huì)看到 README 文件已被跟蹤典徊,并處于暫存狀態(tài):
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: README
暫存已修改的文件
現(xiàn)在我們來修改一個(gè)已被跟蹤的文件。 如果你修改了一個(gè)名為 CONTRIBUTING.md 的已被跟蹤的文件恩够,然后運(yùn)行 git status 命令卒落,會(huì)看到下面內(nèi)容:
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
忽略文件
一般我們總會(huì)有些文件無需納入 Git 的管理,也不希望它們總出現(xiàn)在未跟蹤文件列表蜂桶。 通常都是些自動(dòng)生成的文件儡毕,比如日志文件,或者編譯過程中創(chuàng)建的臨時(shí)文件等扑媚。 在這種情況下腰湾,我們可以創(chuàng)建一個(gè)名為 .gitignore 的文件,列出要忽略的文件的模式疆股。 來看一個(gè)實(shí)際的 .gitignore 例子:
$ cat .gitignore
*.[oa]
*~
提交更新
現(xiàn)在的暫存區(qū)已經(jīng)準(zhǔn)備就緒费坊,可以提交了。 在此之前旬痹,請務(wù)必確認(rèn)還有什么已修改或新建的文件還沒有 git add 過附井, 否則提交的時(shí)候不會(huì)記錄這些尚未暫存的變化。 這些已修改但未暫存的文件只會(huì)保留在本地磁盤唱凯。 所以羡忘,每次準(zhǔn)備提交前,先用 git status 看下磕昼,你所需要的文件是不是都已暫存起來了, 然后再運(yùn)行提交命令 git commit:
$ git commit
這樣會(huì)啟動(dòng)你選擇的文本編輯器來輸入提交說明节猿。
查看提交歷史
在提交了若干更新票从,又或者克隆了某個(gè)項(xiàng)目之后漫雕,你也許想回顧下提交歷史。 完成這個(gè)任務(wù)最簡單而又有效的工具是 git log 命令峰鄙。
$ git log
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 16:40:33 2008 -0700
removed unnecessary test
commit a11bef06a3f659402fe7563abf99ad00de2209e6
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sat Mar 15 10:31:28 2008 -0700
first commit
撤消操作
在任何一個(gè)階段浸间,你都有可能想要撤消某些操作。 這里吟榴,我們將會(huì)學(xué)習(xí)幾個(gè)撤消你所做修改的基本工具魁蒜。 注意,有些撤消操作是不可逆的吩翻。 這是在使用 Git 的過程中兜看,會(huì)因?yàn)椴僮魇д`而導(dǎo)致之前的工作丟失的少有的幾個(gè)地方之一。
有時(shí)候我們提交完了才發(fā)現(xiàn)漏掉了幾個(gè)文件沒有添加狭瞎,或者提交信息寫錯(cuò)了细移。 此時(shí),可以運(yùn)行帶有 --amend 選項(xiàng)的提交命令來重新提交:
$ git commit --amend
取消暫存的文件
接下來的兩個(gè)小節(jié)演示如何操作暫存區(qū)和工作目錄中已修改的文件熊锭。 這些命令在修改文件狀態(tài)的同時(shí)弧轧,也會(huì)提示如何撤消操作。 例如碗殷,你已經(jīng)修改了兩個(gè)文件并且想要將它們作為兩次獨(dú)立的修改提交精绎, 但是卻意外地輸入 git add * 暫存了它們兩個(gè)。如何只取消暫存兩個(gè)中的一個(gè)呢锌妻? git status 命令提示了你:
$ git add *
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
modified: CONTRIBUTING.md
撤消對文件的修改
如果你并不想保留對 CONTRIBUTING.md 文件的修改怎么辦代乃? 你該如何方便地撤消修改——將它還原成上次提交時(shí)的樣子(或者剛克隆完的樣子,或者剛把它放入工作目錄時(shí)的樣子)从祝? 幸運(yùn)的是襟己,git status 也告訴了你應(yīng)該如何做。 在最后一個(gè)例子中牍陌,未暫存區(qū)域是這樣:
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md
它非常清楚地告訴了你如何撤消之前所做的修改擎浴。 讓我們來按照提示執(zhí)行:
$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README
可以看到那些修改已經(jīng)被撤消了。
查看遠(yuǎn)程倉庫
如果想查看你已經(jīng)配置的遠(yuǎn)程倉庫服務(wù)器毒涧,可以運(yùn)行 git remote 命令贮预。 它會(huì)列出你指定的每一個(gè)遠(yuǎn)程服務(wù)器的簡寫。 如果你已經(jīng)克隆了自己的倉庫契讲,那么至少應(yīng)該能看到 origin ——這是 Git 給你克隆的倉庫服務(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)程倉庫使用的 Git 保存的簡寫與其對應(yīng)的 URL。
$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
添加遠(yuǎn)程倉庫
我們在之前的章節(jié)中已經(jīng)提到并展示了 git clone 命令是如何自行添加遠(yuǎn)程倉庫的捡偏, 不過這里將告訴你如何自己來添加它唤冈。 運(yùn)行 git remote add 添加一個(gè)新的遠(yuǎn)程 Git 倉庫,同時(shí)指定一個(gè)方便使用的簡寫:
$ 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)
從遠(yuǎn)程倉庫中抓取與拉取
就如剛才所見银伟,從遠(yuǎn)程倉庫中獲得數(shù)據(jù)你虹,可以執(zhí)行:
$ git fetch <remote>
這個(gè)命令會(huì)訪問遠(yuǎn)程倉庫绘搞,從中拉取所有你還沒有的數(shù)據(jù)。 執(zhí)行完成后傅物,你將會(huì)擁有那個(gè)遠(yuǎn)程倉庫中所有分支的引用夯辖,可以隨時(shí)合并或查看。
如果你使用 clone 命令克隆了一個(gè)倉庫董饰,命令會(huì)自動(dòng)將其添加為遠(yuǎn)程倉庫并默認(rèn)以 “origin” 為簡寫蒿褂。 所以,git fetch origin 會(huì)抓取克伦湓荨(或上一次抓茸乃ā)后新推送的所有工作。 必須注意 git fetch 命令只會(huì)將數(shù)據(jù)下載到你的本地倉庫——它并不會(huì)自動(dòng)合并或修改你當(dāng)前的工作介却。 當(dāng)準(zhǔn)備好時(shí)你必須手動(dòng)將其合并入你的工作谴供。
如果你的當(dāng)前分支設(shè)置了跟蹤遠(yuǎn)程分支(閱讀下一節(jié)和 Git 分支 了解更多信息), 那么可以用 git pull 命令來自動(dòng)抓取后合并該遠(yuǎn)程分支到當(dāng)前分支齿坷。 這或許是個(gè)更加簡單舒服的工作流程桂肌。默認(rèn)情況下,git clone 命令會(huì)自動(dòng)設(shè)置本地 master 分支跟蹤克隆的遠(yuǎn)程倉庫的 master 分支(或其它名字的默認(rèn)分支)永淌。 運(yùn)行 git pull 通常會(huì)從最初克隆的服務(wù)器上抓取數(shù)據(jù)并自動(dòng)嘗試合并到當(dāng)前所在的分支崎场。
推送到遠(yuǎn)程倉庫
當(dāng)你想分享你的項(xiàng)目時(shí),必須將其推送到上游遂蛀。 這個(gè)命令很簡單:git push谭跨。 當(dāng)你想要將 master 分支推送到 origin 服務(wù)器時(shí)(再次說明,克隆時(shí)通常會(huì)自動(dòng)幫你設(shè)置好那兩個(gè)名字)李滴, 那么運(yùn)行這個(gè)命令就可以將你所做的備份到服務(wù)器:
$ git push origin master
只有當(dāng)你有所克隆服務(wù)器的寫入權(quán)限螃宙,并且之前沒有人推送過時(shí),這條命令才能生效所坯。 當(dāng)你和其他人在同一時(shí)間克隆谆扎,他們先推送到上游然后你再推送到上游,你的推送就會(huì)毫無疑問地被拒絕芹助。 你必須先抓取他們的工作并將其合并進(jìn)你的工作后才能推送堂湖。 閱讀 Git 分支 了解如何推送到遠(yuǎn)程倉庫服務(wù)器的詳細(xì)信息。
分支創(chuàng)建
Git 是怎么創(chuàng)建新分支的呢状土? 很簡單无蜂,它只是為你創(chuàng)建了一個(gè)可以移動(dòng)的新的指針。 比如蒙谓,創(chuàng)建一個(gè) testing 分支斥季, 你需要使用 git branch 命令:
$ git branch testing
分支切換
要切換到一個(gè)已存在的分支,你需要使用 git checkout 命令累驮。 我們現(xiàn)在切換到新創(chuàng)建的 testing 分支去:
$ git checkout testing
這樣 HEAD 就指向 testing 分支了泻肯。
分支管理
現(xiàn)在已經(jīng)創(chuàng)建渊迁、合并慰照、刪除了一些分支灶挟,讓我們看看一些常用的分支管理工具。
git branch 命令不只是可以創(chuàng)建與刪除分支毒租。 如果不加任何參數(shù)運(yùn)行它稚铣,會(huì)得到當(dāng)前所有分支的一個(gè)列表:
$ git branch
iss53
* master
testing
注意 master 分支前的 * 字符:它代表現(xiàn)在檢出的那一個(gè)分支(也就是說,當(dāng)前 HEAD 指針?biāo)赶虻姆种В?這意味著如果在這時(shí)候提交墅垮,master 分支將會(huì)隨著新的工作向前移動(dòng)惕医。 如果需要查看每一個(gè)分支的最后一次提交,可以運(yùn)行 git branch -v 命令:
$ git branch -v
iss53 93b412c fix javascript issue
* master 7a98805 Merge branch 'iss53'
testing 782fd34 add scott to the author list in the readmes
--merged 與 --no-merged 這兩個(gè)有用的選項(xiàng)可以過濾這個(gè)列表中已經(jīng)合并或尚未合并到當(dāng)前分支的分支算色。 如果要查看哪些分支已經(jīng)合并到當(dāng)前分支抬伺,可以運(yùn)行 git branch --merged:
$ git branch --merged
iss53
* master
因?yàn)橹耙呀?jīng)合并了 iss53 分支,所以現(xiàn)在看到它在列表中灾梦。 在這個(gè)列表中分支名字前沒有 * 號(hào)的分支通诚康觯可以使用 git branch -d 刪除掉;你已經(jīng)將它們的工作整合到了另一個(gè)分支若河,所以并不會(huì)失去任何東西能岩。
查看所有包含未合并工作的分支,可以運(yùn)行 git branch --no-merged:
$ git branch --no-merged
testing
這里顯示了其他分支萧福。 因?yàn)樗诉€未合并的工作拉鹃,嘗試使用 git branch -d 命令刪除它時(shí)會(huì)失敗:
$ git branch -d testing
error: The branch 'testing' is not fully merged.
If you are sure you want to delete it, run 'git branch -D testing'.
如果真的想要?jiǎng)h除分支并丟掉那些工作鲫忍,如同幫助信息里所指出的膏燕,可以使用 -D 選項(xiàng)強(qiáng)制刪除它。
長期分支
因?yàn)?Git 使用簡單的三方合并悟民,所以就算在一段較長的時(shí)間內(nèi)坝辫,反復(fù)把一個(gè)分支合并入另一個(gè)分支,也不是什么難事逾雄。 也就是說阀溶,在整個(gè)項(xiàng)目開發(fā)周期的不同階段,你可以同時(shí)擁有多個(gè)開放的分支鸦泳;你可以定期地把某些主題分支合并入其他分支中银锻。
許多使用 Git 的開發(fā)者都喜歡使用這種方式來工作,比如只在 master 分支上保留完全穩(wěn)定的代碼——有可能僅僅是已經(jīng)發(fā)布或即將發(fā)布的代碼做鹰。 他們還有一些名為 develop 或者 next 的平行分支击纬,被用來做后續(xù)開發(fā)或者測試穩(wěn)定性——這些分支不必保持絕對穩(wěn)定,但是一旦達(dá)到穩(wěn)定狀態(tài)钾麸,它們就可以被合并入 master 分支了更振。 這樣炕桨,在確保這些已完成的主題分支(短期分支,比如之前的 iss53 分支)能夠通過所有測試肯腕,并且不會(huì)引入更多 bug 之后献宫,就可以合并入主干分支中,等待下一次的發(fā)布实撒。