【學習筆記】Git的日常使用
Note:本筆記是我學習廖雪峰老師的Git教程整理得到,在此向廖老師的無私付出表示衷心的感謝!
0、Git的歷史
- Git是一個分布式的版本控制系統(C語言編寫,一開始為Linux社區服務,替代BitKeeper),方便自己管理版本的同時方便了團隊協作
- 分布式:每臺終端上都有一個版本庫,不依賴服務器(可選的服務器只是為了方便協作中的版本交換);集中式:依賴服務器工作,工作前下載最新版本,工作后上傳自己的版本,沒有服務器不能工作
- GitHub是一個為開源項目提供Git存儲的軟件倉庫,可以免費使用(前提是將托管的代碼公開)
- CVS和SVN是集中式版本控制系統,SVN是CVS的改進型
- 其他版本控制系統:Microsoft Visual Studio的VSS,BitKeeper,IBM的ClearCase等
1、Git的安裝
- Mac要安裝Command Line Tools,git工具在其中,Spotlight-Terminal-git-提示安裝命令行工具,安裝即可(也可以在Xcode-Preference-Downloads-Command Line Tools-Install安裝)
- Linux一般自帶,不帶則使用包管理器安裝:
- Debian系:
sudo apt-get install git(or git-core,舊發行版中git指GNU Interactive Tools,后改名gnuit) - Red Hat系:
sudo yum install git - Arch系:
sudo pacman -S git
- Debian系:
- Windows要依靠Cygwin環境或WSL子系統,建議使用打包好的mysysgit
2、Git的幾個重要概念
- Git的幾個區域:工作區 Working Directory - 暫存區 Stage/Index - 版本庫Repository - 遠程版本庫(如GitHub)
- Git管理的是修改,而不是文件
- Git的HEAD是一個指針,指向當前分支的指針(比如說主分支master,而master指向主分支最新的提交),移動指針來改變分支和版本使得Git具有操作速度極快的特性
- Git的每一個分支都有自己的工作區(受到git監視的目錄)、暫存區以及版本庫,在切換版本庫的同時會同步切換
- 標簽是指向Commit號的指針,一旦建立不可移動;和Commit號一樣標簽具有唯一性
3、Git常用命令
-
git config 配置git基本信息(方便協作中識別身份,
--global表示全局,對所有沒有單獨設定的版本庫均有效)及配置git工具參數git config --global user.name "xxx"設置全局用戶名git config --global user.email "xxx@xxx"設置全局用戶郵箱git config --global color.ui true打開全局下用不同顏色來區分不同的git提示的功能git config --global alias.<alias> <command>為命令設置全局別名,是為 命令設置的別名, 可以是任何文本(如帶參數的命令)
-
git init在當前目錄啟用git來監視版本并初始化git,產生.git隱藏目錄,其中有本地版本庫的各分支(Branches,默認有master分支)、HEAD指針和暫存區,不要刪除 -
git add <filename>將指定文件放入暫存區(沒有提示表示成功),第一次add某一文件的同時會新增對其的監視(Track) -
git commit -m "Commit messages"將所有暫存區文件提交到版本庫- Note:commit時使用
--allow-empty-message -m ''參數可以不填寫Commit messages而提交,但為了項目的可維護性極不推薦
- Note:commit時使用
-
git rm <filename>用于在HEAD指向的版本庫中刪除某個文件,但注意需要git commit才能將更改提交至版本庫 -
git status查看受監視目錄的狀態(工作區文件相對于最新版本庫是否有修改,暫存區是否有未Commit的文件等) -
git diff <filename>暫存區為空時比較當前工作區和最新版本庫,暫存區不為空時比較當前工作區和暫存區,沒有結果說明沒有不同- Note:git diff加上
HEAD -- <filename>參數則指定將當前工作區和最新版本庫比較 - Note:git只能顯示文本文件的具體變化(二進制文件只知道變了沒有),git diff的結構用Unix標準diff格式顯示
- Note:注意Windows記事本程序生成BOM頭(0xEFBBBF)的問題
- Note:git diff加上
-
git log查看版本庫中存在的版本,每個版本包括一串SHA1計算得到的Commit號用于唯一標識改版本,此外還有版本的Commit messages,commit的日期、作者和作者的E-mail- Note:加入
--pretty=oneline參數在一行內顯示,更加緊湊 - Note:加入
--abbrev-commit參數可以將Commit號縮寫為前幾位顯示 - Note:加入
--graph參數可以用圖形畫出分支情況,不需要自己看日志判斷了(注意只有當其他分支被合并到當前分支,其他分支才會被顯示) - Note:加入
-l參數可以只顯示最后一個Commit
- Note:加入
-
git reflog(reference log) 顯示自啟用監視以來所有的版本操作記錄(含Commit號),包括那些已經回退而不在 git log 中顯示的版本 -
git reset用于版本回退、版本回退后的強制還原和撤銷暫存區修改(Unstage)- 版本回退:
git reset --hard HEAD^(or HEAD^,etc.)(HEAD表示版本庫最新版本,后面加幾個就是向上回退幾個版本) - 版本回退后的強制還原:
git reset --hard <commit_id>,Commit號通過git reflog查詢,可以簡寫為前幾位(有區分性的) - 撤銷向暫存區里add的某文件的修改并將其放回工作區:
git reset HEAD <filename>
- 版本回退:
-
git checkout用于撤銷工作區的修改、(創建并)切換到新分支-
git checkout -- <filename>暫存區有此文件的修改,就將撤銷工作區使其與暫存區一致(注意并不會同時撤銷或者說是清空暫存區,撤銷暫存區要使用git reset HEAD <filename>);暫存區沒有此文件的修改,就將撤銷工作區使其與最新的版本庫一致(想要回退舊的版本庫,要使用git reset --hard HEAD^(etc.) orgit reset --hard <commit_id>) -
git checkout <name_of_branch>切換到某分支Note:加入參數
-b可以創建<name_of_branch> 分支的同時切換到該新分支
-
-
git branch用于查看當前分支情況、創建新分支和刪除分支-
git branch用于查看當前分支情況(當前分支用*標注) -
git branch <name_of_branch>用于創建名為<name_of_branch>的新分支 -
git branch -d <name_of_branch>用于刪除<name_of_branch> 分支Note:當一個分支從未被合并就需要被刪除時,需要使用
-D參數替代-d參數以強制刪除 -
git branch --set-upstream <name_of_branch> <name_of_remote_lib>/<name_of_remote_branch>用于將本地庫中未關聯的<name_of_branch>分支與遠程庫<name_of_remote_lib>的<name_of_remote_branch> 分支建立關聯,以方便使用簡化命令git pull
-
-
git merge <name_of_branch>用于自動合并<name_of_branch>分支到當前分支 -
git stash用于將保存、恢復和刪除當前工作現場(暫存區),在臨時的Bug修復任務中十分有用(可以保護當前暫存區來不及Commit的修改)git stash將當前暫存區保存“入棧”并清空git stash list查看“堆棧”中保存的一個或多個工作現場git stash apply恢復最近一次保存的工作現場(不刪除stash的內容)git stash drop刪除最近一次stash的內容git stash pop將最近一次保存的工作現場彈出“堆棧”(刪除stash的內容)
-
git remote用于遠程庫的添加、查看操作git remote add <name_of_remote_lib> git@server-name:path/repo-name.git使用SSH協議為當前目錄下的本地庫關聯一個遠程庫git remote add <name_of_remote_lib> https://git.server-name/path/repo-name.git使用HTTPS協議為當前目錄下的本地庫關聯一個遠程庫git remote查看當前目錄下本地庫關聯的遠程庫信息(默認只顯示遠程庫名,添加-v參數顯示包括地址在內的詳細信息)
-
可以是SSH格式的,也可以是HTTPS格式的網絡地址git clone <address>克隆一個遠程庫的master分支到當前目錄,Note:如果要克隆遠程庫的非master分支,需要使用先使用
git clone命令克隆master分支,再用git checkout -b <name_of_remote_branch> <name_of_remote_lib>/<neme_of_remote_branch>命令在本地新建<name_of_remote_lib>分支并將遠程庫<name_of_remote_lib>的<neme_of_remote_branch>分支同步到本地 -
git push <name_of_remote_lib> <name_of_local_branch>將本地的<name_of_local_branch>分支推送到遠程庫<name_of_remote_lib>(添加-u參數將當前的<name_of_local_branch>和<name_of_remote_lib>設為缺省,之后可以使用git push的簡化命令,當有其他分支的時候不建議簡化命令)Note:
git push命令也可以用來推送標簽到遠程(推送分支的同時不會推送標簽),git push <name_of_remote_lib> <name_of_tag>推送單個標簽到遠程,git push <name_of_remote_lib> --tags推送本地所有標簽到遠程,git push <name_of_remote_lib> :refs/tags/<name_of_tag>從遠程刪除一個標簽 -
git pull <name_of_remote_lib> <name_of_remote_branch>從遠程庫<name_of_remote_lib>向本地拉取<name_of_remote_branch>分支的最新版本(git pull省略參數的寫法則會從關聯的遠程庫中拉取當前所在的分支的最新版本) -
git rebase在利用git pull解決了git push出現的沖突后對本地分支“變基”,將合并后的Commit連接在拉取下來的Commit后而不是本地的Commit后,使得不再因為git pull解決沖突而產生新分支,最終推送到遠程的分支結構更直接美觀(HEAD -> master指示本地指針位置,origin/master指示遠程版本庫位置):- (解決沖突后使用
git rebase)
![]()
- (解決沖突后使用
git rebase)
![]()
- (解決沖突后使用
-
git tag為Commit號打標簽(-m參數同時為標簽添加說明,-s參數同時為標簽使用gpg即GnuPG工具簽上私鑰)、刪除標簽及查看所有標簽,均為本地操作git tag <name_of_tag>在當前分支最新(HEAD指向的)版本處打一個名為<name_of_tag>的標簽git tag <name_of_tag> <commit_id>為Commit號為<commit_id>的版本打一個名為<name_of_tag>的標簽git tag -d <name_of_tag>刪除名為<name_of_tag>的標簽,不影響版本,只刪除版本上面的標簽git tag顯示已經打好的所有標簽名(按字母排序)
-
git show <name_of_tag>顯示標簽名為<name_of_tag>的版本的信息
4、Git遠程版本庫的使用(GitHub/GitLab,etc.)
-
開始使用遠程版本庫
-
Step1:自己注冊一個GitHub賬號(或聯系你的管理員幫你創建一個GitLab賬號)
-
Step2:在Terminal終端/Bash Shell/Git Shell(mysysgit)里用
ssh-keygen -t rsa -b <length_of_key> -C sth.(e.g.Your E-mail Address)在~/.ssh目錄下生成一對公私鑰用于SSH認證,其中-C(Comment)參數不是必須的,id_rsa為私鑰,妥善保存并防止顯示出而泄漏,id_Rsa.pub是公鑰 -
Step3:在GitHub的賬戶設置頁面中"Add SSH Keys"中貼入id_Rsa.pub公鑰中的全部內容(包含ssh-rsa前綴和最后你的Comment,完成基本配置
-
-
將遠程庫與本地庫關聯
-
Step1:在GitHub上選“Create a new repo”建立一個遠程庫
-
Step2:在本地庫中執行
git remote add <name_of_remote_lib> git@server-name:path/repo-name.git使用SSH協議關聯一個遠程庫,遠程庫的名字通常取"origin"以體現其是遠程庫(命令示例:git remote add origin git@github.com:zjuyzj/LearnGit.git)(Note:使用HTTPS協議而不是SSH協議的地址也是可以的,如 https://git.server-name/path/repo-name.git ,只不過這樣速度慢且每次都需要輸入密碼;git://地址默認使用SSH協議)
-
Step3:在本地庫中執行
git push <name_of_remote_lib> master將當前主分支推送到遠程庫(Note:git push命令添加-u參數后,此后再次推送可以省略origin master)
-
-
克隆一個現有的遠程庫到本地
- 在終端內執行
git clone git@server-name:path/repo-name.git即可將該遠程庫克隆到當前目錄下
- 在終端內執行
-
從遠程庫拉取(
git pull)提示“no tracking information”的原因和解決辦法- 原因:本地當前分支未與遠程分支建立關聯(庫是關聯好的)(只有使用
git clone命令得到的本地分支會自動與遠程分支建立關聯),且在git pull中沒有指定<name_of_remote_lib>和<name_of_remote_branch> - 解決辦法:使用
git branch --set-upstream <name_of_branch> <name_of_remote_lib>/<name_of_remote_branch>建立分支關聯即可
- 原因:本地當前分支未與遠程分支建立關聯(庫是關聯好的)(只有使用
-
向遠程庫推送(
git push)出現沖突的原因和解決辦法- 原因:推送的內容和遠程庫上的內容存在git無法處理的沖突(對于文本文件,即修改內容在同一行上),一般是由于其他開發成員在你尚未推送的時候向遠程推送了和你的修改有沖突的修改
- 解決辦法:先
git pull拉回最新的遠程版本庫,此時會發生自動合并,出現合并沖突,手動修改沖突后Commit,最后再次嘗試向遠程庫推送
-
利用GitHub代碼協作編輯的管理邏輯
- 在他人的開源項目網頁下點擊“Fork”將該項目的各分支完整克隆到自己的賬戶下
- 在自己的賬戶下對“Fork”的項目進行編輯修改(即在本地庫和自己賬戶下“Fork”得到的遠程庫之間工作)
- 在官方倉庫的網頁點擊“Pull Request”,審核通過即可向官方倉庫貢獻代碼
5、Git的分支管理
A、git merge <name_of_branch> 執行時可能發生的幾種情況
-
1、從產生分支開始,要合并的兩個分支中一個做了修改,另一個沒做修改,如:
![]()
合并時自動采用Fast-forward快進模式,master指針移動到dev處,完成合并(注意合并分支并不會刪除被合并的分支,要刪除請使用 git branch -d <name_of_branch> )
合并后:

注意,以Fast-forward模式合并分支并刪除被合并分支后,在git log里將不再能看出刪掉的分支存在過的信息,而加入--no-ff -m "Infomation of merged branch" 參數后,會在合并時新建一個Commit號(以"Infomation of merged branch"為Commit message)作為合并后的版本,而不是直接移動指針來合并,即:

- 2、產生分支后,兩個分支都有修改,即:

-
合并時兩分支最新版本庫上的修改不沖突(對于文本文件,即修改內容不在同一行上):
合并時git會自動用vim打開一個說明文檔,要求用戶輸入merge的理由(輸入的內容不需要注釋,git的提示會用
#注釋好以作區分),保存該說明文檔后git自動合并兩個分支上的修改(合并后的分支上的文件同時具有兩分支各自的修改) -
合并時兩分支最新版本庫上的修改有沖突(對于文本文件,即修改內容在同一行上):
合并時git會提示沖突(Conflict),使用
git status可以看到有沖突存在(both modified),git會自動將發生沖突的文檔中有沖突的部分標注在該文檔中,用vim/cat等工具查看該文檔可以看到,比如:Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage. Git tracks changes of files. <<<<<<< HEAD Creating a new branch is quick & simple. ======= Creating a new branch is quick AND simple. >>>>>>> feature1其中,
=======為分割線,<<<<<<<和>>>>>>>指明了分支的名字(HEAD為當前切換到的分支),之間夾的內容就是各個分支在同一行發生沖突的內容這種git無法自動處理的沖突需要手動解決,即對照git給出的沖突內容自行修改文檔,得到一個自己認為總體滿意的版本(定稿),對定稿進行
git add和git commit后沖突解決,分支自動合并,git status里的沖突信息也會消失Note:沖突沒有解決期間,不允許切換到待合并的分支!
B、開發時所應該采用的分支策略
-
master是極其穩定的分支,僅發布新版本使用,不輕易將其他分支合并到master分支;本地的master分支要時刻與遠程同步以保持最新作為開發基礎參考
-
dev是開發總分支,從master上產生,功能穩定后定期向master合并;本地的dev分支要時刻與遠程同步以保證協作開發不出現嚴重沖突
-
每個人都應該有自己的開發分支,從dev上產生,個人階段性工作完成后向dev上合并
![]()
-
需要修復某個分支上的Bug時,從該分支上產生新的Bug分支,在新分支上修復Bug,修復完成后向原分支合并并刪除Bug分支即可;本地的bug分支一般都是臨時性分支,不必向遠程同步
-
需要添加某實驗性的功能時,從dev或master分支上產生feature分支,在feature分支上開發穩定后再合并并刪除feature分支;如果需要合作開發新功能,本地的feature分支就需要向遠程同步
6、.gitignore文件的使用
- .gitignore是一個隱藏文件(以.開頭),用來記錄不被Git監控的文件名,這些文件不被Git監控(
git status命令中不會列入"Untracked files...") - .gitignore文件中一行寫一個文件名,允許使用通配符
* - .gitignore文件放在被Git監視的目錄下,也可以向遠程同步,也允許對其進行版本管理
- 不受監視的文件常常為:縮略圖文件、編譯產生的中間文件、個人敏感信息等
7、搭建一個私有Git服務器(簡易代碼倉庫)
- Step1:使用包管理器為Linux服務器安裝git
- Step2:新建一個系統用戶,
sudo adduser git - Step3:將所有用戶的公鑰導入到/home/git/.ssh/authorized_keys文件中,方便SSH登陸
- Step3:初始化裸倉庫(共享使用,沒有工作區),選定一個目錄,
sudo git init --bare <lib_name>.git - Step4:更改倉庫的屬主和屬組,
sudo chown -R git:git <lib_name>.git - Step5:禁止git用戶利用Shell登陸服務器,編輯/etc/passwd文件,將Shell從/usr/bin/bash改為/usr/bin/git-shell,這樣從Shell登陸會引發自動退出
- 之后用戶就可以正常從服務器克隆<lib_name>.git倉庫并推送了
- 管理公鑰的工具——Gitosis,管理權限的工具Gitolite(原生Git不支持權限管理)




浙公網安備 33010602011771號