1. 程式人生 > >細說GIT分布式版本控制器

細說GIT分布式版本控制器

set 指定 提前 隨著 過去 內容 軟件開發 分布式 commit

一.Git介紹

Git是目前世界上最先進的分布式版本控制器。Svn CVS

版本控制器:就是用來追溯自己書寫的代碼的記錄信息。好處:可以非常方便的記錄何時何地何人操作了哪些代碼。

什麽是分布式版本控制器?

集中式:對於集中式的版本控制器,需要搭建一個中央服務器,然後在這個中央服務器裏面作為代碼的倉庫。

分布式:就是每個用戶的電腦都是一個獨立的倉庫,可以記錄代碼的變化,即使不聯網,完全也可以自己獨立開發。

二.Git安裝

https://git-for-windows.github.io/

安裝完後還需要最後一步設置,在命令行輸入:告訴你是誰

$ git config --global user.name

"Your Name"

$ git config --global user.email "[email protected]"

三.Git操作

1.創建倉庫

1).創建倉庫目錄

技術分享

2).通過git init命令把這個目錄變成Git可以管理的倉庫

技術分享

註意:Git倉庫創建好後,會在該文件存在一個.git的目錄,這個目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裏面的文件,不然改亂了,就把Git倉庫給破壞了。

註意:如果你沒有看到.git目錄,那是因為這個目錄默認是隱藏的,用ls -ah命令就可以看見。

小結:git init 初始化倉庫

2.添加文件到版本庫

把文件添加到版本分兩步,首先將文件添加到暫存區,然後再提交到版本庫

1).創建文件並把文件添加到暫存區(git add

技術分享

git add . 表示將當前目錄下的所有文件都添加到暫存區

2).將文件從暫存區提交到版本庫

技術分享

-m 表示本次提交的描述

小結:

git add xxx 添加單個文件到暫存區

git add . 將當前文件夾下的所有文件都添加到暫存區

git commit -m ‘xxx’ 將文件提交到版本庫 -m 表示描述

3.修改文件查看狀態與不同

此時我們將文件內容修改

技術分享

1).查看狀態

技術分享

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

2).查看此次修改的文件與之前的不同

技術分享

git diff顧名思義就是查看difference,可以從上面的命令輸出看到,我們添加了一行hello單詞

知道了對readme.txt作了什麽修改後,再把它提交到倉庫就放心多了,提前命令與之前相同。

技術分享

小結:

git status 查看倉庫狀態

git diff 查看修改後文件與之前的不同。

4.版本回退

如果此時我們因為某種原因想回退到之前的某個版本該怎麽辦?

1).首先通過git log 查看之前的提交日誌

技術分享

如果嫌這樣看著太亂的話可以試試加上—pretty=oneline參數

技術分享

其中85d58ac82a21e8c587da900edff9a21566b1d708和78c5b099e84439c9b640a5028ee1fcb224432576 代表的是commit id(版本號),

它是通過SHA1計算出來的一個非常大的數字,用十六進制表示,而且你的commit id 和我的肯定不一樣,實際以你自己的為準。

2).回退到之前某個版本

知道了之前的提交日誌那如何回退到之前的版本呢?

首先,Git必須知道當前版本是哪個版本,在Git中,用HEAD表示當前版本,也就是最新的提交85d58ac82a21e8c587da900edff9a21566b1d708(註意我的提交ID和你的肯定不一樣),上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^比較容易數不過來,所以寫成HEAD~100。

我們現在回退到上一版本使用命令:git reset –hard HEAD^

查看此時的文件:cat readme.txt

通過查看文件發現確實是回到了上一個版本,那麽我們再通過git log查看此時版本庫的狀態。

最新的“修改readme.txt文件”這個版本已經不見了,就相當於我們坐了時光機一樣,穿越到了之前的版本,

3).回退到未來某個版本

現在肯定又有人想我穿越到了過去,那我再怎麽穿越回來呢?

在Git中,總是有後悔藥可以吃的。當你用$ git reset --hard HEAD^回退到”添加readme.txt文件”版本時,再想恢復到”修改readme.txt文件”,就必須找到”修改readme.txt文件”的commit id。Git提供了一個命令git reflog用來記錄你的每一次命令:

然後通過git reset –hard 85d58ac回退到”修改readme.txt文件”版本。

我們再通過查看文件內容,和歷史提交記錄發現又回到了”修改readme.txt文件”的版本

小結:

git log 查看提交歷史記錄,以便確認回退到歷史哪個版本。

git reflog 查看命令歷史,以便確定要回到未來哪個版本

git reset –hard commit_id 版本之間的穿梭回退

5.工作區與暫存區

1).工作區:

就是你在電腦裏能看到的目錄,比如我的learngit文件夾就是一個工作區:

2).暫存區:

是邏輯上的一個概念,是看不到的。

3).版本庫:

工作區有一個隱藏目錄.git,這個不算工作區,而是Git的版本庫。

Git的版本庫裏存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區,還有Git為我們自動創建的第一個分支master,以及指向master的一個指針叫HEAD

分支和HEAD的概念我們以後再講。

前面講了我們把文件往Git版本庫裏添加的時候,是分兩步執行的:

第一步是用git add把文件添加進去,實際上就是把文件修改添加到暫存區;

第二步是用git commit提交更改,實際上就是把暫存區的所有內容提交到當前分支。

因為我們創建Git版本庫時,Git自動為我們創建了唯一一個master分支,所以,現在,git commit就是往master分支上提交更改。

你可以簡單理解為,需要提交的文件修改通通放到暫存區,然後,一次性提交暫存區的所有修改。

俗話說,實踐出真知。現在,我們再練習一遍,先對readme.txt做個修改,比如加上一行內容:

然後,在工作區新增一個LICENSE文本文件(內容隨便寫)。

先用git status查看一下狀態:

Git非常清楚地告訴我們,readme.txt被修改了,而LICENSE還從來沒有被添加過,所以它的狀態是Untracked

現在,使用兩次命令git add,把readme.txtLICENSE都添加後,用git status再查看一下:

現在,暫存區的狀態就變成這樣了:

所以,git add命令實際上就是把要提交的所有修改放到暫存區(Stage),然後,執行git commit就可以一次性把暫存區的所有修改提交到分支。

一旦提交後,如果你又沒有對工作區做任何修改,那麽工作區就是“幹凈”的:

現在版本庫變成了這樣,暫存區就沒有任何內容了:

小結:

工作區是指我們本地能夠目錄,暫存區是邏輯上的定義,我們想提交某個文件時,需要將工作區的文件放入到暫存區(git add),然後再提交。

6.管理修改

場景:比如說你修改readme.txt文件,並且git add 了,隨後你又修改了readme.txt文件,但是此時你沒有git add,直接git commit的了,這種情況下,你的第二次修改將不會被提交。

原因是你第二次修改沒有放入暫存區,而git commit 是將暫存區的內容提交到版本庫的。

下面實際操作一下:

1)第一次修改readme.txt文件:添加一行first update

2)git add 此次的修改

3)第二次修改readme.txt文件,添加一行second update

4)直接git commit 提交

發現第二次的修改沒有被提交。驗證了上面的結論,只有在暫存區的數據才能被提交。所以要想被提交必須先將文件放入到暫存區,然後再提交

我們在修改了某些文件時,也可以直接使用git commit -a -m ‘xxxx’ 提交。-a就相當於git add .操作,將當前目錄下所有修改了的文件放入暫存區。

小結:

在暫存區的數據才能被提交到版本庫。

修改了某些文件時,也可以直接使用git commit -a -m ‘xxxx’ 提交

7.撤銷修改

場景1:修改了工作區的某個文件內容如何丟棄修改?

場景2:不但修改了工作區的某個文件內容,而且還添加到了暫存區,如何丟棄修改?

場景3:不但添加到了暫存區而且還提交到了版本庫,如何丟棄修改?

場景1:修改了工作區的某個文件內容如何丟棄修改?

1.修改readme.txt文件 添加一行working undo

2.git status 查看狀態

你可以發現git會提示你,git checkout – file 可以丟棄工作區的修改

3.git checkout – file 丟棄修改

場景2:不但修改了工作區的某個文件內容,而且還添加到了暫存區,如何丟棄修改?

1.修改readme.txt文件 添加一行stage undo

2.git status查看狀態

Git同樣告訴我們,用命令git reset HEAD file可以把暫存區的修改撤銷掉(unstage),重新放回工作區.

3.git reset HEAD file 撤銷暫存區的修改,重放回工作區。

此時修改的文件已經被放回到工作區。

4.從工作區中撤銷本次修改

此時修改內容已被丟棄。

場景3:不但添加到了暫存區而且還提交到了版本庫,如何丟棄修改?

這種情況就需要參考版本回退這一節了,回退到上一個版本

  1. 修改readme.txt文件,添加一行repository undo

  1. 提交到版本庫

  1. 回退到上一個版本

小結:

對於只在工作區修改了文件內容,撤銷此次修改使用 git checkout – file撤銷

對於提交到了暫存區的文件內容修改,撤銷此次修改需要分兩步,第一步:git reset HEAD file 重放回工作區,第二步:git checkout – file 從工作區中撤銷。

對於已經提交到版本庫的文件內容修改,撤銷需要回退到上一個版本,使用git reset –hard commit_id.

8.刪除文件

如何將已經提交到版本庫的文件刪除?

  1. 添加文件到版本庫

  1. 從版本庫中刪除

小結:

將文件從版本庫刪除也是分為兩步:

第一步:git rm file 從版本庫刪除

第二步:git commit -m ‘xxx’ 提交本次的操作

四.遠程倉庫

1.添加遠程倉庫

以Github為例

1).在github上創建倉庫

創建完成之後

倉庫創建完成之後,github會提示我們從這個倉庫裏克隆出新的倉庫,或者創建新的倉庫與之個管理,或者推送已存在的倉庫與之關聯。

2).把本地的倉庫與github倉庫關聯。

origin 是遠程庫的名字,github的默認叫法

3).把本地倉庫的內容推送到github倉庫

-u 的意思是如果當前分支與多個主機存在追蹤關系,則可以使用-u選項指定一個默認主機,這樣後面就可以不加任何參數使用Git push

推送完成後,github上就有了你提交的內容

從現在起,只要本地作了提交,就可以通過命令:

git push origin master

把本地master分支的最新修改推送至github上。

小結:

git remote add origin xxx關聯一個遠程庫

git push -u origin master 第一次將master分支的所有內容推送到遠程庫

git push origin master 上面命令第一次推送之後,以後的每次本地提交,使用不帶-u 參數的即可。

2克隆遠程倉庫

上面講了如何將本地倉庫與遠程倉庫關聯,還有一種情況就是將遠程倉庫克隆到本地

此時我將倉庫克隆到了E盤

這樣你的E盤就會出現你克隆的那個倉庫。

小結:

要克隆一個倉庫,首先你必須要知道倉庫的地址,然後使用git clone命令克隆

五.分支管理

分支:是指在開發主線上又開辟了一條線,這樣能在不影響主線的同時繼續工作

1. 創建與合並分支

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

一開始的時候,master分支是一條線,Git用master指向最新的提交,再用HEAD指向master,就能確定當前分支,以及當前分支的提交點:

每次提交,master分支都會向前移動一步,這樣,隨著你不斷提交,master分支的線也越來越長:

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

你看,Git創建一個分支很快,因為除了增加一個dev指針,改改HEAD的指向,工作區的文件都沒有任何變化!

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

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

所以Git合並分支也很快!就改改指針,工作區內容也不變!

合並完分支後,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉後,我們就剩下了一條master分支:

實戰:

1).創建並切換分支

git checkout命令加上-b參數表示創建並切換,相當於以下兩條命令:

git branch dev

git checkout dev

2).查看當前分支

git branch命令會列出所有分支,當前分支前面會標一個*號。

3).修改文件內容提交

4).切換回主分支

切換回master分支後,再查看一個readme.txt文件,剛才添加的內容不見了!因為那個提交是在dev分支上,而master分支此刻的提交點並沒有變:

5).將dev分支合並到master分支

git merge命令用於合並指定分支到當前分支。合並後,再查看readme.txt的內容,就可以看到,和dev分支的最新提交是完全一樣的。

註意到上面的Fast-forward信息,Git告訴我們,這次合並是“快進模式”,也就是直接把master指向dev的當前提交,所以合並速度非常快。

當然,也不是每次合並都能Fast-forward,我們後面會講其他方式的合並。

合並完成後,就可以放心地刪除dev分支了:

6).刪除dev分支

刪除後,再看branch,就只剩下master分支了。

小結:

查看分支:git branch

創建分支:git branch <name>

切換分支:git checkout <name>

創建+切換分支:git checkout -b <name>

合並某分支到當前分支:git merge <name>

刪除分支:git branch -d <name>

2. 解決沖突

場景:你新建並切換到了分支feature1,然後修改了readme.txt文件並提交。隨後你又切換到了master分支,同樣修改了readme.txt文件並提交

這時如果你要合並feature1分支時,即會產生沖突。

模擬並解決:

1).創建並切換分支feature1,修改readme.txt文件,最後提交

2).切換到主分支,修改readme.txt文件,並提交

現在,master分支和feature1分支各自都分別有新的提交,變成了這樣:

3).合並分支

這是git告訴我們 readme.txt文件產生沖突,必須手動解決沖突後再提交

git status 也告訴我們沖突的文件。

4).查看沖突文件

Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,我們修改如下後保存

5).修改文件,手動解決沖突

6).查看分支合並情況

7).刪除分支

擴展:

git merge xxx 默認是使用fast-forward,fast-forward方式就是當條件允許的時候,git直接把HEAD指針指向合並分支的頭,完成合並。屬於“快進方式”,不過這種情況如果刪除分支,則會丟失分支信息。因為在這個過程中沒有創建commit。

git merge --no-ff xxx 其中—no-ff指的是強行關閉fast-forward方式,使得合並分支後能夠保留分支的commit的歷史記錄。

小結:

當Git無法自動合並分支時,就必須首先解決沖突。解決沖突後,再提交,合並完成。

用git log --graph命令可以看到分支合並圖。

3. Bug分支

bug在軟件開發中就像家常便飯一樣,有了bug就需要修復,而git又特別提倡使用分支,所以每個bug都可以通過創建一個臨時分支來修復,修復後,合並分支,然後再刪除臨時分支。

場景:當你接到線上環境代號為007的bug時,很自然的會去創建一個bug分支,分支名為bug007,但是,此時你正在dev分支上進行工作還沒有提交,並不是你不想提交,而是你的工作還沒完成還沒法提交,但是現在這個bug又非常緊急,要求你盡快解決,這時我們該怎麽辦?

模擬並解決:

1).創建bug007分支

2).模擬在dev上正在工作還沒有提交

3).git提供了一個stash功能,可以把當前工作現場“儲藏”起來,等以後恢復現場後繼續工作

使用git stash將當前dev正在開發的工作儲藏起來

再通過git status查看發現工作區現在是幹凈的了。

此時我們就可以切換到bug分支進行bug修復

4).切換到bug007分支修復bug

此時bug已經修改,那麽我們就可以很放心的合並到主分支並將bug007分支刪掉。

因為bug007是在主分支上建立的,所以此時需要切換到主分支上刪除

5).合並並刪除bug007分支

6).之前為了修改bug,我們將dev的內容儲藏起來了,那麽現在我們怎麽恢復呢?

首先通過git stash list 查看

我們發現之前的工作現場還在。

那我們可以通過git stash pop來恢復現場

7).恢復工作現場

再git stash list 發現已經沒有內容了。

小結:

修復bug時,我們會通過創建新的bug分支進行修復,然後合並,最後刪除;

當手頭工作沒有完成時,先把工作現場git stash一下,然後去修復bug,修復後,再git stash pop,回到工作現場。

4.Feature分支

軟件開發中,總有無窮無盡的新的功能要不斷添加進來。

添加一個新功能時,你肯定不希望因為一些實驗性質的代碼,把主分支搞亂了,所以,每添加一個新功能,最好新建一個feature分支,在上面開發,完成後,合並,最後,刪除該feature分支。

現在你收到了一個新需求,要求你完成一個書籍管理的功能,

於是準備開發創建feature分支

半天後你開發完畢:

切換回dev分支準備合並

如果一切順利的話,合並刪除分支。

但是就在這時,接到上級命令說這個功能必須取消。

於是我們使用git branch -d 命令刪除這個feature分支

這時git會提示我們,feature_book沒有被合並,如果真的要強行刪除使用git branck -D 命令來刪除

刪除成功

小結:

開發一個新feature,最好新建一個分支;

如果要丟棄一個沒有被合並過的分支,可以通過git branch -D <name>強行刪除。

細說GIT分布式版本控制器