常用的git命令:
安裝之後第一步安裝 Git 之後,你要做的第一件事情就是去配置你的名字和郵箱,因為每一次提交都需要這些信息:
git config --global user.name "bukas" git config --global user.email "[email protected]"
獲取Git配置信息,執行以下命令:
git config --list
創建版本庫什麼是版本庫呢?版本庫又名倉庫,英文名repository,你可以簡單理解成一個目錄,這個目錄裡面的所有文件都可以被Git管理起來,每個文件的修改、刪除,Git都能跟蹤,以便任何時刻都可以追蹤歷史,或者在將來某個時刻可以“還原”。
mkdir testgit && cd testgit git init
瞬間Git就把倉庫建好了,細心的讀者可以發現當前目錄下多了一個.git的目錄,默認是隱藏的,用ls -ah命令就可以看見。
把文件添加到版本庫
touch readme.md git add readme.md
然後用命令git commit告訴Git把文件提交到倉庫:
git commit -m "wrote a readme file"
簡單解釋一下git commit命令,-m後面輸入的是本次提交的說明,可以輸入任意內容,當然最好是有意義的,這樣你就能從歷史記錄裡方便地找到改動記錄。
一次可以add多個不同的文件,以空格分隔:
git add a.txt b.txt c.txt
倉庫狀態
git status
git status命令可以讓我們時刻掌握倉庫當前的狀態。
但如果能看看具體修改了什麼內容就更好了:
git diff readme.md
版本回退在實際工作中,我們腦子裡怎麼可能記得一個幾千行的文件每次都改了什麼內容,不然要版本控制系統干什麼。版本控制系統肯定有某個命令可以告訴我們歷史記錄,在Git中,我們用git log命令查看:
git log
git log命令顯示從最近到最遠的提交日志。如果嫌輸出信息太多,看得眼花缭亂的,可以試試加上--pretty=oneline參數:
git log --pretty=oneline
需要友情提示的是,你看到的一大串類似2e70fd...376315的是commit id(版本號)
在 Git中,用HEAD表示當前版本,也就是最新的提交commit id,上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100。
現在我們要把當前版本回退到上一個版本,就可以使用git reset命令:
git reset --hard HEAD^
然我們用git log再看看現在版本庫的狀態,最新的那個版本已經看不到了!好比你從21世紀坐時光穿梭機來到了19世紀,想再回去已經回不去了,腫麼辦?
辦法其實還是有的,只要上面的命令行窗口還沒有被關掉,你就可以順著往上找啊找啊,假設找到那個commit id是2e70fdf...,於是就可以指定回到未來的某個版本:
git reset --hard 2e70fdf
版本號沒必要寫全,前幾位就可以了,Git會自動去找。當然也不能只寫前一兩位,因為Git可能會找到多個版本號,就無法確定是哪一個了。
現在,你回退到了某個版本,關掉了電腦,第二天早上就後悔了,想恢復到新版本怎麼辦?找不到新版本的commit id怎麼辦?
Git提供了一個命令git reflog用來記錄你的每一次命令:
git reflog
終於舒了口氣,於是你看到的commit id是2e70fdf,現在,你又可以乘坐時光機回到未來了。
工作區和暫存區Git和其他版本控制系統如SVN的一個不同之處就是有暫存區的概念。
工作區就是你在電腦裡能看到的目錄,比如我的testgit文件夾就是一個工作區。
工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。
Git的版本庫裡存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有Git為我們自動創建的第一個分支master,以及指向master的一個指針叫HEAD。
前面講了我們把文件往 Git 版本庫裡添加的時候,是分兩步執行的:
第一步是用git add把文件添加進去,實際上就是把文件修改添加到暫存區;
第二步是用git commit提交更改,實際上就是把暫存區的所有內容提交到當前分支。
因為我們創建Git版本庫時,Git自動為我們創建了唯一一個master分支,所以現在git commit就是往master分支上提交更改。
你可以簡單理解為,git add命令實際上就是把要提交的所有修改放到暫存區(Stage),然後執行git commit就可以一次性把暫存區的所有修改提交到分支。
一旦提交後,如果你又沒有對工作區做任何修改,那麼工作區就是“干淨”的。
修改與撤銷用git diff HEAD -- readme.md命令可以查看工作區和版本庫裡面最新版本的區別。
git checkout -- file可以丟棄工作區的修改:
git checkout -- readme.md
命令git checkout -- readme.md意思就是,把readme.md文件在工作區的修改全部撤銷,即讓這個文件回到最近一次git commit或git add時的狀態。
當然也可以用git reset命令。
刪除文件一般情況下,你通常直接在文件管理器中把沒用的文件刪了,或者用rm命令刪了:
rm readme.md
這個時候,Git 知道你刪除了文件,因此,工作區和版本庫就不一致了,git status命令會立刻告訴你哪些文件被刪除了。
現在你有兩個選擇,一是確實要從版本庫中刪除該文件,那就用命令git rm刪掉,並且git commit:
git rm readme.md git commit -m "remove readme.md"
現在,文件就從版本庫中被刪除了。
另一種情況是刪錯了,因為版本庫裡還有呢,所以可以很輕松地把誤刪的文件恢復到最新版本:
git checkout -- readme.md
生成SSH key創建 SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,如果有,再看看這個目錄下有沒有id_rsa和id_rsa.pub這兩個文件,如果已經有了,可直接跳到下一步。如果沒有,打開 Shell(Windows下打開Git Bash),創建SSH Key:
ssh-keygen -t rsa -C "[email protected]"
你需要把郵件地址換成你自己的郵件地址,然後一路回車,使用默認值即可。
如果一切順利的話,可以在用戶主目錄裡找到.ssh目錄,裡面有id_rsa和id_rsa.pub兩個文件,這兩個就是SSH Key的秘鑰對,id_rsa是私鑰,不能洩露出去,id_rsa.pub是公鑰,可以放心地告訴任何人。
然後登錄GitHub(或者其它Git代碼托管平台),打開Account settings,SSH Keys頁面,點Add SSH Key,填上任意Title,在Key文本框裡粘貼id_rsa.pub文件的內容。
為什麼GitHub需要SSH Key呢?因為GitHub需要識別出你推送的提交確實是你推送的,而不是別人冒充的,而Git支持SSH協議,所以GitHub只要知道了你的公鑰,就可以確認只有你自己才能推送。
當然,GitHub允許你添加多個Key。假定你有若干電腦,你一會兒在公司提交,一會兒在家裡提交,只要把每台電腦的Key都添加到GitHub,就可以在每台電腦上往GitHub推送了。
遠程服務器Git 最強大的功能之一是可以有一個以上的遠程服務器(另一個事實,你總是可以運行一個本地倉庫)。你不一定總是需要寫訪問權限,你可以從多個服務器中讀取(用於合並),然後寫到另一個服務器中。添加一個遠程服務器很簡單:
git remote add origin(別名,根據愛好命名) [email protected]:bukas/bukas.git
如果你想查看遠程服務器的相關信息,你可以這樣做:
# shows URLs of each remote server git remote -v # gives more details about origin git remote show origin(別名)
下一步,就可以把本地庫的所有內容推送到遠程庫上:
git push -u origin master
把本地庫的內容推送到遠程,用git push命令,實際上是把當前分支master推送到遠程。
由於遠程庫是空的,我們第一次推送master分支時,加上了-u參數,Git不但會把本地的master分支內容推送的遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來,在以後的推送或者拉取時就可以簡化命令。
從現在起,只要本地作了提交,就可以通過命令把本地master分支的最新修改推送至GitHub:
git push origin master
SSH警告
當你第一次使用Git的clone或者push命令連接GitHub時,會得到一個警告:
The authenticity of host ‘github.com (xx.xx.xx.xx)’ can’t be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?
這是因為Git使用SSH連接,而SSH連接在第一次驗證GitHub服務器的Key時,需要你確認 GitHub的Key的指紋信息是否真的來自GitHub的服務器,輸入yes回車即可。
從遠程庫克隆當已經有一個遠程庫的時候,我們可以用命令git clone克隆一個本地庫:
git clone [email protected]:test/testgit.git
你也許還注意到,GitHub給出的地址不止一個,還可以用https://github.com/test/testgit.git這樣的地址。實際上Git支持多種協議,默認的git://使用ssh,但也可以使用https等其他協議。使用https除了速度慢以外,還有個最大的麻煩是每次推送都必須輸入口令,但是在某些只開放http端口的公司內部就無法使用ssh協議而只能用https。
創建與合並分支首先我們創建dev分支,然後切換到dev分支:
git checkout -b dev
git checkout命令加上-b參數表示創建並切換,相當於以下兩條命令:
git branch dev git checkout dev
然後用git branch命令查看當前分支:
git branch
我們在dev分支上進行添加修改操作,然後我們把dev分支的工作成果合並到master分支上:
git checkout master git merge dev
git merge命令用於合並指定分支到當前分支。
注意到git merge的信息裡面可能有Fast-forward字樣,Git告訴我們,這次合並是“快進模式”,也就是直接把master指向dev的當前提交,所以合並速度非常快。
當然也不是每次合並都能Fast-forward。
合並完成後,就可以放心地刪除dev分支了:
git branch -d dev
如果要丟棄一個沒有被合並過的分支,可以通過git branch -D 強行刪除。
在本地創建和遠程分支對應的分支,使用git checkout -b branch-name origin/branch-name,本地和遠程分支的名稱最好一致;
建立本地分支和遠程分支的關聯,使用git branch --set-upstream branch-name origin/branch-name;
從遠程抓取分支,使用git pull,如果有沖突,要先處理沖突。
解決沖突人生不如意之事十之八九,合並分支往往也不是一帆風順的。
有時候我們進行合並的時候,會提示有沖突出現CONFLICT (content),必須手動解決沖突後再提交。git status也可以告訴我們沖突的文件。
打開沖突文件我們會看到Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,我們修改後提交:
git add readme.md git commit -m "conflict fixed"
用帶參數的git log也可以看到分支的合並情況:
git log --graph --pretty=oneline --abbrev-commit
分支管理策略通常,合並分支時,如果可能,Git會用Fast forward模式,但這種模式下,刪除分支後,會丟掉分支信息。
如果要強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
下面我們實戰一下--no-ff方式的git merge:
首先,仍然創建並切換dev分支:
git checkout -b dev
修改readme.md文件,並提交一個新的commit:
git add readme.md git commit -m "add merge"
現在,我們切換回master:
git checkout master
准備合並dev分支,請注意--no-ff參數,表示禁用Fast forward:
git merge --no-ff -m "merge with no-ff" dev
Bug分支軟件開發中,bug就像家常便飯一樣。有了bug就需要修復,在Git中,由於分支是如此的強大,所以,每個bug都可以通過一個新的臨時分支來修復,修復後,合並分支,然後將臨時分支刪除。
當你接到一個修復一個代號101的bug的任務時,很自然地,你想創建一個分支issue-101來修復它,但是,等等,當前正在dev上進行的工作還沒有提交。
並不是你不想提交,而是工作只進行到一半,還沒法提交,預計完成還需1天時間。但是,必須在兩個小時內修復該bug,怎麼辦?
幸好,Git還提供了一個stash功能,可以把當前工作現場“儲藏”起來,等以後恢復現場後繼續工作:
git stash
現在,用git status查看工作區,就是干淨的(除非有沒有被 Git 管理的文件),因此可以放心地創建分支來修復bug。
首先確定要在哪個分支上修復bug,假定需要在master分支上修復,就從master創建臨時分支:
git checkout master git checkout -b issue-101
現在修復bug,然後提交:
git add readme.md git commit -m "fix bug 101"
修復完成後,切換到master分支,並完成合並,最後刪除issue-101分支:
git checkout master git merge --no-ff -m "merged bug fix 101" issue-101
太棒了,原計劃兩個小時的bug修復只花了5分鐘!現在,是時候接著回到dev分支干活了!
git checkout dev git status
工作區是干淨的,剛才的工作現場存到哪去了?用git stash list命令看看:
git stash list
工作現場還在,Git把stash內容存在某個地方了,但是需要恢復一下,有兩個辦法:
一是用git stash apply恢復,但是恢復後,stash內容並不刪除,你需要用git stash drop來刪除;
另一種方式是用git stash pop,恢復的同時把stash內容也刪了:
git stash pop
再用git stash list查看,就看不到任何stash內容了。
你可以多次stash,恢復的時候,先用git stash list查看,然後恢復指定的stash,用命令
git stash apply stash@{0}
標簽管理發布一個版本時,我們通常先在版本庫中打一個標簽,這樣,就唯一確定了打標簽時刻的版本。將來無論什麼時候,取某個標簽的版本,就是把那個打標簽的時刻的歷史版本取出來。所以,標簽也是版本庫的一個快照。
命令git tag 用於新建一個標簽,默認為HEAD,也可以指定一個commit id。
git tag -a -m "blablabla..."可以指定標簽信息。
還可以通過-s用私鑰簽名一個標簽:
git tag -s v0.5 -m "signed version 0.2 released" fec145a
git tag可以查看所有標簽。
用命令git show 可以查看某個標簽的詳細信息。
如果標簽打錯了,也可以刪除:
git tag -d v0.1
因為創建的標簽都只存儲在本地,不會自動推送到遠程。所以,打錯的標簽可以在本地安全刪除。
如果要推送某個標簽到遠程,使用命令git push origin :
git push origin v1.0
或者,一次性推送全部尚未推送到遠程的本地標簽:
git push origin --tags
如果標簽已經推送到遠程,要刪除遠程標簽就麻煩一點,先從本地刪除:
git tag -d v0.9
然後,從遠程刪除。刪除命令也是push,但是格式如下:
git push origin :refs/tags/v0.9
忽略特殊文件在安裝Git一節中,我們已經配置了user.name和user.email,實際上,Git還有很多可配置項。
比如,讓Git顯示顏色,會讓命令輸出看起來更醒目:
git config --global color.ui true
有些時候,你必須把某些文件放到Git工作目錄中,但又不能提交它們,比如保存了數據庫密碼的配置文件啦,等等,每次git status都會顯示Untracked files…,有強迫症的童鞋心裡肯定不爽。
好在Git考慮到了大家的感受,這個問題解決起來也很簡單,在 Git工作區的根目錄下創建一個特殊的.gitignore文件,然後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不需要從頭寫.gitignore文件,GitHub已經為我們准備了各種配置文件,只需要組合一下就可以使用了。所有配置文件可以直接在線浏覽:https://github.com/github/gitignore
當然也可以配置全局忽略的文件,這樣就不用每個項目都加gitignore了:
git config --global core.excludesfile '~/.gitignore'
配置別名有沒有經常敲錯命令?比如git status?status這個單詞真心不好記。
如果敲git st就表示git status那就簡單多了,當然這種偷懶的辦法我們是極力贊成的。
我們只需要敲一行命令,告訴Git,以後st就表示status:
git config --global alias.st status
當然還有別的命令可以簡寫:
git config --global alias.co checkout git config --global alias.ci commit git config --global alias.br branch
--global參數是全局參數,也就是這些命令在這台電腦的所有Git倉庫下都有用。
在撤銷修改一節中,我們知道,命令git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區。既然是一個unstage操作,就可以配置一個unstage別名:
git config --global alias.unstage 'reset HEAD'
配置一個git last,讓其顯示最後一次提交信息:
git config --global alias.last 'log -1'
甚至還有人把lg配置成了:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
配置文件
配置Git的時候,加上–global是針對當前用戶起作用的,如果不加,那只針對當前的倉庫起作用。
配置文件放哪了?每個倉庫的Git配置文件都放在.git/config文件中。
而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig中。