工作中g(shù)it是一項(xiàng)必不可少的技能尔苦,在項(xiàng)目的開發(fā)進(jìn)程中起著至關(guān)重要的作用
下面介紹一些git在工作中的一些使用實(shí)踐涩馆、常用流程行施、常用命令,供大家參考魂那!
一:前言
Git的定義是:分布式版本控制系統(tǒng)蛾号,用于項(xiàng)目開發(fā)中的版本控制。
從本質(zhì)上來(lái)講 Git 是一個(gè)內(nèi)容尋址(content-addressable)文件系統(tǒng)涯雅,并在此之上提供了一個(gè)版本控制系統(tǒng)的用戶界面鲜结。
Git 的核心部分是一個(gè)簡(jiǎn)單的鍵值對(duì)數(shù)據(jù)庫(kù)(key-value data store)。你可以向該數(shù)據(jù)庫(kù)插入任意類型的內(nèi)容活逆,它會(huì)返回一個(gè)鍵值精刷,通過(guò)該鍵值可以在任意時(shí)刻再次檢索(retrieve)該內(nèi)容。
git管理的項(xiàng)目工作目錄下的每一個(gè)文件都不外乎這兩種狀態(tài):已跟蹤或未跟蹤蔗候。
已跟蹤的文件是指那些被納入了版本控制的文件怒允,在上一次快照中有它們的記錄,在工作一段時(shí)間后锈遥,它們的狀態(tài)可能處于未修改纫事,已修改或已放入暫存區(qū)。
工作目錄中除已跟蹤文件以外的所有其它文件都屬于未跟蹤文件迷殿,它們既不存在于上次快照的記錄中,也沒有放入暫存區(qū)咖杂。
初次克隆某個(gè)倉(cāng)庫(kù)的時(shí)候庆寺,工作目錄中的所有文件都屬于已跟蹤文件,并處于未修改狀態(tài)诉字。
Git 保存的不是文件的變化或者差異懦尝,而是一系列不同時(shí)刻的文件快照。
在進(jìn)行提交操作時(shí)壤圃,Git 會(huì)保存一個(gè)提交對(duì)象(commit object)陵霉。該提交對(duì)象會(huì)包含一個(gè)指向暫存內(nèi)容快照的指針。但不僅僅是這樣伍绳,該提交對(duì)象還包含了作者的姓名和郵箱踊挠、提交時(shí)輸入的信息以及指向它的父對(duì)象的指針。
二:git存儲(chǔ)
git將項(xiàng)目的存儲(chǔ)分為4部分冲杀,每部分有自己作用效床,見下圖:(圖片來(lái)自:博客)
Workspace
:工作區(qū)(當(dāng)前用戶操作修改的區(qū)域)Index/Stage
:暫存區(qū) (add后的區(qū)域)Repository
:倉(cāng)庫(kù)區(qū)或本地倉(cāng)庫(kù)(commit后的區(qū)域)Remote
:遠(yuǎn)程倉(cāng)庫(kù)(push后的區(qū)域)
整體過(guò)程可以簡(jiǎn)述為:
工作區(qū)-->
add
-->暫存區(qū)-->commit
-->本地倉(cāng)庫(kù)區(qū)-->push
-->遠(yuǎn)程倉(cāng)庫(kù)區(qū)遠(yuǎn)程倉(cāng)庫(kù)區(qū)-->
fetch
-->使用refs\remotes下對(duì)應(yīng)分支文件記錄遠(yuǎn)程分支末端commit_id 和 本地倉(cāng)庫(kù)區(qū) -->merge
-->工作區(qū)遠(yuǎn)程倉(cāng)庫(kù)區(qū)-->
pull
-->使用refs\remotes下對(duì)應(yīng)分支文件記錄遠(yuǎn)程分支末端commit_id and 本地倉(cāng)庫(kù)區(qū) and 工作區(qū)
git pull和git fetch有什么不同呢?下面簡(jiǎn)單說(shuō)一下
想要知道他們得不同权谁,我們需要先了解兩個(gè)概念
FETCH_HEAD
:可以看做是一個(gè)版本鏈接剩檀,記錄在本地的refs\remotes下對(duì)應(yīng)分支文件中,指向著目前已經(jīng)從遠(yuǎn)程倉(cāng)庫(kù)取下來(lái)的分支的最新版本的commit_id旺芽。commit-id
:在每次本地commit來(lái)保存當(dāng)前工作到本地倉(cāng)庫(kù)區(qū)后沪猴, 會(huì)產(chǎn)生一個(gè)commit-id辐啄,這是一個(gè)能唯一標(biāo)識(shí)一個(gè)版本的序列號(hào)。在使用git push后运嗜,這個(gè)序列號(hào)還會(huì)同步到遠(yuǎn)程倉(cāng)庫(kù)壶辜。
所以他們之間的不同在于:
git pull
直接將遠(yuǎn)程分支的修改更新到本地倉(cāng)庫(kù)區(qū)和本地工作區(qū),我們就可以在本地工作區(qū)中看到最新代碼git fetch
只將遠(yuǎn)程分支的修改拉取到本地倉(cāng)庫(kù)洗出,并更新到FETCHHEAD士复,記錄遠(yuǎn)程分支最新的commitid,不會(huì)更新本地工作區(qū)代碼翩活,只有使用了git merge
才會(huì)將提交更新到本地倉(cāng)庫(kù)區(qū)和工作區(qū)
其他想要了解更多git內(nèi)部消息請(qǐng)移步我的另一篇博文:git內(nèi)部存儲(chǔ)實(shí)現(xiàn)機(jī)制
在 git status中
的體現(xiàn)阱洪,見下圖:
Changesto be committed
::代表被add的文件,被加載到了暫存區(qū)Changesnotstagedforcommit
:代表在當(dāng)前分支中被修改的文件菠镇,還沒有被add冗荸,存儲(chǔ)在工作區(qū)Untrackedfiles
:代表不被git追蹤的文件,可以理解為不被git管理的文件如果沒有Changes to be committed和Changes not staged for commit說(shuō)明現(xiàn)階段所有的修改已經(jīng)被commit到本地倉(cāng)庫(kù)
如果git status后出現(xiàn)下述情況利耍,說(shuō)明還有已經(jīng)的commit到本地倉(cāng)庫(kù)的還未被push到遠(yuǎn)程倉(cāng)庫(kù)
Git 作為一個(gè)系統(tǒng)蚌本,是以它的一般操作來(lái)管理并操縱(HEAD、index隘梨、Working Directory)三棵樹的
HEAD:
是當(dāng)前分支引用的指針程癌,它總是指向該分支上的最后一次提交。這表示 HEAD 將是下一次提交的父結(jié)點(diǎn)轴猎。通常嵌莉,理解 HEAD 的最簡(jiǎn)方式,就是將它看做 你的上一次提交的快照捻脖。index:
index索引是你的 預(yù)期的下一次提交锐峭。我們也會(huì)將這個(gè)概念引用為 Git 的 “暫存區(qū)域”,這就是當(dāng)你運(yùn)行 git commit 時(shí) Git 看起來(lái)的樣子可婶。Git 將上一次檢出到工作目錄中的所有文件填充到索引區(qū)沿癞,它們看起來(lái)就像最初被檢出時(shí)的樣子。之后你會(huì)將其中一些文件替換為新版本矛渴,接著通過(guò) git commit 將它們轉(zhuǎn)換為樹來(lái)用作新的提交椎扬。WorkingDirectory:
最后,你就有了自己的工作目錄具温。另外兩棵樹以一種高效但并不直觀的方式盗舰,將它們的內(nèi)容存儲(chǔ)在 .git 文件夾中。工作目錄會(huì)將它們解包為實(shí)際的文件以便編輯桂躏。
如下圖:
三:git提交規(guī)則
首先钻趋,有個(gè)問(wèn)題需要確認(rèn)一下,提交信息是使用中文還是英文呢剂习?
如果你的項(xiàng)目是開源項(xiàng)目并且面向國(guó)際的開源項(xiàng)目蛮位,類似于阿里的Druid\PingCAP的TiDB等较沪,那么一定要是用英文提交信息的!如果你的項(xiàng)目是公司內(nèi)部使用或者只會(huì)被公司內(nèi)部開發(fā)修改失仁,那么中文也是不錯(cuò)的尸曼,更加便于查看和管理。當(dāng)然萄焦,開發(fā)組中的英文能力都不錯(cuò)的話控轿,用英文也是可以的。
分支Branch管理:如果沒有一個(gè)好的branch管理的話拂封,可能會(huì)有下述圖的情況茬射,刺不刺激~
推薦的分支管理:
master
分支為主分支(保護(hù)分支),禁止直接在master上進(jìn)行修改代碼和提交冒签,此分支的代碼可以隨時(shí)被發(fā)布到線上在抛;develop
分支為測(cè)試分支或者叫做合并分支,所有開發(fā)完成需要提交測(cè)試的功能合并到該分支萧恕,該分支包含最新的更改刚梭;feature
分支為開發(fā)分支,大家根據(jù)不同需求創(chuàng)建獨(dú)立的功能分支票唆,開發(fā)完成后合并到develop分支朴读;fix
分支為bug修復(fù)分支,需要根據(jù)實(shí)際情況對(duì)已發(fā)布的版本進(jìn)行漏洞修復(fù)走趋;
標(biāo)簽Tag管理:Tag采用三段式:v版本.里程碑.序號(hào)(v2.3.1)
架構(gòu)升級(jí)或架構(gòu)重大調(diào)整衅金,修改第1位
新功能上線或者模塊大的調(diào)整,修改第2位
bug修復(fù)上線吆视,修改第3位
當(dāng)然典挑,可以根據(jù)實(shí)際情況來(lái)設(shè)計(jì)酥宴,比如項(xiàng)目特別大啦吧,可以使用四段表達(dá)Tag,項(xiàng)目比較小也可以使用二段式Tag拙寡,只要符合場(chǎng)景并有實(shí)際意義即可 授滓!
提交信息格式:下面只是提供一種建議格式,大家可以根據(jù)自己的項(xiàng)目實(shí)際情況來(lái)定格式肆糕,只要能把當(dāng)前提交表達(dá)清楚,格式統(tǒng)一,方便快速閱讀和定位即可般堆!
1.建議中文示例:
<新功能>(urllAnalyz) 添加解析url功能l
<修改>(TestServiceImpl) 修改某功能的某個(gè)實(shí)現(xiàn)為另一個(gè)實(shí)現(xiàn)
<bug修復(fù) style="margin: 0px; padding: 0px; box-sizing: border-box;">(TestUnti) 修復(fù)url特殊情況下解析失敗問(wèn)題 (issue#12)</bug修復(fù)>
<重構(gòu)>(getData) 重構(gòu)獲取數(shù)據(jù)的方法
<測(cè)試>(getDataTest) 添加(修改、刪除)獲取數(shù)據(jù)的單元測(cè)試代碼
<文檔>(doc)修改(添加诚啃、刪除)文檔
2.建議的英文示例:
feat:新功能(feature)
style:格式
fix:修補(bǔ)bug
refactor:重構(gòu)
test:測(cè)試相關(guān)
docs:文檔(documentation)
3.格式(type:scope:body:issue) :<|新功能|修改|Bug修復(fù)|重構(gòu)|測(cè)試>(影響模塊)提交描述信息(#issue?)
4.優(yōu)點(diǎn):
與github數(shù)據(jù)issue關(guān)聯(lián)淮摔,便于通過(guò)issue獲取更多信息
commit 提交時(shí),格式統(tǒng)一始赎,便于后續(xù)快速準(zhǔn)確定位提交
可以更好的將此次提交表述清楚
四:Git操作過(guò)程
4.1 初始化項(xiàng)目和橙,并上傳到git服務(wù)器
基本過(guò)程:創(chuàng)建遠(yuǎn)程倉(cāng)庫(kù)仔燕、初始化本地git倉(cāng)庫(kù)、將本地倉(cāng)庫(kù)與遠(yuǎn)程倉(cāng)庫(kù)關(guān)聯(lián)起來(lái)魔招、添加本地倉(cāng)庫(kù)想要提交的代碼到本地git緩沖區(qū)晰搀,將本地倉(cāng)庫(kù)的本地分支與遠(yuǎn)程倉(cāng)庫(kù)的遠(yuǎn)程分支關(guān)聯(lián)起來(lái)、提交代碼
在git服務(wù)器上創(chuàng)建同名git項(xiàng)目办斑,并獲取http地址
本地git初始化項(xiàng)目git倉(cāng)庫(kù)外恕,在項(xiàng)目目錄下
git init
將本地git倉(cāng)庫(kù)和遠(yuǎn)程倉(cāng)庫(kù)關(guān)聯(lián)起來(lái),并設(shè)置遠(yuǎn)程倉(cāng)庫(kù)名稱
git remote add<name><http地址>
其中http地址為上述第一步獲取的遠(yuǎn)程倉(cāng)庫(kù)的地址乡翅,name一般為origin鳞疲,當(dāng)然也可以設(shè)置其他的名字 例如:git remote add origin http://igit.corp.com/my/test.git
4\. 添加項(xiàng)目文件到本地git緩沖區(qū) `git add-A` `git commit-m` '初始化項(xiàng)目' 或者 `git commit-a-m` '初始化項(xiàng)目'
5\. 將本地分支關(guān)聯(lián)遠(yuǎn)程分支并提交,git默認(rèn)在遠(yuǎn)程分支上創(chuàng)建于本地分支同名的分支 `git push--set-upstream origin master`
這就是將本地的master分支 與 origin遠(yuǎn)程倉(cāng)庫(kù)關(guān)聯(lián)起來(lái)并在遠(yuǎn)程倉(cāng)庫(kù)創(chuàng)建同名master分支峦朗,以后本地master都提交到遠(yuǎn)程倉(cāng)庫(kù)中的origin/master分支上建丧。
upstream:上游的意思
至此,應(yīng)該就可以了波势,我們可以在git服務(wù)器上刷新看看是否提交上去了
4.2 提交某一分支的修改
查看當(dāng)前分支的修改
git status
查看想要查看的文件的修改
git diff<file_name>
確認(rèn)正確后翎朱,提交修改到暫存區(qū)
git add-A或者git add<file_name><file_name>
提交到本地倉(cāng)庫(kù)
git commit-m'提交信息'
提交到遠(yuǎn)程倉(cāng)庫(kù)
git push
4.3 拉取遠(yuǎn)程分支修改到本地分支
當(dāng)遠(yuǎn)程分支別人推了一版新的代碼時(shí),我們想要將代碼拉下來(lái)尺铣,可以采用兩種方式pull 和 fetch+merge:(他們的不同點(diǎn)文章上面已經(jīng)解釋)
使用pull:
- 將遠(yuǎn)程分支最新代碼更新合并到本地倉(cāng)庫(kù)區(qū)和工作區(qū)
git pull
使用fetch:
將遠(yuǎn)程所有分支最新的commitid更新到FETCHHEAD拴曲,記錄遠(yuǎn)程分支最新的commit_id 和 本地倉(cāng)庫(kù)區(qū)
git fetch
將最新的代碼合并到工作區(qū)
git merge
4.4 取消track某一文件
git rm-r--cache<file_name>
untrack后,使用commit -a 時(shí)凛忿,不會(huì)將其添加到暫存區(qū)中
- 之后會(huì)在.ignore文件中將該untrack的文件添加進(jìn)去澈灼,完成
4.5 保存賬號(hào)密碼,避免每次push都要輸入(簡(jiǎn)單方法)
確保在git中手動(dòng)輸入過(guò)賬號(hào)和密碼
輸入下面語(yǔ)句即可
git config--globalcredential.helper store
4.6 暫存自己的修改店溢,便于接著工作(特別有用)
試想一個(gè)場(chǎng)景:如果你正在一個(gè)分支上工作修改叁熔,leader讓你改另外的分支的BUG或者對(duì)其他的分支做一些操作。
我們知道如果一個(gè)分支上有還沒有commit的修改的話床牧,不可以切換分支荣回,但是又因?yàn)樽约旱墓ぷ鬟€未完成,不想commit戈咳,此時(shí) git stash
就起作用了心软。
你要把現(xiàn)在正在工作的分支保存下來(lái),等處理完其他的再回來(lái)接著當(dāng)前分支的修改工作著蛙。
1\. 將當(dāng)前分支的修改暫存起來(lái)(此處不等于add+commit) `git stash`
備份當(dāng)前的工作區(qū)的內(nèi)容删铃,從最新的一次提交中讀取相關(guān)內(nèi)容,讓工作區(qū)保證和上次提交的內(nèi)容一致踏堡。同時(shí)猎唁,將當(dāng)前的工作區(qū)修改的內(nèi)容保存到Git棧中暫存起來(lái)。
2\. 切換到別的分支工作顷蟆,完成后切換回原來(lái)的工作分支诫隅,查看暫存列表 `git stash list`
顯示Git棧內(nèi)的所有備份缎患,可以利用這個(gè)列表來(lái)決定從那個(gè)地方恢復(fù)
3\. 恢復(fù)暫存的修改到工作區(qū) `git stash apply<stash_name>` 恢復(fù)暫存之后不刪除暫存
從Git棧中讀取最新一次保存的內(nèi)容,恢復(fù)工作區(qū)的相關(guān)內(nèi)容阎肝。
git stash pop
恢復(fù)暫存之后刪除暫存
從Git棧中讀取最新一次保存的內(nèi)容挤渔,恢復(fù)工作區(qū)的相關(guān)內(nèi)容。之后pop會(huì)刪除最新的暫存风题。
4\. 刪除“暫存” `git stash drop<stash_name>`
從Git棧刪除最舊的一個(gè)暫存
結(jié)束
4.7 將文件修改回退到某一狀態(tài)
一些已經(jīng)提交的或者已經(jīng)修改的部分判导,想要再修改一下,或者刪除已經(jīng)提交的
a. 刪除某些commit沛硅,將head重定位到某一commit(回溯到以前的版本)
git reset--hard<commit_id>
注意Q廴小!摇肌!上述命令會(huì)將commit_id前的所有commit修改刪除
git reset<commit_id>
上述命令不會(huì)將commit_id前的commit刪除擂红,而是會(huì)將修改回退到本地工作區(qū)
git push origin HEAD--force
此步驟將服務(wù)器方也設(shè)置為相應(yīng)的commit
b. 將文件修改恢復(fù)到當(dāng)前已提交分支的原樣(未 git add 情況下) 撤銷修改就回到和版本庫(kù)一模一樣的狀態(tài),即用版本庫(kù)里的版本替換工作區(qū)的版本
git checkout--<file_name>
c. 將文件修改恢復(fù)到當(dāng)前已提交分支的原樣(已經(jīng) git add 情況下)
git reset HEAD
將add退回
git checkout--<file_name>
d. 將文件修改恢復(fù)到已提交分支的原樣(已經(jīng) git commit 情況下)
git reset<commit_id>
此處commit_id可以是任意分支的commit_id
git checkout--<file_name>
4.8 版本的回溯與前進(jìn)
有時(shí)候需要回溯或前進(jìn)到以前的版本 或 回溯前進(jìn)到以前的commit
只要記住commit_id就可以在版本之間來(lái)回的穿梭围小,注意是可以“來(lái)回”穿梭哦
獲取需要回溯到版本的commitid
git log
--> 復(fù)制所需的版本commitid回退到該版本
git reset--hard<commit_id>
如果想讓服務(wù)器也回退到該版本的話
git push origin HEAD--force
五:Git常用命令
初始化項(xiàng)目為git項(xiàng)目
git init
clone服務(wù)器代碼到本地
git clone<http_url>
添加修改文件到暫存區(qū)
git add<file_name>
git add-A
添加所有修改文件到暫存區(qū)
提交修改到本地倉(cāng)庫(kù)
git commit-m'提交信息'
git commit-a-m'提交信息'
相當(dāng)于git add -A + git commit -m 的整合
提交本地倉(cāng)庫(kù)的修改到遠(yuǎn)程倉(cāng)庫(kù)
git push
將遠(yuǎn)程庫(kù)<remote_name style="margin: 0px; padding: 0px; box-sizing: border-box;">的遠(yuǎn)程分支<branch_name style="margin: 0px; padding: 0px; box-sizing: border-box;">作為當(dāng)前分支的上游分支</branch_name></remote_name>
git push--set-upstream<remote_name><branch_name>
<remote_name style="margin: 0px; padding: 0px; box-sizing: border-box;">為遠(yuǎn)程倉(cāng)庫(kù)的別名昵骤,一般為origin</remote_name>
查看文件本次的修改
git diff
顯示本次所有被修改文件的修改
git diff<file_name>
顯示該文件本次的修改
查看當(dāng)前分支下當(dāng)前狀態(tài)
git status
顯示出被修改的文件和提交的次數(shù)等
查看提交歷史
git log
git log--graph
查看分支合并圖
merge其他分支到當(dāng)前分支
git merge<branch_name>
在merge過(guò)程如果出現(xiàn)沖突,在解決沖突后會(huì)產(chǎn)生一個(gè)新的commit肯适,并且HEAD指向該commit 如果沒有沖突变秦,HEAD會(huì)在分支的最新commit上
切換到上一個(gè)分支
git checkout-
切換到其他分支
git checkout<branch_name>
在某一分支基礎(chǔ)上創(chuàng)建新分支
git checkout<branch_name>
切換到基礎(chǔ)分支
git checkout-b<new_branch_name>
在當(dāng)前分支基礎(chǔ)上 創(chuàng)建新分支
顯示分支
git branch
所有本地分支
git branch-r
所有遠(yuǎn)程分支
git branch-a
所有分支,本地和遠(yuǎn)程
刪除本地分支
git branch-D<branch-name>
刪除遠(yuǎn)程分支
git push origin--delete<branch-name>
添加一個(gè)新的遠(yuǎn)程倉(cāng)庫(kù)
git remote add<shortname><url>
在同一個(gè)項(xiàng)目的git url中可以添加多個(gè)遠(yuǎn)程倉(cāng)庫(kù) 每個(gè)倉(cāng)庫(kù)相互隔離有自己的分支管理
將本地分支與遠(yuǎn)程倉(cāng)庫(kù)中分支聯(lián)系起來(lái)
git push--set-upstream<遠(yuǎn)程倉(cāng)庫(kù)名稱><遠(yuǎn)程倉(cāng)庫(kù)中分支名稱>
以后本地的該分支的push框舔,會(huì)默認(rèn)提交到設(shè)置的遠(yuǎn)程倉(cāng)庫(kù)中遠(yuǎn)程分支中
刪除遠(yuǎn)程倉(cāng)庫(kù) git remote rm<遠(yuǎn)程倉(cāng)庫(kù)name>
刪除本地tag git tag-d<tag_name>
刪除遠(yuǎn)程tag git push origin:refs/tags/<tag_name>
查看tag信息 git show<tag_name>
暫存當(dāng)前修改 git stash
查看暫存列表 git stash lsit
恢復(fù)暫存的修改
git stash apply
(恢復(fù)后不刪除暫存)
git stash pop
(恢復(fù)后刪除暫存)
刪除暫存 git stash drop
撤回已經(jīng)add到暫存區(qū)的文件到本地工作區(qū)
git reset HEAD<file_name>
git reset HEAD
回退所有add
add會(huì)被標(biāo)識(shí)為Changes to be committed蹦玫,取消add后標(biāo)識(shí)為Changes not staged for commit(不等于untrack)
取消track某一文件 git rm-r--cache<file_name>
untrack后,使用commit -a 時(shí)刘绣,不會(huì)將其添加到暫存區(qū)中
只merge某一個(gè)分支上的某一個(gè)commit git cherry-pick<被merge分支中的某一個(gè)commit的commit-id>
撤銷在本地工作區(qū)的文件的修改
撤銷修改就回到和版本庫(kù)一模一樣的狀態(tài)樱溉,即用版本庫(kù)里的版本替換工作區(qū)的版本 git checkout--<file_name>
刪除某些commit,將head重定位到某一commit(回溯到以前的版本)
git reset--hard<commit_id>
git push origin HEAD--force
此步驟將服務(wù)器方也設(shè)置為相應(yīng)的commit
刪除本地在遠(yuǎn)程服務(wù)器上不存在的分支 git remote prune origin
拉取遠(yuǎn)程分支到本地 git fetch origin<branch_name>
新建一個(gè)tag到指定commit
git tag<tag_name><commit_id>
git tag<tag_name>
當(dāng)前commit
取消當(dāng)前合并纬凤,重建合并前狀態(tài) git merge--abort
總結(jié)
本文介紹了Git是什么福贞、Git的存儲(chǔ)結(jié)構(gòu)、Git的提交規(guī)則和一些工作中常會(huì)用到的git操作的過(guò)程移斩,最后總結(jié)了常用的命令肚医。Git在工作中的團(tuán)隊(duì)開發(fā)中起著至關(guān)重要的作用绢馍,希望本篇文章可以對(duì)大家有些許幫助~
更多技術(shù)文章向瓷,歡迎關(guān)注博主!