1. 程式人生 > >最好最易懂的Git教學——分享“好麻煩部落格”Git教學(2)

最好最易懂的Git教學——分享“好麻煩部落格”Git教學(2)

Git branch

branch (分支)應該是 Git 最重要的技能了,在一個多人專案的開發過程中我們有時候要開發新功能,有時候是要修正某個Bug,有時候想要測試某個特異功能能不能 work ,這時候我們通常都會從主 branch 再開出一條新的 branch 來做,這支新開的 branch 會帶著你的主 branch 目前的最新狀態,當你完成你所要開發的新功能/ Bug 修正後確認沒問題就再把它 merge(合併)回主 Branch ,如此便完成了新功能的開發或是 Bug 的修正,因此每個人都可以從主 branch 拉一條新的 branch 來做自己想做的事,再來我們好好了解一下 branch 的使用。

瞭解 branch 最好的方法就是有影象可以看,你可以用任何你已安裝的GUI來檢視,但在你安裝 Git 的時候其實同時也安裝了最基本的 Git GUI 叫做 gitk,你可以使用 gitk --all 這個指令來呼叫他,此時你應該能看到以下的畫面:

gitk

點選左上方區塊的 commit 節點你可以看到當次 commit 的詳細資料,例如作者以及他的更新記錄,但你會發現這時候終端機是無法輸入的,因此請你先關掉 gitk ,改打指令 gitk --all & 來讓 gitk 在背景執行。

git branch 這個指令可以列出所有的 branch 並告訴你目前正在哪個 branch:

$ git br
* master
  develop
  feature/test

上面的訊息告訴我們在這個 Git repository裡有3支 branch ,而你目前正在 master branch 上。假設我們現在要開一支新的 branch 叫做 cat ,使用 git branch 來幫助你開一支新的 branch

$ git branch cat
$ git branch
  cat
* master

上面我們開了一支新的 branch 叫做 cat ,使用 git branch 再檢視一次發現已經多了這支新的 branch了,這時候你去檢視你的 gitk 的影象狀態會發現像下圖一樣,新的 branch cat 與 master 在同一條水平線上,表示目前他們的狀態是一模一樣的。

git branch

你應該也有發現,雖然我們建立了一個 cat 的 branch ,但其實我們所在的 branch 還是在 master branch,因此我們現在還需要切換過去,因此我們使用 git checkout 來切換:

$ git checkout cat
Switched to branch 'cat'

這樣就會從原本的 mater branch 切換到 cat branch 了。

接下來假設我正在 cat 這支 branch 做開發,因此新增一個檔案,加上一些內容,將它 add 到 stage 後再 commit 它。

$ vim lib/cat.rb
$ git status
# On branch cat
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#   lib/cat.rb
nothing added to commit but untracked files present (use "git add" to track)
$ git add lib/cat.rb
$ git commit -m "Add Cat.rb"
[cat ea7d309] Add Cat.rb
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 lib/cat.rb

cat branch

上面的流程你已經很熟悉了,接下來我們再切換到原本的 master branch ,這時候你會發現剛剛在 cat branch 新增的 cat.rb 檔案已經不見了。

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.

master branch

Git 在我們切換 branch 的同時就會很聰明的會把我們的工作目錄更動成那個 branch 該有的狀態,如果你這時候切換到 GUI 去看,你會發現到與剛剛 cat 和 master branch 在同一條水平線上不同,cat branch現在已經比 master branch 再多出了一個 commit 的內容。

gitk

現在我在切換到 cat branch 去增加更多的內容,一樣再將它 add 到 stage 後,再 commit 它。

$ git checkout cat
Switched to branch 'cat'
$ mvim lib/cat.rb
$ git add lib/cat.rb
$ git commit -m "Add initializer"
[cat a3bce42] Add initializer
 1 files changed, 3 insertions(+), 1 deletions(-)

add initializer

切到 GUI 來看的話你會發現現在 cat 這支 branch 比 master branch 要在多上兩個 commit 的內容。

gitk

如果這時候我們在 master 上繼續開發會發生什麼事呢? 我們現在切換到 master branch 並增加一個檔案及內容,照慣例 add 後 commit。

$ git co master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
$ git add spec/animal_spec.rb
$ git commit -m "Another spec"
[master 7d72927] Another spec
 1 files changed, 2 insertions(+), 0 deletions(-)

master another spec

我在 master branch 的 animal_spec.rb 增加了一些內容,把它 commit 之後我們切換到 GUI 來看。

master spec

我們發現現在 master branch 與 cat branch 已經產生分歧了,因為兩支 branch 都有了各自往後開發的 commit ,而且由於 master branch 最後一次的 commit 時間較新因此排列在最前面。

Git rebase 整理現在的 branch

假設我們現在在 cat branch 的開發動作已經完畢,通常我們現在要做的事情會是將 cat branch 合併回 master branch,在開發流程上, master branch 就像是一個主要的 branch ,每個開發人員都是從 master branch checkout 出去一支新的 branch 做開發,在開發完畢後就再將開發完的 branch 合併回 master branch,因此 master branch 都會保有最新的開發好的狀態,一般在 Git 教學中會教你現在使用 git merge 這個指令來將兩個 branch 合併,但這邊我要先教你的是 git rebase 這個指令。

與 git merge 不同的是, git rebase 不單單只是將兩個不同的 branch 合併起來,而是將某一支 branch 基於另一支 branch 的內容合併起來,這是什麼意思? 以我們的例子來說,我們在 cat branch 開發完了以後,這時候我們的 master branch 也有了其他開發者所合併回去的內容,換句話說現在的 master branch 與我們當初 checkout 出去的時候的狀態已經不同了,但我們會希望我們現在這支 cat branch 的內容就像是剛剛從 master branch checkout出來一樣乾淨,也就是說讓 cat branch 中保有 master branch 最新的狀態, git rebase會基於 master branch 目前最後一次的 commit 內容再往後把你在 cat branch 上commit 的內容加上去,我們現在在 cat branch 輸入 git rebase master 來將 cat branch 基於 master branch 做 rebase。

$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Add Cat.rb
Applying: Add initializer

過程中沒有發生衝突,這時候我們到 GUI 看看現在的結果。

git rebase

原先 cat branch 上的兩個 commit (Add Cat.rb 和 Add initializer) 已經合併到 master branch 最新的 commit (Another spec),換句話說目前 cat branch 的內容就像是剛從 master branch 所 checkout 出來然後再加上自己的 commit,因此不同於 git merge 的線圖會把 cat branch 合併到 master branch , 而是把原本的 cat branch 接到 master branch 因此只有一條線,當一個專案有很多的 branch 再做開發的時候會避免很多 branch 的線接來接去難以辨認。

開發過程中,若你在開發的 branch 功能比較多, commit 的量也比較多時,建議使用rebase將你現在的 branch 整理過再合併回主幹,這樣會產生較漂亮的線圖

若你想要看看目前的 branch 與其他 branch 有哪些差異,你可以使用 git diff 的指令去觀察,例如我現在想要看 master 跟 cat 這兩個 branch 的差異,我只要下:

$ git diff cat master
diff --git a/lib/cat.rb b/lib/cat.rb
deleted file mode 100644
index 1227d26..0000000
--- a/lib/cat.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class Cat < Animal
-  def initialize
-    super
-  end
-end

你就可以看到現在的 cat branch 跟 master branch 的差異在哪了。

如果我們開發完畢時,我們會把開發好的東西合併回 master 很自然的我們通常都會使用 git merge 這個指令來合併兩個branch

$ git merge cat
Merge made by recursive.
 lib/cat.rb |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 lib/cat.rb

這時候我們看圖的話會是這樣:

git merge

可以看到我剛剛在 master branch 下了 git merge cat 這個指令來告訴 git 要 merge cat 到現在所在的 branch ,因此在圖上就看到了 cat branch 拉一條線回來合併到了 master 這個 branch 了,解釋這張圖的意思就是, cat branch 從 master branch 的 Another spec 這一次的 commit 分支出來後,自己產生了三次的 commit (Add Cat.rb、Add initializer、Rever “Add initializer”) 然後合併到 master。

Confict: 處理 Git 合併時的衝突:

很常發生的情況是再 merge 或是 rebase 的圖中產生了 convict (衝突),這時候 Git 會停下來請你去處理,例如我們在 cat 和 master 的 branch 都對 lib/cat.rb 這支檔案做編輯,然後我們將他們 merge:

$ git merge cat
Auto-merging lib/cat.rb
CONFLICT (content): Merge conflict in lib/cat.rb
Automatic merge failed; fix conflicts and then commit the result.

你會看到 Git 告訴你在你合併的過程中在 lib/cat.rb 這支檔案發生了衝突,Git 不知道該怎麼處理因此要你去處理它,這時候我們開啟這支檔案會看到這樣的情況:

git confict

<<<<<<<<<< HEAD 到 ========== 的中間區域是目前你所在 branch 的 commit 內容,而從 =========== 到 >>>>>>>>>>> cat 則是你要合併的 cat branch 的內容,你必須做出決定看是要兩個都留下,或是選一個,或是改成你想要的內容,改好後記得要將 Git 自動產生的 <<< 、 =====、 <<< 的內容都刪除,修改完畢後存檔,將剛剛修改過的檔案再使用 git add 加入 stage ,將所有的衝突都修正完畢後就使用 git commit 提交一次 commit,由於這次的 commit 是在處理 merge 時的衝突,因此 Git 很聰明的已經幫我們加上了一些預設的訊息 “Merge branch ‘cat’”, commit 提交後就會看到合併成功的訊息了。

$ git add lib/cat.rb
$ git commit
[master c37c9e3] Merge branch 'cat'

發生 confict 時的處理步驟

  1. 將發生 confict 的檔案開啟,處理內容( 別忘了刪除<<<、===、>>> )。
  2. 使用 git add 將處理好的檔案加入 stage。
  3. 反覆步驟 1~2 直到所有 confict 處理完畢。
  4. git commit 提交合併訊息。
  5. 完成

講到這裡我們再來整理一下工作流程,讓大家再複習一下 git 的使用:

  1. 在專案中會有一條主 branch 是大家將開發好或是修好的東西合併回去的物件,所有要開發的新功能或是修 bug 都是從主 branch 拉出一條新的 branch 去工作。
  2. 當你完成一個階段性的任務時,將你剛剛 所新增的內容使用 git add加入到 stage 的狀態,並且使用 git commit 加上 commit 的訊息來提交一次的 commit。
  3. 反覆動作 2 直到你完成這支 branch 的主要目的(新功能/修 bug ),若這時你離主 branch 已經有一段時間,或是確定主 branch 上已經有新的 commit ,使用 git rebase 將自己的分支整理然後使用 git merge 合併回主 branch,反之則是直接使用 git merge 將自己 branch 的內容合併回去。

Git reset 取消上一次的操作

取消 merge

版本控制最大的好處之一就是讓你永遠可以後悔,因此我們常會希望把已暫存的檔案、已提交的 commit 或是已合併的 branch 取消修改,這時候我們可以使用 git reset 這個指令來幫助我們,像現在我若是想要取消剛剛的 merge 動作,我只要下:

$ git reset --hard ORIG_HEAD
HEAD is now at c126ff9 Config initialze

這時候再回去看圖你會發現已經回到合併前的樣子了:

git reset

取消已暫存的檔案

有時候手殘不小心將還沒修改完的檔案使用 git add 加入了 stage ,這時候可以使用 git reset HEAD <file> 來將這支檔案取消 stage:

git reset

你可以看到我使用 git add 將檔案加入 stage 後,在我的 status 狀態顯示 lib/cat.rb 這支檔案現在已經準備好被 commit ,但這時我使用了 git reset HEAD 將這支檔案取消 stage,再使用 status 檢視時它就變回一支還沒加入 stage 的檔案了。

取消修改過的檔案

連續剛剛的情況,若是我想完全放棄這次修改 (將檔案狀態回復到最新的一次 commit 時的狀態),我可以使用 git checkout -- <file> 來回復這支檔案:

$ git checkout -- lib/cat.rb

取消變更不會有任何訊息,但這時你去看檔案會發現他已經回復成沒修改過時的模樣了。

修改上一次的commit

手誤打太快, commit 訊息打錯時,我們可以使用 git commit --amend 來幫助我們重新修改:

git reset git reset

在上面我想要修改打錯字的 commit 訊息 “Cat initiae”,因此我使用 git commit --amend 來修改成正確的訊息。

強制回復到上一次 commit 的版本

有時候我們想要放棄所有修改回到 commit 時的狀態,這時候我們可以下 git reset --hard HEAD 來回復,HEAD 引數可以加上一些變化,例如 HEAD^ 表示目前版本的上一個版本 HEAD~2 則是再上一個,因此你可以自由的跳回去之前的狀態。

git reset, hard 與 soft 的差異

你可能會在這邊感到疑惑,在使用 git reset 的時候都會看到一個 soft 或是 hard 的引數,這代表什麼樣的意義?基本上在使用 git reset 的時候,都會把目前狀態回復到你想回復的版本,但若是不加引數的情況,會把你做過的修改仍然保留,但是,若是加上 —soft 引數,則會把做過的修改加入 stage ,若是加上 hard 引數的話則是把做過的修改完全刪除,回到那個版本原本的樣子。

相關推薦

最好易懂Git教學——分享麻煩部落Git教學2

Git branch branch (分支)應該是 Git 最重要的技能了,在一個多人專案的開發過程中我們有時候要開發新功能,有時候是要修正某個Bug,有時候想要測試某個特異功能能不能 work ,這時候我們通常都會從主 branch 再開出一條新的 branch 來做

有關IOS開發寫的部落和網站持續更新,含盲點

1. Swift中的trim方法處理字串:http://www.hangge.com/blog/cache/detail_1649.html 2. Swift語言中的@available和#available https://blog.csdn.net/offbye/article/deta

Qt中窗體小化以及視窗大小修改的相關函式使用2

繼續寫的。 在上一篇文章中說過呼叫view的一些show、showNormal、showMaximized等方法來實現視窗正常顯示。 但後來在實現的過程中發現: 視窗的最大化和全屏是一個效果的,這完全不符合自己當初的意願啊! 尤其是在qml中呼叫view的這些show方法

前端進階:一些部落博文分享

前言 之前在讀書會聽到的,人與人思考同一問題時,心理表徵是不同的。在技術圈,各路大神大牛雲集。向他們看齊,學習他們發現問題、分析問題以及解決問題的方式,能讓我們更好地看到差距,提升自我。 開始 我不盲目追隨誰,只是取人所長,提升自我。以下是一些我自己在平時擴充套件學習中,發現的較好的部落

Android AIDL簡單易懂的使用與解析2

在上篇文章 Android AIDL最簡單易懂的使用與解析(1)中,我們學會了如何編寫一個簡單的 AIDL 來進行跨程序通訊,本著知其然更要知其所以然的道理,在這一篇中我們就來具體看看 AIDL幫我們生成了一套基於 Binder 的怎樣的介面吧~ 我們先來看看testAID

深入理解Java中的回撥機制通俗易懂的回撥機制的部落

1. 什麼是回撥? 在我看來,回撥其實是一個相當具有迷惑性的名字,因為它很容易讓人糾結於回撥這個詞語本身的含義,從而忽略了回撥這種機制的本質。要理解Java中的回撥概念,最好的方式不是通過例項,而是從回撥概念的起源說起。   最開始接觸回撥時在C語言中函式指

分享之測試WebService小工具 STORM

pen 方法 gles edit 編輯框 mage utl 工具 按鈕 http://www.cnblogs.com/yhuang/archive/2012/04/04/share_storm.html 最近的項目中,一直要使用到WebService,為了測試自己編寫的We

NOIP2016提高組初賽2四、讀程序寫結果3、求長回文子序列

所有 並且 names mes font esp mic abcd 大小 #include <iostream> using namespace std; int lps(string seq, int i, int j) { int len1, len2;

全面超大規模數據集下載鏈接匯總

科學 acc -a 規模 elf nsf sogo ins 名單 大數據 大數據 1. https://delicious.com/pskomoroch/dataset 2.http://stackoverflow.com/questions/10843892/dow

【微軟大法】VS Tools for AI全攻略2

port shell orf 方式 virt cnblogs 我們 玩耍 虛擬 接著上文,我們來討論如何使用Azure資源來訓練我們的tensorflow項目。Azure雲我個人用得很多,主要是因為微軟爸爸批了150刀每月的額度,我可以愉快地玩耍。 那麽針對Azure,有成

git2======== 連接倉庫後提交報錯

war fatal ref details repo caused date 目錄 rst 在共享完成密鑰後出現如下情況 [root@python3_ansible python]# git push -u origin master Username for ‘htt

git2======== 報錯處理

ota auto ack tps eat fat got fail github 在共享完成密鑰後出現如下情況 [root@python3_ansible python]# git push -u origin master Username for ‘https://

基於qml創建簡單的圖像處理程序2-使用c++&qml進行圖像處理

.cn turn isnull 按鈕 編寫 可能 finish height 通過 《基於qml創建最簡單的圖像處理程序》系列課程及配套代碼基於qml創建最簡單的圖像處理程序(1)-基於qml創建界面http://www.cnblogs.com/jsxyhelu/p/83

痞子衡嵌入式:極精簡的Git命令教程2- 連接(remote/clone)

我們 pair ssh key 技術 彈出 change 能夠 sha2 permanent   今天是Git系列課程第二課,上一課我們已經學會在本地創建一個空repo,痞子衡今天要講的是如何將本地倉庫與遠程建立聯系。 1.將本地倉庫掛上遠程git remote   本地

git命令行2

git 命令行一、父提交的表示方法 1.HEAD引用 在.git/HEAD目錄下存在一個HEAD文件,其記錄著當前工作區對應的SHA1。如果當前工作區從某個分支檢出(checkout),那麽這個HEAD文件中的引用最終執行分支對應的SHA1,如果處於分離頭狀態(不對應分支,從某個commit檢查),那麽這個H

長上升子序列O(nlogn) 要強的T^T2358

中間 數學 個數 img NPU 序列 ger main col 題目來源:http://120.78.128.11/Problem.jsp?pid=2358 要強的T^T TimeLimit:1000MS MemoryLimit:65536K 64-bit in

算法數據結構面試分享數組排序問題2 - 計數排序

排序 計數 算法 數據結構 數組排序問題(2) 昨天我們留了一道題目“給你一個整型數組,裏面出現的數在[0-100] 之間,能用最優化的方法幫我排序嗎”。 1. 確保我們理解了問題,並且嘗試一個例子,確認理解無誤. 這是一道排序算法題,我們學過很多排序的算法。不一樣的是,它給定一個額外的條件,

【強烈推薦】科註學習班——自了法師分享:珍惜暇滿人身寶

針對 得來 pro 後來 全國 有一點 HR ner 想去 凈土宗專修平臺 2016-03-11 新佛友請點擊圖片上方【凈土宗專修平臺】輕松關註。回復【阿彌陀佛】既有大量珍貴資源(在百度網盤裏)與您分享! 摘自《科註學習班第206集》 2016/3/2

Gitgit-checkout的用法總結2

參考 正文 nsa dex block -o onf script 還需要 原帖收藏於IT老兵驛站,傳遞一個IT老兵在雕零前的光和氧。 前言 結合前一篇文章,再認真總結一下git-checkout的用法,因為可能一次總結到不了位,那麽就不怕啰嗦,不怕重復,多總結幾次,這樣可

網工實用常用的網絡命令之一——Ping 命令詳解

關閉 連通 自己 命令詳解 機房 幫助 辦公室 技術分享 詳解 Ping是Windows、Unix和Linux系統下的一個命令。ping也屬於一個通信協議,是TCP/IP協議的一部分。利用“ping”命令可以檢查網絡是否連通,可以很好地幫助我們分析和判定網絡故障。 網工最實