想要學會使用Git,首先需要理解什么是分布式版本庫,什么是工作區和暫存區,這幾個概念是理解很多命令的基礎。強烈推薦閱讀廖雪峰老師寫的Git教程,這是目前為止最好的中文Git教程,沒有之一。如果你想要成為Git專家請參考《Pro Git》(Second Edition)。
先簡單地解釋一下工作區、版本庫和暫存區。看不懂沒關系,先了解下后面的git add
和git commit
命令后再看就容易理解了。(如果還是沒有明白,點這里。)
- 工作區:你的工作目錄,你的工程文件夾。
- 版本庫:就是你工作區中的
.git
文件夾,這里忠實地記錄著你提交過的每一次改動。git commit
命令就是把你的改動從暫存區提交到了版本庫的當前分支,比如默認的master
分支。 - 暫存區:需要提交的文件修改通通放到暫存區,然后,一次性提交暫存區的所有修改。也就是使用
git add
后文件修改就保存到了暫存區,以備使用git commit
命令提交到真正的版本庫。
這里只對常用命令做一下梳理,這些命令基本可以滿足日常使用,注意所有git
命令都要在你項目的根目錄下使用。
創建倉庫
$ git init
添加到暫存區
創建倉庫之后就可以使用git管理當前目錄下的代碼了。同時該目錄下多了一個.git
的子目錄,用ls -a
可以查看。
$ git add filename
把修改添加到暫存區,每次修改后都需要運行git add
命令,之前已經add
過得文件也一樣,如果不add到暫存區,那就無法commit
。因為git
記錄的是修改而不是你文件的拷貝,這也是它可以如高效和節約空間的原因。(使用過git add
命令的文件狀態就是Tracked
,新建的文件狀態是Untracked
。)
$ git add .
把所有文件添加到暫存區。
忽略某些文件
有些文件我們無需Git
管理,也不希望看到它出現在Untracked
列表里面,比如使用Vim
時產生的.swp
臨時文件。我們只要創建一個名為.gitignore
的文件,列出要忽略的文件模式即可,支持簡單地正則表達式(其實是glob
模式匹配,shell中使用的簡化了的正則表達式)。
看一個《Pro Git》中給的.gitignore
文件的例子就懂了:
# 此為注釋,會被 Git 忽略
# 忽略所有 .swp 結尾和 .a 結尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 忽略項目根目錄下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目錄下地所有文件
build/
# 忽略 doc/ 目錄下的所有 .txt 文件,但不包括 doc/ 子目錄中的 .txt 文件
doc/*.txt
# 忽略 doc/ 目錄下的所有 .txt 文件,包括 doc/ 子目錄中的 .txt 文件
doc/**/*.txt
那些討厭的臨時文件再也不會在git add
的時候搗亂,也不會出現在Untracked
列表里了。
提交
$ git commit -m "wrote a new file"
把文件提交到版本庫,-m
后面輸入的是本次提交的說明,方便以后從歷史記錄里找到改動記錄。
如果不想每次都要git add
,git commit
怎么辦,有一個簡單地辦法,使用-a
參數:
$ git commit -a -m "I did some work"
這樣即使是上次提交之后修改過的文件(Tracked
)也可以直接提交到版本庫中(當前的分支)。
查看狀態
$ git status
查看版本庫狀態,就是告訴你哪個文件修改已經在暫存區了(to be commit
),哪個文件已經add
過但是最后的修改沒有add
(Changes not staged for commit
),哪個文件是新建的還沒有add
過(Untracked
)。
查看日志
$ git log
git log
命令顯示所有提交,從最早的提交到最近一次提交(當前HEAD所指向的提交,請參考版本回退)。
$ git log --pretty=oneline
加上--pretty
參數后可以單行輸出。
$ git reflog
用來記錄你的每一次命令,包括回退命令。
版本回退
在Git中,用HEAD表示當前版本,也就是最新的提交。
$ git reset --hard HEAD^
這個命令表示回退到當前HEAD的上一個版本,也就是舍棄了最后一次提交。會退后再使用git log
命令將無法查看最后一次提交的記錄,只能看到當前HEAD,以及更早的提交。可以使用git reflog
命令查看所有提交記錄。
$ git reset fc142e435432984a95b46bb7b757b9bdcee0e8e8
git reset
后的參數是通過git reflog
查看到的你希望回退到的版本,可以是任意提交過的版本。
撤銷修改
$ git checkout -- filename
命令git checkout -- filename
意思就是,把filename
文件在工作區的修改全部撤銷,這里有兩種情況:
文件修改后還沒有
add
到暫存區,撤銷修改就回到最后一次commit
時的狀態;已經
add
后又作了修改,撤銷修改就回到最后一次add
時的狀態。
如果你亂改了文件還add
到了暫存區,想要回到上一次commit
時的狀態,先使用命令git reset HEAD filename
,使暫存區文件恢復到和commit
時一致,再使用git checkout -- filename
。
注意:git checkout -- file
命令中的--
很重要,沒有--
,就變成了“創建一個新分支”的命令。
刪除文件
直接刪除摸個文件,或者用rm filename
命令刪除,然后使用命令:
$ git rm filename
然后commit
就可以了。如果不小心刪錯了文件并且沒有commit
,沒關系,冷靜一下,使用上面一條命令git checkout -- filename
就可以恢復了。
如果一個文件已經被提交到版本庫,那么你永遠不用擔心誤刪,但是要小心,你只能恢復文件到最新版本,你會丟失最近一次提交后你修改的內容。
查看分支
每次提交,Git都把它們串成一條時間線,這條時間線就是一個分支。默認分支是master
,也是HEAD指向的分支。
$ git branch
前面有*
的分支是當前分支。
新建分支
$ git branch branchname
比如git branch dev
命令創建了一個叫dev
的分支,現在dev
和master
指向相同的提交。
切換分支
$ git checkout branchname
使用git checkout dev
后,HEAD就指向了dev
,現在提交的修改就會到dev
分支上,而master
分支會停留在當前狀態。
創建+切換分支
$ git checkout -b branchname
前面兩條命令合并成一條。
合并某分支到當前分支
$ git merge branchname
比如當前分支是master
,使用git merge dev
,會將dev
分支上的提交添加到master
分支上。這種合并方式是快速合并(Fast-forward)當兩個分支都做過修改后合并是可能會產生沖突,無法進行快速合并,當Git無法自動合并分支時,就必須首先解決沖突。
刪除分支
$ git branch -d branchname
合并完成后,就可以放心地刪除dev分支了。合并后再刪掉分支,和直接在master分支上工作效果是一樣的,但過程更安全。
查看文件差異
$ git diff
比較工作區和暫存區的差異。
$ git diff filename
比較同一個文件在不同分支的差異。
$ git diff branchname
比較當前分支和branchname
分支的差異。
$ git diff --cached
// or git diff --staged
比較暫存區和HEAD的差異。
$ git diff --HEAD
比較工作區和HEAD的差異。
解決沖突
git merge
命令會標記有沖突的文件內容,使用git status
可以查看沖突文件,使用git diff filename
可以查看文件內容,比較不同分支上的差異。
打開有沖突的文件,解決沖突,再提交,合并完成。
用帶參數的git log --graph
可以看到分支的合并情況:
$ git log --graph --pretty=oneline --abbrev-commit
現在,你已經可以使用Git在自己的機器上愉快地玩耍啦_。