新手git教程
本文轉(zhuǎn)載自:http://igeekbar.com/igeekbar/post/82.htm
?
Git近些年的火爆程度非同一般,這個版本控制系統(tǒng)被廣泛地用在大型開源項目(比如Linux),不同規(guī)模的團隊開發(fā),以及獨立開發(fā)者,甚至學生之中。
初學者非常容易被git里的各種命令、參數(shù)嚇得不愿意繼續(xù)去學。但實際上剛上手的時候,你并不需要了解所有命令的用途。你可以從掌握一些簡單、常用又強大的命令開始,然后逐步去學習。這就是我們這篇文章要講的內(nèi)容。讓我們快開始吧!
?
基本了解
Git是一些命令行工具的集合,可以用來跟蹤、記錄文件的變動,經(jīng)常用于開源代碼。比如你可以進行舊版本恢復、比對、分析、合并等等。這個過程被稱之為版本控制。已經(jīng)有一系列的版本控制系統(tǒng),比如SVN、Mercurial、Perforce、CVS、Bitkeepe等等。
Git是分布式的,這意味著它并不依賴于中心服務器來保存你文件的舊版本。任何一臺機器都可以有一個本地版本的控制系統(tǒng),其實就是一個硬盤上的文件,我們稱之為倉庫(repository)。如果是多人協(xié)作的話,你還需要一個線上倉庫,用來同步代碼等信息。這就是GitHub、BitBucket等網(wǎng)站做的工作。
?
1.安裝Git
在你的機器上安裝git非常簡單:
- Linux – 打開終端,然后通過包管理安裝,在Ubuntu上命令是:sudo apt-get install git
- Windows – 推薦使用git for windows,它包括了圖形工具以及命令行模擬器。
- OS X – 最簡單的方式是使用homebrew安裝,命令行執(zhí)行brew install git
如果你是新手,推薦使用圖形工具Github desktop和Sourcetree。不過即使使用圖形界面的應用,知道一些基本的git命令依然很重要。接下來的內(nèi)容我們集中在命令行控制上。
?
2.配置Git
安裝完git,首要任務是做一些簡單的配置,最重要的是用戶名及郵箱,打開終端,執(zhí)行以下命令。
$ git config --global user.name "My Name"?$ git config --global user.email myEmail@example.com
配置好這兩項,Git就能記錄下來是誰做的動作,一切都更有組織性了。
?
3.創(chuàng)建一個新倉庫 – git init
git會把所有文件以及歷史記錄直接記錄成一個文件夾保存在你的項目中。創(chuàng)建一個新的倉庫,首先要去到項目路徑下,執(zhí)行g(shù)it init。這時Git會創(chuàng)建一個隱藏的文件夾.git,所有的歷史和配置信息都儲存在其中。
比如我們在桌面創(chuàng)建一個文件夾?git_exercise, 打開終端,輸入:
$ cd Desktop/git_exercise/?$ git init
命令行會出現(xiàn)
Initialized empty Git repository in /home/user/Desktop/git_exercise/.git/這說明我們的倉庫已經(jīng)建立好了,但現(xiàn)在是空的,試著新建一個hello.txt文本文件到這個文件夾里。
?
4.檢查狀態(tài) – git status
Git status是另一個非常重要的命令,它反饋給我們倉庫當前狀態(tài)的信息:是否為最新代碼,有什么更新等等。在我們新建的倉庫中執(zhí)行g(shù)it status會得到以下內(nèi)容:
$ git status?On branch master?
Initial commit?
Untracked files:?
? (use "git add ..." to include in what will be committed)?
hello.txt
反饋信息告訴我們,hello.txt尚未跟蹤,這是說這個文件是新的,git不知道是應該跟蹤它的變動還是直接忽略。為了跟蹤我們的新文件,我們需要暫存它。
?
5.暫存 – git add
Git有個概念叫“暫存區(qū)“,你可以把它看成一塊空白的畫布,包裹著所有你可能會提交的變動。它一開始是空的,可以通過?git add?命令添加內(nèi)容,最后使用?git commit?提交(創(chuàng)建一個快照)。
這個例子中只有一個文件,讓我們先add它:
$ git add hello.txt如果需要提交目錄下的所有內(nèi)容,可以這樣做:
$ git add -A再次使用git status查看狀態(tài)試試:
$ git status?On branch master?
Initial commit?
Changes to be committed:?
? (use "git rm --cached ..." to unstage)?
new file: ? hello.txt
我們的文件已經(jīng)準備好可以提交了。狀態(tài)信息還告訴我們暫存區(qū)文件發(fā)生了什么變動,這里我們新增了一個文件,同樣可以做修改和刪除。取決于我們在上一次git add之后發(fā)生了什么。
?
6.提交 – git commit
一次提交代表著我們的倉庫到了一個新的狀態(tài),就像是一個快照,允許我們像使用時光機一樣回到之前的某個時間點。
創(chuàng)建提交,需要我們至少在到暫存區(qū)有一次修改(剛才我們做了git add),然后輸入命令:
$ git commit -m "Initial commit."這就創(chuàng)建了一次從暫存區(qū)的提交(加入hello.txt),-m “Initial commit.”是用戶對這次提交的描述,建議寫成有意義的描述性信息。
?
遠程倉庫
到目前為止,我們的操作都是在本地的——只存在于.git文件中。為了能夠協(xié)同開發(fā),我們需要把代碼部署到遠程倉庫服務器上。
?
1.鏈接遠程倉庫 – git remote add
為了能夠上傳到遠程倉庫,我們需要先建立起鏈接。在這篇教程中,我們遠程倉庫的地址為:https://github.com/igeekbar/awesome-project。但你應該自己在Github、或BitBucket上搭建倉庫,自己一步一步嘗試。
把本地倉庫鏈接到Github上,在命令行執(zhí)行以下內(nèi)容:
# This is only an example. Replace the URI with your own repository address.?$ git remote add origin https://github.com/igeekbar/awesome-project.git
一個項目可以同時擁有好幾個遠程倉庫,為了區(qū)分通常會起不同的名字。通常主要的遠程倉庫被稱為origin。
?
2.上傳到服務器 – git push
把本地的提交傳送到服務器的動作叫做push。每次我們要提交修改到服務器上時,都會使用到git push。
git push命令有兩個參數(shù),遠程倉庫的名字,以及分支的名字:
$ git push origin master?Counting objects: 3, done.?
Writing objects: 100% (3/3), 212 bytes | 0 bytes/s, done.?
Total 3 (delta 0), reused 0 (delta 0)?
To https://github.com/igeekbar/awesome-project.git?
?* [new branch] ? ? ?master -> master
取決于你使用的服務器,push過程中你可能需要驗證身份(輸入用戶名、密碼,請先在網(wǎng)站上進行注冊)。如果沒有出差錯,現(xiàn)在用瀏覽器看你的遠程倉庫上已經(jīng)有hello.txt了。
?
3.克隆倉庫 – git clone
其他人可以看到你放在Github上的開源項目,他們可以用git clone命令下載到本地。
$ git clone https://github.com/igeekbar/awesome-project.git本地也會創(chuàng)建一個新的倉庫,并自動將github上的版本設(shè)為遠程倉庫。
?
4.從服務器上獲得修改 – git pull
如果你更新了遠程倉庫上的內(nèi)容,其他人可以通過git pull命令拉取你的變動:
$ git pull origin master?From https://github.com/igeekbar/awesome-project?
?* branch ? ? ? ? ? ?master ? ? -> FETCH_HEAD?
Already up-to-date.
因為在我們git clone之后還沒有提交過修改,所有沒有任何變動。
?
分支
當你在做一個新功能的時候,最好是在一個獨立的區(qū)域上開發(fā)(原始項目的拷貝),通常稱之為分支。分支之間相互獨立,并且擁有自己的歷史記錄,直到你決定把他們合并到一起。這樣做的原因是:
- 已經(jīng)可以運行的穩(wěn)定版本的代碼不會被破壞
- 不同的功能可以由不同開發(fā)者同時開發(fā)
- 開發(fā)者可以專注于自己的分支,不用擔心被其他人破壞
- 在不確定哪個版本更好之前,同一個特性可以在不同的分支上創(chuàng)建多個版本,便于比較
?
1.創(chuàng)建新分支 – git branch
每一個倉庫的默認分支都叫master, 創(chuàng)建新分支可以用git branch <name>命令:
$ git branch amazing_new_feature創(chuàng)建了一個名為amazing_new_feature的新分支,它目前和master分支是一樣的內(nèi)容。
?
2.切換分支 – git checkout
使用git branch,可以查看分支狀態(tài):
$ git branch?? amazing_new_feature?
* master
* 號表示當前活躍分支為master,現(xiàn)在我們想在新分支上開發(fā)新的特性,使用git checkout切換分支。有一個參數(shù)表示要切換到的分支。
$ git checkout amazing_new_feature?
3.合并分支 – git merge
我們在“amazing_new_feature”分支想添加一個feature.txt。和之前一樣我們來創(chuàng)建文件、添加到暫存區(qū)、提交。
$ git add feature.txt?$ git commit -m "New feature complete."
新分支任務完成了,回到master分支。
$ git checkout master現(xiàn)在去查看文件夾內(nèi)容,你會驚奇地發(fā)現(xiàn)之前剛剛創(chuàng)建的feature.txt文件不見了,因為我們現(xiàn)在回到了master分支上,這里并沒有feature.txt。想把文件添加到這里,我們需要使用git merge把amazing_new_feature分支合并到master上。
$ git merge amazing_new_feature現(xiàn)在master分支是最新的了,amazing_new_feature分支可以刪掉了。
$ git branch -d amazing_new_feature?
進階功能
在這篇教程的最后一節(jié),我們來看一些高級并且實用的技巧。
?
1.比對兩個不同提交之間的差別
每次提交都有一個標識id,查看所有歷史提交和他們的id,可以使用?git log:
$ git log?commit ba25c0ff30e1b2f0259157b42b9f8f5d174d80d7?
Author: igeekbar?
Date: ? Fri July 29 17:15:28 2016 +0300?
? ? New feature complete?
commit b10cc1238e355c02a044ef9f9860811ff605c9b4?
Author: igeekbar?
Date: ???Fri July 29?16:30:04 2016 +0300?
? ? Added content to hello.txt?
commit 09bd8cc171d7084e78e4d118a2346b7487dca059?
Author: igeekbar?
Date: ? Thu July 28 17:52:14 2016 +0300?
? ? Initial commit
id很長,但是當使用它的時候你并不需要復制整個字符串,前幾個字符就夠了。
查看某一次提交更新了什么,使用?git show [commit]:
$ git show b10cc123?commit b10cc1238e355c02a044ef9f9860811ff605c9b4?
Author: igeekbar?
Date: ???Fri July 29?16:30:04 2016 +0300?
? ? Added content to hello.txt?
diff --git a/hello.txt b/hello.txt?
index e69de29..b546a21 100644?
--- a/hello.txt?
+++ b/hello.txt?
@@ -0,0 +1 @@?
+Nice weather today, isn't it?
查看兩次提交的不同,可以使用git diff [commit-from]..[commit-to]:
$ git diff 09bd8cc..ba25c0ff?diff --git a/feature.txt b/feature.txt?
new file mode 100644?
index 0000000..e69de29?
diff --git a/hello.txt b/hello.txt?
index e69de29..b546a21 100644?
--- a/hello.txt?
+++ b/hello.txt?
@@ -0,0 +1 @@?
+Nice weather today, isn't it?
比較首次提交和最后一次提交,我們可以看到中間所有的更改。使用git difftool命令可以用圖形化界面查看所有更改。
?
2.回滾某個文件到之前的版本
Git允許我們將某個特定的文件回滾到特定的提交,使用的也是?git checkout命令。
下面我們將hello.txt回滾到最初的狀態(tài),需要指定回滾到哪個提交(以id作為參數(shù)),以及文件的全路徑。
$ git checkout 09bd8cc1 hello.txt?
3.回滾提交
如果你發(fā)現(xiàn)最新的一次提交忘記加入某個文件,或是信息輸入的不正確,你可以通過?git commit --amend來改正,它會把最新的提交打回暫存區(qū),并嘗試重新提交。
如果是更復雜的情況,比如不是最新的提交除了問題,你可以使用git revert。
最新的一次提交別名也叫HEAD。
$ git revert HEAD其他提交需要指明id:
$ git revert b10cc123回滾提交時,發(fā)生沖突是非常頻繁的。比如文件被指定回滾的提交之后的某次提交修改過,git不能正確回滾。
?
4.解決合并沖突
沖突經(jīng)常出現(xiàn)在合并分支或者是拉取別人的代碼。有些時候git能自動處理沖突,其他時候需要我們手動處理。
我們來看以下的例子,John 和 Tim 分別在各自的分支上寫了一段代碼,來顯示一個數(shù)組中所有的元素。
John使用了for循環(huán):
// Use a for loop to console.log contents.?for(var i=0; i<arr.length; i++) {?
console.log(arr[i]);?
}
Tim使用forEach:
// Use forEach to console.log contents.?arr.forEach(function(item) {?
console.log(item);?
});
它們都提交了代碼到各自的分支上,現(xiàn)在假設(shè)John嘗試合并Tim的代碼:
$ git merge tim_branch?Auto-merging print_array.js?
CONFLICT (content): Merge conflict in print_array.js?
Automatic merge failed; fix conflicts and then commit the result.
這時候git并不能自動解決沖突,于是它在代碼中插入沖突標記。
<<<<<<< HEAD?// Use a for loop to console.log contents.?
for(var i=0; i<arr.length; i++) {?
? ? console.log(arr[i]);?
}?
=======?
// Use forEach to console.log contents.?
arr.forEach(function(item) {?
? ? console.log(item);?
});?
>>>>>>> Tim’s commit.
==== 號上方是當前最新一次提交,下方是沖突的代碼。這樣我們可以清晰地看出區(qū)別,決定使用哪一個版本,或者重新寫一個。假設(shè)我們對于這兩個版本都不滿意,我們把代碼改成以下代碼:
// Not using for loop or forEach.?// Use Array.toString() to console.log contents.?
console.log(arr.toString());
好了,再提交一下:
$ git add -A?$ git commit -m "Array printing conflict resolved."
在大型項目中,我們可能在合并過程中出現(xiàn)很多沖突,大部分開發(fā)者會借助GUI工具來獲得幫助,運行推行界面可以使用git mergetool命令。
?
5.配置 .gitignore
大部分項目中,會有些文件、文件夾是我們不想提交的。為了防止使用git add -A時不小心提交,我們可以利用.gitignore文件:
- 在項目根目錄創(chuàng)建.gitignore文件
- 在文件中列出不需要提交的文件名、文件夾名,每個一行
- .gitignore文件需要像普通文件一樣add、commit和push
通常會被ignore的文件有:
- log文件
- task runner builds
- node.js項目中的node_modules文件夾
- IDEs比如NetBeans和IntelliJ生成的文件
- 個人筆記
以下是一個.gitignore文件的例子:
*.log?build/?
node_modules/?
.idea/?
my_notes.txt
“/”說明是一個文件夾,里面的所有內(nèi)容都被遞歸忽略
?
?
總結(jié)
Git教程到這里就結(jié)束啦!
Git很復雜,還有很多的特性和技巧等著你去挖掘,這篇教程只涵蓋了冰山一角,希望你不要因為太多繁瑣的命令而停下前進的腳步!加油!
總結(jié)
- 上一篇: cygwin/gcc与MinGW
- 下一篇: Marshal在C#中的应用(void