下面是我整理的常用 Git 命令清單。幾個(gè)專用名詞的譯名如下茫经。
Workspace:工作區(qū)
Index / Stage:暫存區(qū)
Repository:倉庫區(qū)(或本地倉庫)
Remote:遠(yuǎn)程倉庫
本地分支關(guān)聯(lián)遠(yuǎn)程:git branch --set-upstream-to=origin/beta beta
# 在當(dāng)前目錄新建一個(gè)Git代碼庫
$ git init
# 新建一個(gè)目錄瓷炮,將其初始化為Git代碼庫
$ git init [project-name]
# 下載一個(gè)項(xiàng)目和它的整個(gè)代碼歷史
$ gitclone[url]
Git的設(shè)置文件為.gitconfig递宅,它可以在用戶主目錄下(全局配置)娘香,也可以在項(xiàng)目目錄下(項(xiàng)目配置)。
# 顯示當(dāng)前的Git配置
$ git config --list
# 編輯Git配置文件
$ git config -e [--global]
# 設(shè)置提交代碼時(shí)的用戶信息
$ git config [--global] user.name"[name]"
$ git config [--global] user.email"[email address]"
# 添加指定文件到暫存區(qū)
$ git add [file1] [file2] ...
# 添加指定目錄到暫存區(qū)烘绽,包括子目錄
$ git add [dir]
# 添加當(dāng)前目錄的所有文件到暫存區(qū)
$ git add .
# 添加每個(gè)變化前,都會(huì)要求確認(rèn)
# 對于同一個(gè)文件的多處變化俐填,可以實(shí)現(xiàn)分次提交
$ git add -p
# 刪除工作區(qū)文件安接,并且將這次刪除放入暫存區(qū)
$ git rm [file1] [file2] ...
# 停止追蹤指定文件,但該文件會(huì)保留在工作區(qū)
$ git rm --cached [file]
# 改名文件英融,并且將這個(gè)改名放入暫存區(qū)
$ git mv [file-original] [file-renamed]
# 提交暫存區(qū)到倉庫區(qū)
$ git commit -m [message]
# 提交暫存區(qū)的指定文件到倉庫區(qū)
$ git commit [file1] [file2] ... -m [message]
# 提交工作區(qū)自上次commit之后的變化,直接到倉庫區(qū)
$ git commit -a
# 提交時(shí)顯示所有diff信息
$ git commit -v
# 使用一次新的commit驶悟,替代上一次提交
# 如果代碼沒有任何新變化胡野,則用來改寫上一次commit的提交信息
$ git commit --amend -m [message]
# 重做上一次commit,并包括指定文件的新變化
$ git commit --amend [file1] [file2] ...
# 列出所有本地分支
$ git branch
# 列出所有遠(yuǎn)程分支
$ git branch -r
# 列出所有本地分支和遠(yuǎn)程分支
$ git branch -a
# 新建一個(gè)分支硫豆,但依然停留在當(dāng)前分支
$ git branch [branch-name]
# 新建一個(gè)分支,并切換到該分支
$ git checkout -b [branch]
# 新建一個(gè)分支,指向指定commit
$ git branch [branch] [commit]
# 新建一個(gè)分支够庙,與指定的遠(yuǎn)程分支建立追蹤關(guān)系
$ git branch --track [branch] [remote-branch]
# 切換到指定分支恭应,并更新工作區(qū)
$ git checkout [branch-name]
# 切換到上一個(gè)分支
$ git checkout -
# 建立追蹤關(guān)系,在現(xiàn)有分支與指定的遠(yuǎn)程分支之間
$ git branch --set-upstream [branch] [remote-branch]
# 合并指定分支到當(dāng)前分支
$ git merge [branch]
# 選擇一個(gè)commit耘眨,合并進(jìn)當(dāng)前分支
$ git cherry-pick [commit]
# 刪除分支
$ git branch -d [branch-name]
# 刪除遠(yuǎn)程分支
$ git push origin --delete [branch-name]
$ git branch -dr [remote/branch]
# 列出所有tag
$ git tag
# 新建一個(gè)tag在當(dāng)前commit
$ git tag [tag]
# 新建一個(gè)tag在指定commit
$ git tag [tag] [commit]
# 刪除本地tag
$ git tag -d [tag]
# 刪除遠(yuǎn)程tag
$ git push origin :refs/tags/[tagName]
# 查看tag信息
$ git show [tag]
# 提交指定tag
$ git push [remote] [tag]
# 提交所有tag
$ git push [remote] --tags
# 新建一個(gè)分支境肾,指向某個(gè)tag
$ git checkout -b [branch] [tag]
# 顯示有變更的文件
$ git status
# 顯示當(dāng)前分支的版本歷史
$ gitlog
# 顯示commit歷史,以及每次commit發(fā)生變更的文件
$ gitlog--stat
# 搜索提交歷史奥喻,根據(jù)關(guān)鍵詞
$ gitlog-S [keyword]
# 顯示某個(gè)commit之后的所有變動(dòng)偶宫,每個(gè)commit占據(jù)一行
$ gitlog[tag] HEAD --pretty=format:%s
# 顯示某個(gè)commit之后的所有變動(dòng),其"提交說明"必須符合搜索條件
$ gitlog[tag] HEAD --grep feature
# 顯示某個(gè)文件的版本歷史环鲤,包括文件改名
$ gitlog--follow [file]
$ git whatchanged [file]
# 顯示指定文件相關(guān)的每一次diff
$ gitlog-p [file]
# 顯示過去5次提交
$ gitlog-5 --pretty --oneline
# 顯示所有提交過的用戶纯趋,按提交次數(shù)排序
$ git shortlog -sn
# 顯示指定文件是什么人在什么時(shí)間修改過
$ git blame [file]
# 顯示暫存區(qū)和工作區(qū)的差異
$ git diff
# 顯示暫存區(qū)和上一個(gè)commit的差異
$ git diff --cached [file]
# 顯示工作區(qū)與當(dāng)前分支最新commit之間的差異
$ git diff HEAD
# 顯示兩次提交之間的差異
$ git diff [first-branch]...[second-branch]
# 顯示今天你寫了多少行代碼
$ git diff --shortstat"@{0 day ago}"
# 顯示某次提交的元數(shù)據(jù)和內(nèi)容變化
$ git show [commit]
# 顯示某次提交發(fā)生變化的文件
$ git show --name-only [commit]
# 顯示某次提交時(shí),某個(gè)文件的內(nèi)容
$ git show [commit]:[filename]
# 顯示當(dāng)前分支的最近幾次提交
$ git reflog
# 下載遠(yuǎn)程倉庫的所有變動(dòng)
$ git fetch [remote]
# 顯示所有遠(yuǎn)程倉庫
$ git remote -v
# 顯示某個(gè)遠(yuǎn)程倉庫的信息
$ git remote show [remote]
# 增加一個(gè)新的遠(yuǎn)程倉庫吵冒,并命名
$ git remote add [shortname] [url]
# 取回遠(yuǎn)程倉庫的變化,并與本地分支合并
$ git pull [remote] [branch]
# 上傳本地指定分支到遠(yuǎn)程倉庫
$ git push [remote] [branch]
# 強(qiáng)行推送當(dāng)前分支到遠(yuǎn)程倉庫西剥,即使有沖突
$ git push [remote] --force
# 推送所有分支到遠(yuǎn)程倉庫
$ git push [remote] --all
# 恢復(fù)暫存區(qū)的指定文件到工作區(qū)
$ git checkout [file]
# 恢復(fù)某個(gè)commit的指定文件到暫存區(qū)和工作區(qū)
$ git checkout [commit] [file]
# 恢復(fù)暫存區(qū)的所有文件到工作區(qū)
$ git checkout .
# 重置暫存區(qū)的指定文件,與上一次commit保持一致瞭空,但工作區(qū)不變
$ git reset [file]
# 重置暫存區(qū)與工作區(qū)揪阿,與上一次commit保持一致
$ git reset --hard
# 重置當(dāng)前分支的指針為指定commit,同時(shí)重置暫存區(qū)咆畏,但工作區(qū)不變
$ git reset [commit]
# 重置當(dāng)前分支的HEAD為指定commit南捂,同時(shí)重置暫存區(qū)和工作區(qū),與指定commit一致
$ git reset --hard [commit]
# 重置當(dāng)前HEAD為指定commit旧找,但保持暫存區(qū)和工作區(qū)不變
$ git reset --keep [commit]
# 新建一個(gè)commit溺健,用來撤銷指定commit
# 后者的所有變化都將被前者抵消,并且應(yīng)用到當(dāng)前分支
$ git revert [commit]
# 暫時(shí)將未提交的變化移除钦讳,稍后再移入
$ git stash
$ git stash pop
# 生成一個(gè)可供發(fā)布的壓縮包
$ git archive
一、主分支Master
首先愿卒,代碼庫應(yīng)該有一個(gè)缚去、且僅有一個(gè)主分支。所有提供給用戶使用的正式版本琼开,都在這個(gè)主分支上發(fā)布易结。
Git主分支的名字,默認(rèn)叫做Master。它是自動(dòng)建立的搞动,版本庫初始化以后躏精,默認(rèn)就是在主分支在進(jìn)行開發(fā)。
二鹦肿、開發(fā)分支Develop
主分支只用來分布重大版本矗烛,日常開發(fā)應(yīng)該在另一條分支上完成。我們把開發(fā)用的分支箩溃,叫做Develop瞭吃。
這個(gè)分支可以用來生成代碼的最新隔夜版本(nightly)。如果想正式對外發(fā)布涣旨,就在Master分支上歪架,對Develop分支進(jìn)行"合并"(merge)。
Git創(chuàng)建Develop分支的命令:
git checkout -b develop master
將Develop分支發(fā)布到Master分支的命令:
# 切換到Master分支
git checkout master
# 對Develop分支進(jìn)行合并
git merge --no-ff develop
這里稍微解釋一下霹陡,上一條命令的--no-ff參數(shù)是什么意思和蚪。默認(rèn)情況下,Git執(zhí)行"快進(jìn)式合并"(fast-farward merge)烹棉,會(huì)直接將Master分支指向Develop分支攒霹。
使用--no-ff參數(shù)后,會(huì)執(zhí)行正常合并峦耘,在Master分支上生成一個(gè)新節(jié)點(diǎn)剔蹋。為了保證版本演進(jìn)的清晰,我們希望采用這種做法辅髓。關(guān)于合并的更多解釋泣崩,請參考Benjamin Sandofsky的《Understanding the Git Workflow》。
三洛口、臨時(shí)性分支
前面講到版本庫的兩條主要分支:Master和Develop矫付。前者用于正式發(fā)布,后者用于日常開發(fā)第焰。其實(shí)买优,常設(shè)分支只需要這兩條就夠了,不需要其他了挺举。
但是杀赢,除了常設(shè)分支以外,還有一些臨時(shí)性分支湘纵,用于應(yīng)對一些特定目的的版本開發(fā)脂崔。臨時(shí)性分支主要有三種:
* 功能(feature)分支
* 預(yù)發(fā)布(release)分支
* 修補(bǔ)bug(fixbug)分支
這三種分支都屬于臨時(shí)性需要,使用完以后梧喷,應(yīng)該刪除砌左,使得代碼庫的常設(shè)分支始終只有Master和Develop脖咐。
四、 功能分支
接下來汇歹,一個(gè)個(gè)來看這三種"臨時(shí)性分支"屁擅。
第一種是功能分支,它是為了開發(fā)某種特定功能产弹,從Develop分支上面分出來的派歌。開發(fā)完成后,要再并入Develop取视。
功能分支的名字硝皂,可以采用feature-*的形式命名。
創(chuàng)建一個(gè)功能分支:
git checkout -b feature-x develop
開發(fā)完成后作谭,將功能分支合并到develop分支:
git checkout develop
git merge --no-ff feature-x
刪除feature分支:
git branch -d feature-x
五、預(yù)發(fā)布分支
第二種是預(yù)發(fā)布分支奄毡,它是指發(fā)布正式版本之前(即合并到Master分支之前)折欠,我們可能需要有一個(gè)預(yù)發(fā)布的版本進(jìn)行測試。
預(yù)發(fā)布分支是從Develop分支上面分出來的吼过,預(yù)發(fā)布結(jié)束以后锐秦,必須合并進(jìn)Develop和Master分支。它的命名盗忱,可以采用release-*的形式酱床。
創(chuàng)建一個(gè)預(yù)發(fā)布分支:
git checkout -b release-1.2 develop
確認(rèn)沒有問題后,合并到master分支:
git checkout master
git merge --no-ff release-1.2
# 對合并生成的新節(jié)點(diǎn)趟佃,做一個(gè)標(biāo)簽
git tag -a 1.2
再合并到develop分支:
git checkout develop
git merge --no-ff release-1.2
最后扇谣,刪除預(yù)發(fā)布分支:
git branch -d release-1.2
六、修補(bǔ)bug分支
最后一種是修補(bǔ)bug分支闲昭。軟件正式發(fā)布以后罐寨,難免會(huì)出現(xiàn)bug。這時(shí)就需要?jiǎng)?chuàng)建一個(gè)分支序矩,進(jìn)行bug修補(bǔ)鸯绿。
修補(bǔ)bug分支是從Master分支上面分出來的。修補(bǔ)結(jié)束以后簸淀,再合并進(jìn)Master和Develop分支瓶蝴。它的命名,可以采用fixbug-*的形式租幕。
創(chuàng)建一個(gè)修補(bǔ)bug分支:
git checkout -b fixbug-0.1 master
修補(bǔ)結(jié)束后舷手,合并到master分支:
git checkout master
git merge --no-ff fixbug-0.1
git tag -a 0.1.1
再合并到develop分支:
git checkout develop
git merge --no-ff fixbug-0.1
最后,刪除"修補(bǔ)bug分支":
git branch -d fixbug-0.1
{針對文件修改恢復(fù)}
工作區(qū)修改一個(gè)文件后令蛉,又想回到修改前(git add前)
1. 當(dāng)然可以直接手動(dòng)再在工作區(qū)中將文件修改回去
2. 修改后聚霜,通過命令git status查看
$ git status
# On branch master
# 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:? readme.txt
#
nochanges added to commit (use"git add"and/or"git commit -a")
這時(shí)Git會(huì)告訴你狡恬,git checkout -- file可以丟棄工作區(qū)的修改:
$ git checkout-- readme.txt
Note:
1.?git checkout -- file命令中的--很重要,沒有--蝎宇,就變成了“切換到另一個(gè)分支”的命令弟劲,我們在后面的分支管理中會(huì)再次遇到git checkout命令。
2. 命令git checkout -- readme.txt意思就是姥芥,把readme.txt文件在工作區(qū)的修改全部撤銷兔乞,這里有兩種情況:
一種是readme.txt自修改后還沒有被放到暫存區(qū),現(xiàn)在凉唐,撤銷修改就回到和版本庫一模一樣的狀態(tài)庸追;一種是readme.txt已經(jīng)添加到暫存區(qū)后,又作了修改台囱,現(xiàn)在淡溯,撤銷修改就回到添加到暫存區(qū)后的狀態(tài)〔狙担總之咱娶,就是讓這個(gè)文件回到最近一次git commit或git add時(shí)的狀態(tài)。
3.?工作區(qū)强品、暫存區(qū)的概念不清楚的可見于Git版本控制教程 - Git本地倉庫
如果在工作區(qū)中修改了文件還git add到暫存區(qū)(但是在commit之前)
用git status查看一下膘侮,修改只是添加到了暫存區(qū),還沒有提交:
$ git status
# On branch master
# Changes to be committed:
#? (use"git reset HEAD <file>..."to unstage)
#
#? ? ? modified:? readme.txt
#
Git同樣告訴我們的榛,用命令git reset HEAD file可以把暫存區(qū)的修改撤銷掉(unstage)琼了,重新放回工作區(qū):
$ gitresetHEADreadme.txt
Unstaged changesafterreset:
M? ? ? readme.txt
git reset命令既可以回退版本,也可以把暫存區(qū)的修改回退到工作區(qū)夫晌。當(dāng)我們用HEAD時(shí)雕薪,表示最新的版本。
再用git status查看一下慷丽,現(xiàn)在暫存區(qū)是干凈的蹦哼,工作區(qū)有修改。
然后丟棄工作區(qū)的修改
$ git checkout -- readme.txt
$ git status
#Onbranch master
nothingtocommit (working directory clean)
不但修改了文件還從暫存區(qū)提交commit到了版本庫 - 版本回退
版本回退可以回退到上一個(gè)版本要糊。不過纲熏,這是有條件的,就是你還沒有把自己的本地版本庫推送到遠(yuǎn)程锄俄。Git是分布式版本控制系統(tǒng)局劲。
在工作中對某個(gè)文件(如readme.txt)進(jìn)行多次修改交commit。
可以通過版本控制系統(tǒng)命令告訴我們提交的歷史記錄奶赠,在Git中鱼填,我們用git log命令查看:
$ git log
commit3628164fb26d48395383f8f31179f24e0882e1e0
Author: Michael Liao <askxuefeng@gmail.com>
Date:? Tue Aug2015:11:492013+0800
? ? append GPL
commitea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date:? Tue Aug2014:53:122013+0800
adddistributed
commitcb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date:? Mon Aug1917:51:552013+0800
wrote a readmefile
Note:
1.?git log命令顯示從最近到最遠(yuǎn)的提交日志,我們可以看到3次提交毅戈,最近的一次是append GPL苹丸,上一次是add distributed愤惰,最早的一次是wrote a readme file。
2. 如果嫌輸出信息太多赘理,看得眼花繚亂的宦言,可以試試加上--pretty=oneline參數(shù):
$ git log --pretty=oneline
3628164fb26d48395383f8f31179f24e0882e1e0appendGPL
ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file
3.?你看到的一大串類似3628164...882e1e0的是commit id(版本號(hào)),和SVN不一樣商模,Git的commit id不是1奠旺,2,3……遞增的數(shù)字施流,而是一個(gè)SHA1計(jì)算出來的一個(gè)非常大的數(shù)字响疚,用十六進(jìn)制表示,而且你看到的commit id和我的肯定不一樣瞪醋,以你自己的為準(zhǔn)忿晕。為什么commit id需要用這么一大串?dāng)?shù)字表示呢?因?yàn)镚it是分布式的版本控制系統(tǒng)银受,后面我們還要研究多人在同一個(gè)版本庫里工作杏糙,如果大家都用1,2蚓土,3……作為版本號(hào),那肯定就沖突了赖淤。
4.?每提交一個(gè)新版本蜀漆,實(shí)際上Git就會(huì)把它們自動(dòng)串成一條時(shí)間線。如果使用可視化工具(如GitX咱旱、github的客戶端确丢、pycharm)查看Git歷史,就可以更清楚地看到提交歷史的時(shí)間線吐限。0
現(xiàn)在我們想要把readme.txt回退到上一個(gè)版本
如“add distributed”的那個(gè)版本鲜侥,怎么做呢?首先诸典,Git必須知道當(dāng)前版本是哪個(gè)版本描函,在Git中,用HEAD表示當(dāng)前版本狐粱,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一樣)舀寓,上一個(gè)版本就是HEAD^,上上一個(gè)版本就是HEAD^^肌蜻,當(dāng)然往上100個(gè)版本寫100個(gè)^比較容易數(shù)不過來互墓,所以寫成HEAD~100。
現(xiàn)在蒋搜,我們要把當(dāng)前版本“append GPL”回退到上一個(gè)版本“add distributed”篡撵,就可以使用git reset命令:
$gitreset--hard HEAD^
HEADisnowat ea34578 adddistributed
這時(shí)readme.txt的內(nèi)容就成了版本add distributed
我們用git log再看看現(xiàn)在版本庫的狀態(tài):
$ git log
commitea34578d5496d7dd233c827ed32a8cd576c5ee85
Author: Michael Liao <askxuefeng@gmail.com>
Date:? Tue Aug2014:53:122013+0800
adddistributed
commitcb926e7ea50ad11b8f9e909c05226233bf755030
Author: Michael Liao <askxuefeng@gmail.com>
Date:? Mon Aug1917:51:552013+0800
wrote a readmefile
最新的那個(gè)版本append GPL已經(jīng)看不到了判莉!
恢復(fù)文件后,要是我們又想回到修改后的文件呢育谬?(命令行窗口還沒有被關(guān)掉)
{這個(gè)是git reset --hard后券盅,又反悔了,想回到修改后的狀態(tài)}
只要上面的命令行窗口還沒有被關(guān)掉斑司,你就可以順著往上找啊找啊渗饮,找到那個(gè)append GPL的commit id是3628164...,于是就可以指定回到未來的某個(gè)版本:
$ gitreset--hard 3628164
HEADisnowat3628164append GPL
版本號(hào)沒必要寫全宿刮,前幾位就可以了互站,Git會(huì)自動(dòng)去找。
Git的版本回退速度非辰┤保快胡桃,因?yàn)镚it在內(nèi)部有個(gè)指向當(dāng)前版本的HEAD指針,當(dāng)你回退版本的時(shí)候磕潮,Git僅僅是把HEAD從指向append GPL:
改為指向add distributed:
然后順便把工作區(qū)的文件更新了翠胰。所以你讓HEAD指向哪個(gè)版本號(hào),你就把當(dāng)前版本定位在哪自脯。
恢復(fù)文件后之景,要是我們又想回到修改后的文件呢?(命令行窗口早就關(guān)掉了)
{這個(gè)是git reset --hard后膏潮,又反悔了锻狗,想回到修改后的狀態(tài)}
想恢復(fù)到新版本怎么辦?找不到新版本的commit id怎么辦焕参?當(dāng)你用$ git reset --hard HEAD^回退到add distributed版本時(shí)轻纪,再想恢復(fù)到append GPL,就必須找到append GPL的commit id叠纷。
Git提供了一個(gè)命令git reflog用來記錄你的每一次命令:[Git高級教程:git log與git reflog]
$ git reflog
ea34578 HEAD@{0}:reset: moving to HEAD^
3628164HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file
第二行顯示append GPL的commit id是3628164刻帚,現(xiàn)在,你又可以乘坐時(shí)光機(jī)回到未來了涩嚣。