GIT原理和常用命令速成
【原創,2018-03-16,15:33:49】
剛開始學習GIT的時候,以為只要掌握幾個基本的操作指令就萬事大吉了。但是隨著GIT使用的深入,如果不了解些原理就會遇到各種各樣讓人一臉懵逼的問題,所以還是要對GIT原理有一些基本了解,這裏默認已經掌握常用的基本指令了。(隨便搜教程看下就行,例如clone pull push add commit log reset status branch checkout差不多吧,文末也會記錄一些常用命令)
ps. 文中列舉了許多英文單詞,因為在外文手冊和help中經常會看到這些單詞,而不容易得知其對應中文意思,所以這裏把常用的概念註釋了出來。
一、GIT原理
原理先從git-gui版本的visuallize history圖開始說起,先舉例子上圖(win下):
(ps. win版本直接安裝git-gui就好,linux上安裝gitk,並且shell中用gitk --all & 執行)
這是git中的樹狀圖,表示了版本的演進發展過程,每個節點在英文手冊或者help中稱為point。下方的節點表示父節點,上面的節點表示子節點,子節點由父節點演化得到。
1、每一個圓點表示一個開發版本,每次commit或者pull、stash等就會出現新的子節點,後面的文字表示commit時寫的註釋信息
2、左側方框表示分支branch名稱(例如master, average等),連線的節點表示該分支當前的版本。
3、黃色表示HEAD指針指向的point(表示處於當前工作狀態下),常說成HEAD指針指向當前工作狀態的分支,但是圖中有一些節點是沒有對應分支的,此時這個節點對應的分支就用hash值表示,哈希值在git-gui中可以查到或者git log中查到。
所以從此處開始,後文中不區分節點和分支的概念,兩者是一一對應的,只是有的分支有名字,有的分支沒有名字(哈希值,並且git branch 也默認不顯示),因此HEAD也可以當做分支名稱使用
4、每一個倉庫包括三部分:工作區、版本庫(暫存區和分支),如圖所示(圖片來自網絡)
工作區:對應於當前倉庫(repository)目錄(linux叫目錄,win叫文件夾)下除了.git文件夾外其他所有文件
版本庫:對用於.git中的文件,包括暫存區(stage/index)的數據 + 各個版本分支(按照上面3的說法就是指各個節點)的數據
5、文件分為三種狀態:unstaged, stage, commit之後的文件
git add 命令就是把unstaged的數據提交到緩存區表位staged狀態
git commit 命令就是把staged的數據提交,生成一個新的point
git status 命令可以查看處於unstaged, staged 狀態的文件,
其中unstaged文件又分為modified(之前存在的文件做出修改), untracked(新建文件)
ps. git status 輸出結果中還給出了從stage撤回到unstaged, 從modified恢復修改之前的指令,untracked文件的恢復就是rm刪除就可以了
二、常用指令(盡量按照使用GIT時可能碰到的先後順序寫)
1、從零開始
(1)從遠程主機下載已有的倉庫開始
a)ssh方式(關於SSH公鑰秘鑰的產生和設置這裏就不提了,網上隨便一搜就有)
git clone git@域名:用戶ID/倉庫名稱.git
b) https方式
git clone https://域名/用戶ID/倉庫名稱.git
輸入用戶名和密碼
(2)從本地主機新建倉庫開始
git init
2、本地分支的操作
git branch 查看本地分支
git branch -a 查看本地分支和遠程分支
git checkout -b AAA BBB 在BBB節點上建立名字為AAA的分支並切換到該分支(即移動HEAD指針)
(缺省-b AAA:分支名字使用哈希值表示,只輸入哈希值的前幾位就可以了 )
(缺省BBB:默認使用HEAD指針的節點)
git branch -d AAA 刪除名字為AAA的分支
(ps. 有一些節點沒有分支名字並且不是現有分支的父節點,在GIT中會保存一段時間,之後就可能被刪除了)
3、完成本次開發準備本地提交
(git status 查看文件狀態)
git add 文件名/.(點表示所有unstaged文件)
git commit -m "xxx
4、版本還原(保證不存在unstaged和staged的文件才可以使用還原功能,可以commit,或者撤回add和修改,或者stash把未commit文件加入到棧)
分為兩種情況:
a)HEAD指向有名字的分支,可以理解為把該分支移動到HEAD指向節點的父節點,並且移動HEAD指針到該父節點
b)HEAD指向沒有名字的分支(哈希值表示),reset等價於移動HEAD指針的checkout指令
這裏主要針對a情況
git log -n 查看記錄(顯示當前節點的所有父節點)
git reset --soft XXX 把當前分支(有名字)移動到歷史分支XXX,工作區文件不變,版本庫中有差異的文件直接放入到暫存區(index),即staged狀態
git reset --mixed XXX (--mixed可缺省) 當前分支(有名字)移動到歷史分支XXX,工作區文件不變,版本庫中有差異的文件放入到unstaged狀態
git reset --hard XXX 當前分支(有名字)移動到歷史分支XXX,工作區文件也都全部還原到歷史版本
ps1. reset不會立刻把git樹中的節點刪除掉,而是會保存一段時間
ps2. XXX參數為分支名稱,可以是有名字的分支名稱,無名字分支的哈希值名稱,HEAD指針變形(HEAD^表示上一個父節點,HEAD^^上兩個父節點)
5、push(同4)
(origin表示該倉庫對應的遠程倉庫,在clone之後已經默認設置好了,不過可以修改也可以建立新的源)
git push origin AAA:BBB 把AAA分支推到遠程BBB分支(缺省 “:BBB”:遠程分支和本地分支同名,遠程沒有同名分支則新建;缺省“AAA”:刪除遠程BBB分支)
(缺省“AAA:BBB”:push HEAD指針指向的分支,遠程分支和本地分支同名)
(缺省 "origin AAA:BBB"): 若源是惟一的,則origin可以省略,指令作用同上
6、pull(同4)
(1)pull = fetch + merge
(2)pull一般用於本地已經存在的分支,用於同步
git pull origin AAA:BBB(AAA是遠程分支,BBB是本地分支)
(缺省:BBB表示本地分支和遠程分支同名,缺省AAA:BBB表示HEAD分支,origin唯一的時候也可以缺省)
(3)fetch一般用於獲得本地不存在的分支,或者已知本地和遠程分支有沖突想要先檢查區別再合並的情況
fetch會修改FETCH_HEAD指針,記錄在本地的一個文件中,指向著目前已經從遠程倉庫取下來的分支的末端版本。(也當做一個分支名稱就可以了)
git fetch origin AAA:BBB(同上)
(這裏比較坑的一點即是缺省AAA:BBB表示的是master分支,不!是!HEAD!)
(4)git diff AAA:BBB 比較AAA分支到BBB分支的變化,如果結果太長建議使用重定向,讓結果輸出到文件(例如git diff AAA:BBB > a.diff )
(缺省:BBB,表示AAA分支到當前HEAD分支的變化,例如git diff FETCH_HEAD)
關於diff輸出的標記符號:
參考:http://blog.csdn.net/zcube/article/details/42246331
@@ -AAA分支的起始行號,AAA分支的結束行號(如果之後一行逗號後面省略) +BBB分支的起始行號,BBB分支的結束行號(只有一行逗號後面省略) @@
(5)git merge AAA 表示AAA分支合並到當前分支(缺省AAA表示FETCH_HEAD分支合並到當前分支)
如果發生沖突,需要自己去文件中修改,文件中的標記如下:
<<<<<<<到=======是當前分支的文件內容,=======到>>>>>>>是合並文件的文件內容
7、棧
一般用於兩種情況
(1)自己在本地上做了一些修改但由於沒完成還不想提交,發現遠程也做了一些修改,所以可以先把本地的修改加入到棧中,然後pull,在讀出修改信息
(2)在開發中突然發現一個更重要的問題需要修改測試,可以把當前的部分沒完成的工作加入到棧中
git stash 把所有unstaged和staged的文件修改加入到棧中
git stash pop 讀出棧的修改(如發生沖突需要自己去修改)
git stash drop 扔掉棧中的第一條
git stash clear 清空棧
就先寫到這裏,其他的補充以後再添加
GIT原理和常用命令速成