Git筆記及實踐經驗

最近使用Git時感到有些生疏,所以利用晚上空余時間將廖雪峰Git教程重新系統的學習一邊并做了筆記,溫故知新。


Git簡介

Git是目前世界上最先進的分布式版本控制系統。

集中式vs分布式

CVS和SVN是集中式的版本控制系統,Git是分布式版本控制系統。

集中式:

版本庫是集中存放在中央服務器的,在工作室都用自己的電腦,要先從中央服務器取得最新的版本,然后開始干活,干完活再把自己的或推送到中央服務器。集中式版本控制系統最大毛病是必須聯網才能工作。

分布式:

分布式版本控制系統根本沒有“中央服務器”,每個人的電腦上都是一個完整的版本庫,這樣你工作時就不須聯網了,因為版本庫就在你電腦中。既然每個人電腦上都有完整的版本庫,那多人何如協作呢?比方你在電腦修改了文件A,你同事也在他電腦中修改了文件A,這時你們只需把各自修改推送給對方就可以互相看到對方修改了。

相比集中式,分布式安全性要更高些。Git優勢不單是不必聯網這么簡單,Git極其強大的分支管理,把SVN遠遠拋在后面。

版本庫版本管理

版本庫(repository)又名倉庫,可以簡單理解為一個目錄,這個目錄里面所有文件都可以被Git管理起來,每個文件的修改、刪除,Git都能跟蹤,一遍任何時刻都能追蹤歷史,或者在將來某時刻可以還原。

- git init

通過git init命令可以吧當前目標變成Git可以管理的倉庫。瞬間Git就把倉庫建好并告訴你這是個空的倉庫,且目錄下多一個.git目錄,這個目錄是Git來跟蹤管理版本庫的,沒事不要手動修改這個目錄的文件。

- git add 與git commit

在該倉庫目錄下先用命令git add readme.txt告訴Git,把文件添加到倉庫。執行上面命令,沒有任何顯示則表明成功。Unix的哲學就是“沒有消息就是好消息”。第二步,用命令git commit告訴Git,把文件提交到倉庫。git commit -m "wrote a readme file",其中-m后面輸入的是本提交的說明,可以輸入任意內容,方便在歷史記錄中查找改動。git commit命令成功后會告訴你,1個文件被改動(新添加的readme文件),插入了兩行內容。

為什么Git添加文件需要add,commit兩步呢?

因為commit可以一次提交很多文件,所以你可以多次add不同的文件。

- git status

當修改了文件后,運行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
#
no changes added to commit (use "git add" and/or "git commit -a")

可以讓我們時刻掌握倉庫當前的狀態,命令告訴我們readme被修改過但還沒準備提交修改。

- git diff

git diff可以查看文件具體修改了什么內容。輸入git diff readme.txt

$ git diff readme.txt 
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
 Git is free software.

- git log

commit了數次版本后,可以使用git log命令顯示從最近到最遠的提交日志。如果覺得輸出信息太多,可以加上--pretty=oneline參數。

- git reset

我們準備把readme文件會退到上一個版本,首先Git必須知道當前版本是哪個版本,在Git中,用HEAD表示當前版本,上個版本就是HEAD^,上上個版本就是HEAD^^,往上100個版本可寫成HEAD~100

輸入git reset -- hard HEAD^即可回到上個版本,此時用git log再看版本庫狀態發現之前版本消失了。如果想再回去,只要順著命令行串口向上找,找到那版本的commit id然后再運行``git reset -- hard 95d933`就又可以回到未來的那版本了。

Git版本回退速度非常快,因為Git在內部有個指向當前版本的HEAD指針。HEAD指向版本就是當前版本,因此Git允許我們在版本歷史之間穿梭。穿梭前用git log可以查看提交歷史,以便確定要退回哪個版本。要重返未來,用git reflog查看命令歷史,以便確定要會帶未來的哪個版本。

工作區和暫存區

工作區(Working Directory):就是你在電腦里能看到的目錄。

版本庫(Repository):工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。Git的版本庫里存了很多東西,其中最重要的是stage(或叫index)的暫存區。還有Git為我們自動創建了第一個分支master,以及指向master的一個指針叫HEAD

前面講吧文件往Git版本庫里添加時分兩步執行:git add,實際就是把文件修改添加到暫存區。git commit,實際上是把暫存區的所有內容提交到當前分支。因為我們創建Git版本庫時,Git自動為我們創建了唯一一個master分支,所以現在git commit就是往這個分支上提交修改。

- git checkout

使用git checkout --file可以把file文件在工作區的修改全部撤銷,即讓這個文件回到最近一次git addgit commit時的狀態。這里必須在checkout后寫明文件,否則就變成“切換到另一個分支”的命令了。

如果想撤銷掉已添加到暫存區的修改,用命令git reset HEAD file可以把暫存區的修改撤銷掉,重新放回工作區。git reset命令既可以回退版本,也可以把暫存區的修改回退到工作區。然后再按上面步驟撤銷工作區。

- git rm

在Git中,刪除也是一個修改操作。一般情況下會在終端調用命令rm file刪除文件,Git知道你刪除了文件,因此工作區和版本庫就不一致了。此時可以從版本庫中刪除這個文件,使用git rm刪掉并且git commit,文件就從版本庫中刪除了。如果是刪錯了,因為版本庫中還有,則使用git checkout --file就可把文件恢復了。git checkout其實是用版本庫里的版本替換工作區的版本,無論工作區是修改還是刪除,都可以還原。

遠程倉庫

Git是分布式版本控制系統,同一個Git倉庫可以分布到不同的機器上。最早肯定是只有一臺機器有原始版本庫,伺候別的機器可以“克隆”這個原始版本庫,而且每臺機器的版本庫都一樣不分主次。實際情況常是找一臺電腦充當服務器的角色,其他每個人都從這個“服務器”倉庫克隆一份到自己電腦上并且各自把各自的提交推送到服務器倉庫里,也從服務器倉庫中拉取別人的提交。

GitHub就是提供Git倉庫托管服務的,只要注冊一個GitHub賬號就可以免費獲得Git遠程倉庫。假設我們從零開發,最好的方式是先創建遠程庫,然后再從遠程庫克隆。

使用命令git clone克隆一個本地庫,如git clone git@github.com:orwater/cleargit.git

分支管理

在版本回退時我們已經知道,每次提交Git都辦它們穿成一條時間線,這條時間線就是分支。截至目前只有一條時間線,在Git里這個分支叫主分支,即master分支。HEAD嚴格來說不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是當前分支。

一開始時,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當前分支,以及當前分支的提交點。每次提交,master分支都會向前移動一部,這樣隨著不斷提交,master分支線也越來越長。

當我們創建新的分支,例如dev時,Git新建一個指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當前分支在dev上了。

從現在開始,對工作區的修改和提交就是針對dev分支了,比如新的提交一次后,dev指針往前移動一步,而master指針不變。

假如我們在dev上的工作完成了,就可以把dev合并到master上,最簡單的方法是直接把master指向dev的當前提交完成合并。

合并完分支后,甚至可以刪除dev分支。刪除dev分支就是刪除dev指針,最后就剩下一條主分支了。

  • 創建分支

首先我們創建dev分支,然后切換到上面,git checkout -b dev,-b參數表示創建并且切換。

然后可以用git branch命令查看當前分支。

可以使用命令git checkout master切換回主分支。

如果要把dev分支的工作結果合并到master上,使用git merge命令用于合并指定分支到當前分支。git merge dev

合并完成后,就可以使用git branch -d dev刪除分支了。

  • 解決沖突

創建個feature1新分支,修改readme文件并提交。然后切換到主分支再對readme文件做不同的修改并提交。

這種情況下,Git無法執行“快速合并”,只能試圖把各自的修改合并起來,但這種合并可能會有沖突。

$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

Git提示readme文件存在沖突,必須手動解決沖突后再提交。這時我們查看readme文件:

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

Git用<<<<<<<,=======,>>>>>>>>標記出不同分支的內容。這樣進行修改后再提交就可以了。

  • 分支合并策略

通常,合并分支時,如果可能,Git會用Fast forward模式,但這種模式下刪除分支后會丟掉分支信息。如果要強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣從分支歷史上就可以看出分支信息了,知道曾經做個合并。

使用--no-ff參數的git merge表示禁用Fast forward模式。因為本次合并要創建一個新的commit,所以加上-m參數。

$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
 readme.txt |    1 +
 1 file changed, 1 insertion(+)

在實際開發中,我們應該按照幾個基本原則進行分支管理:

首先。master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活。干活都在dev分支上,其分支不穩定,到摸個時候再把分支合并到主分支上,在主分支發布版本。團隊成員都在dev上干活,每個人都有自己的分支,是不是往dev分支上合并就可以了。

- git stash

軟件開發中,修復bug時,在Git中由于分支是如此強大,所以每個bug都可以通過一個新的臨時分支來修復,修復后合并分支再將臨時分支刪除。

如果正在工作時要修復一個bug,就要先創建一個臨時分支來修復。但手頭工作還沒完成不能提交。這時應使用Git提供的stash功能,可以把當前工作現場存儲起來,等以后恢復現場后繼續工作。

$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge

現在再用git status查看工作區就是干凈的了。

當修復好bug后再切換回dev分支要恢復之前內容,有兩個方法:

一種是用git stash apply恢復,但恢復后,stash內容并不刪除,須再調用git stash drop來刪除。

另一種方法是用git stash pop,恢復的同事把stash內容也刪除。再用git stash list查看就看不到任何stash內容了。你可以多次stash,恢復時先用git stash list查看,然后再恢復指定的stashgit stash apply stash@{0}

  • 多人協作

當你從遠程倉庫克隆時,實際上Git自動把本地的master分支和遠程的master分支對應起來了,并且遠程倉庫默認名稱是origin。要查看遠程庫的信息,用git remote,添加-v參數顯示更詳細信息。

$ git remote -v
origin  git@github.com:michaelliao/learngit.git (fetch)
origin  git@github.com:michaelliao/learngit.git (push)

上面顯示了可以抓取和推送的origin地址,如果沒有推送權限就看不到push地址。

- git push

推送分支,就是把該分支上的所有本地提交推送到遠程庫。推送時,要制定本地分支,Git就會把該分支推送到遠程庫對應的遠程分支上。git push origin master

但是并不是一定要把本地分支往遠程推送,那么哪些分支需要推送?

  • master分支是主分支,因此要時刻與遠程同步。
  • dev分支是開發分支,團隊所有成員都需要在上面工作,所以要與遠程同步。
  • bug分支只用于在本地修復bug,就沒必要推到遠程了。

總之Git中分支可以再本地自己藏著玩,是否推送視情況而定。

多人協作的工作模式通常是這樣:

  1. 首先,可以試圖用git push origin branch -name推送自己的修改
  2. 如果推送失敗,則因為遠程分支比你本地更新,需要先用git pull試圖合并
  3. 如果合并有沖突,則解決沖突,并在本地提交;
  4. 沒有沖突或解決沖突后,再用git push origin branch -name推送即可。

如果git pull提示“no tracking information”,則說明本地分支和遠程分支的鏈接關系沒有創建,用命令git branch --set-upstream branch -name origin/branch -name

標簽管理

在發布一個版本時,通常先在版本庫中打一個標簽(tag),這樣就唯一確定了打標簽時刻的版本。將來無論什么時候,取某個標簽的版本就是把那個打標簽時刻的歷史版本取出來。所以,標簽也是版本庫的一個快照。

Git的標簽歲談事版本庫的快照,但其實他就是指向某個commit的指針,所以創建和刪除標簽都是瞬間完成的。相比于難記的commit id,tag是一個讓人容易記住的名字,它跟某個commit綁定在一起。

- git tag

使用命令git tag<name>可以打一個新標簽,使用命令git tag可查看所有標簽。默認標簽是打在最新提交的commit上的,如果想之前的commit打標簽可以先找到是歷史提交的commit id,然后打命令git tag v0.9 6224937即可。


最后附一張Git Cheat Sheet


Git分支最佳實踐

- 主要分支:

中央倉庫有兩個長期的分支:

  • master
  • develop

master用作生產分支,里面的代碼是準備部署到生產環境的。develop是可交付的開發代碼,也可以看作用于集成分支,每晚構建從`develop獲取代碼。當develop分支中的代碼足夠穩定時,就將改動合并到master``分支,同時打上一個標簽,標簽名稱為發布的版本號。

- 輔助分支

通過輔助分支來幫助并行開發,和主要分支不同,這些分支的生命周期是有限的:

  • 特性分支
  • 發布分支
  • 緊急修復分支

特性分支:

特性分支可能從develop分支分出,最終必須合并回develop。特性分支用于開發新特性。每個新特性開一個新分支,最終會合并會develop。特性分支只存在于開發者的倉庫中。

創建新的特性分支:

git checkout -b myfeature develop

合并回develop:

git checkout develop
git merge --no-ff myfeature
git branch -d myfeature
git push origin develop

使用--no-ff確保總是新生成一個提交,避免丟失曾經存在一個特性分支的歷史信息,也能方便地看出那些提交屬于同一個特性。

發布分支:

發布分支可能從develop分出,最終必須合并回developmaster。發布分支以release-*的方式命名。

發布分支為新的發部分版本做準備,包括一些小bug修正和發布的元信息(版本號、發布日期等)的添加。這樣develop分支就可以接受針對以后的發布的新特征。

在代碼基本可以發布的時候從develop分支分出發布分支。這是要確保此次發布包括的特性都已經合并到develop分支了。

創建發布分支:

git checkout -b release-1.2 develop
./bump-version.sh 1.2
git commit -a -m "Bumped version number to 1.2"

完成發布分支:

git checkout master
git merge --no-ff release-1.2
git tag -a 1.2

git checkout develop
git merge --no-ff release-1.2

緊急修復分支:

可能從master分出,必須合并回developmaster。分支名以hotfix-*開頭。如果生產系統里面有個緊急bug要馬上修復的話,我們就從master里分出一個緊急修復分支。這樣某人修復緊急bug的同時,團隊其他成員可繼續在develop上開發。修復完bug之后,需要合并回master,同時也需要合并回develop

參考文章 git分支最佳實踐;


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,993評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內容

  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,691評論 9 163
  • 有一個周五的早晨,領導安排去打印一份報告,然后下午的時候快遞出去。接到任務,在正準備去打印的時候,突然想到快遞每天...
    小清讀書閱讀 2,794評論 0 0
  • 俗話說“不言人私,不揭人短”,人活一生,是以尊嚴立于世。“人活一張臉,樹活一張皮”,古人很早就對尊嚴做了很好的形象...
    為世瑞閱讀 227評論 0 0
  • 每次住了幾天的朋友走后我都有一種如釋重負卻又被掏空的失落感。今天也是如此。 昨晚喝分別酒,我有一種見一面少一面的感...
    麥子的麥浪閱讀 261評論 0 0