Git初級操作指南

Git初級操作指南

前言: “ git的使用是每個軟件開發人員必備的技能,但很多git的初學者,都只是知道常用的一些命令寫法,卻不知道命令真正對應的作用是什麼。網絡上大部分git操作教程文章,都是直接羅列了一些常用命令,命令後面註釋作用的描述。初學者看過文章之後,可能還是無法舉一反三,碰到其他場景,仍然需要再去搜索應該使用什麼命令操作。”

本文通過介紹git管理的目錄結構,將git常用操作命令基於git結構通過圖形的方式展現,讓初學者對git操作對應的作用流向印象深刻,從而達到對於更加複雜的應用場景也能思路清晰。

目錄


Git操作一般流程

初始化一個倉庫

## 新建一個目錄作爲工作目錄
$ mkdir git_test   
$ cd git_test
## 在本地初始化git倉庫
$ git init

獲取遠程倉庫

## 把遠程倉庫clone下來
$ git clone git@github.com:xx/xxx.git
## 默認遠程倉庫名爲origin
## 也可以添加遠程倉庫爲origin
$ git remote add origin git@github.com:xx/xxx.git
## 合併遠程倉庫代碼到本地
$ git pull origin master

提交代碼

## 添加所有修改
$ git add .
## 提交修改
$ git commit -m "add some files"
## 推送到遠程倉庫
$ git push

在非常常規的單人開發情況下,或許知道以上命令已經夠用了。但一般項目都是團隊協作,而且可能有多個分支版本,碰到稍微複雜的場景,僅僅記住這些命令就顯得不夠了。
清楚地知道每個git操作對應的流程和作用才能應對更多的情況。首先,得要了解一下git的目錄結構。

Git目錄結構

在Git中,我們將需要進行版本控制的文件目錄叫做一個倉庫(repository),這個目錄裏面的所有文件都通過Git來實現版本管理,Git能跟蹤並記錄在該目錄中發生的所有更新。

git管理的目錄結構如下圖所示:
git倉庫結構
根據上圖,給出每個部分的簡要說明:

  • Directory:使用Git管理的一個目錄,包含我們的工作空間和Git的管理空間。
  • WorkSpace:需要通過Git進行版本控制的目錄和文件 (也就是我們的項目代碼),這些目錄和文件組成了工作空間,除了.git之外的都屬於工作區。
  • .git:存放Git管理信息的目錄,初始化倉庫的時候自動創建。
  • Index/Stage:暫存區,在提交進本地倉庫之前,我們可以把所有的更新以內容快照的形式放在暫存區。
  • Local Repo:本地倉庫,一個存放在本地的版本庫;指針HEAD會指向當前的開發分支(branch)。
  • Stash:是一個工作狀態保存棧,用於保存/恢復WorkSpace中的臨時狀態。

git命令基本就是圍繞這些部分在進行操作,接下來對應着結構看看操作的流程走向。

git操作的流程

git提交流程

git倉庫結構
如上圖,對應之前提到的git提交代碼的操作命令:

$ git add .
$ git commit -m "add some files"
$ git push

首先,add命令將工作區(即本地項目代碼)的所有修改文件添加到暫存區;然後commit將暫存區內容提交到本地倉庫,並添加提交記錄message;最後push將本地倉庫推送到遠程服務器倉庫。

git拉取流程

git倉庫結構
如上圖,對應的git拉取遠程倉庫代碼的操作命令:

$ git remote add origin git@github.com:xx/xxx.git
$ git pull origin master

# git pull操作等於fetch + merge
$ git fetch origin master
$ git merge origin/master

pull操作從遠程倉庫拉取代碼併合併到本地工作區,等同於先執行fetch操作再執行merge操作。fetch操作從遠程獲取最新版本到本地,不會自動合併;merge操作合併對應分支代碼到工作區。

注:注意git push和git pull的默認操作,即未指定upstream遠程主機名和分支名的情況下,git push會根據git config中的push.default屬性進行操作;git pull會自動在本地分支和遠程分支之間建立追蹤關係(tracking)。本文不展開介紹。

git撤銷流程

這裏寫圖片描述

如上圖,對應的git撤銷操作命令:

$ git reset HEAD^
$ git reset --soft HEAD^
$ git reset --hard HEAD^

reset 默認的參數爲mixed,git reset 操作會將添加到暫存區的更新撤回工作區;

git reset –soft HEAD^ 參數爲soft,軟回退,即將本地倉庫的提交回退一個版本至暫存區,且將HEAD指針重置到上一版本,即將HEAD指針前移一個commit對象 (注:HEAD爲指向當前分支的指針,HEAD^爲語法糖一個^表示往上一個版本,可以多個,也可以用 HEAD~n );

​git reset –hard HEAD^ 硬回退,直接將工作區代碼回退至上一版本,且將HEAD指針前移一個commit對象。

git查看操作

git也可以使用命令的形式查看git操作後的對應狀態和歷史記錄。
git status 命令用於顯示工作目錄和暫存區的狀態。使用此命令能看到那些修改被暫存, 哪些沒有, 哪些文件沒有被git 跟蹤(tracked)。

$ git status
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#  (use "git reset HEAD <file>..." to unstage)
#
#       modified:   xx/xxx
#
# Changes not staged for commit:
#  (use "git add/rm <file>..." to update what will be committed)
#  (use "git checkout -- <file>..." to discard changes in working directory)
#
#        modified:   yy/yyy  
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#   

其中,git status輸出的內容分爲3個分類/組:

  • Changes to be committed : 已經在暫存區, 等待提交commit的更新
  • Changes not staged for commit : 工作區有修改, 但是沒有被添加到暫存區的更新
  • Untracked files : 沒有跟蹤(tracked)過的文件, 即從沒有add過的文件

git status不顯示已經commit的信息,看項目歷史的提交信息要使用 git log


git log 命令用於顯示提交日誌信息。

 $ git log
commit e745820e4ac11053dedaa2a440ce1b5fbe4de2e3
Author: xiaojun <xiaojun@stargraph.cn>
Date:   Sat Apr 21 18:49:42 2018 +0800

    feat(xx):xx

commit e5ffc53a4ef483dcc72fc5fbe565373dd03f79e6
Author: xiaojun <xiaojun@stargraph.cn>
Date:   Thu Apr 19 22:09:37 2018 +0800

    feat(xxx): xxx

默認不用任何參數的話,git log 會按提交時間列出所有的更新,最近的更新排在最上面。每次更新都有一個 commit ID、作者的名字和電子郵件地址、提交時間,最後縮進一個段落顯示提交的message。
git log 有許多選項參數可以設置顯示的格式和內容,這裏不展開介紹。

git show 命令可查看某一次提交詳細信息。 git show命令採用SHA-1 commit ID作爲參數。

git show
commit e745820e4ac11053dedaa2a440ce1b5fbe4de2e3
Author: xiaojun <[email protected]>
Date:   Sat Apr 21 18:49:42 2018 +0800

    feat(message):xxxx

diff --git a/src/xx
new file mode 100644
index 0000000..5eda378
--- /dev/null
+++ b/xx
@@ -0,0 +1,67 @@
+ //新增代碼
+  xxxxx
+  xxx       
 ...

若不指定參數,則展示最近一次提交的詳情信息,diff後爲更新的文件名,—後爲對應文件刪除的內容,+++後爲添加的內容。

git diff 命令用於顯示文件之間的差異。

不加參數,默認情況下用於顯示工作區中當前文件和暫存區快照之間的差異,也就是工作區修改之後還沒有暫存起來的變化內容。
也可以使用 git diff 比較兩次提交之間的差異,git diff 比較在兩個分支之間的差異等等。

$ git diff
diff --git xx.js
index d9f99f6..0db60fb 100644
--- a/xxx
+++ b/xxx
@@ -6,7 +6,7 @@ 
- xxx
+ yyy

瞭解了以上git操作,還不足以應對大部分應用情況,因爲git管理往往還需要多分支管理,下面再介紹git分支的操作。

git分支管理

在進行提交操作時,Git 會保存一個提交對象(commit object)。該提交對象會包含一個指向暫存區內容快照的指針,不僅如此該對象還會包含作者信息、提交message和指向它父對象的指針,而父對象即上一次提交產生的提交對象。這樣當前分支保存的記錄就像一條鏈表一樣鏈接起來。Git 中的分支,其實本質上僅僅是個指向 commit 對象的可變指針。
這裏寫圖片描述

如上圖所示,每一個字母表示一個提交對象,每個對象有指針指向其父對象;HEAD指針指向當前分支的最新版本。

新建分支、切換分支

# 新建develop分支
$ git branch develop
# 切換到develop分支
$ git checkout develop
# 新建並切換到新建的develop分支,等同於以上兩步
$ git checkout -b develop

這裏寫圖片描述

如上圖,新建的分支基於當前master分支的記錄複製了另一條鏈;而切換到develop分支之後,HEAD指針則指向develop分支的最新版本。

合併分支

這裏寫圖片描述

如上圖所示,若開發人員在切換不同的分支後都有繼續不同的開發,提交了不同的記錄,此時不同的分支鏈就會出現分叉。這種情況非常常見,本地倉庫分支可能有多個不同版本,遠程倉庫分支也會被其他開發人員更新提交記錄,所以合併分支讓分叉重新還原成一條鏈,整合版本以便後續開發很重要。
假設上圖的情況是,develop分支爲某個迭代的開發版本,master分支爲正式穩定版本,兩個分支上同時都有開發人員做了更新提交,此時需要合併develop分支到master分支整合成正式版本。此時使用merge命令:

# 切換到master分支
$ git checkout master
Switched to branch 'master'
# 合併develop分支到master
$ git merge develop

這裏寫圖片描述

如圖所示,合併操作在將合併結果生成一個新的快照並自動創建了一個新的提交,這個合併提交不只一個父提交對象。
而,合併分支的時候有可能不那麼順利,如果兩個分支的分叉上的更新同時修改了同一文件的同一部分,git合併時則會產生衝突,並不能自動創建一個新的合併提交,此時需要手動解決衝突:

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

Git 會在有衝突的文件中加入標準的衝突解決標記,出現衝突的文件會包含一些特殊區段:

<<<<<<< HEAD:index.html
<div>xxx</div>
=======
<div>
yyy
</div>
>>>>>>> develop:index.html

HEAD 所指向的版本(master分支)代碼爲 ======= 的上半部分,而 develop 分支在 ======= 的下半部分。解決衝突後,add、commit提交新的記錄即可完成合並。


另外再介紹合併代碼的兩種不同的操作rebase和cherry-pick。
rebase一般用於簡化歷史提交記錄,將提交鏈合併爲一條。
這裏寫圖片描述

$ git checkout develop
$ git rebase master

rebase master分支到develop, devleop分支的提交將會取消掉,創建新的提交接在master分支鏈後面。如圖所示,歷史記錄成一條線,相當整潔。


cherry-pick 相當於更加細粒度的合併操作。git cherry-pick可以選擇某一個分支中的一個或幾個commit(s)來進行操作。例如,假設我們有個穩定版本的分支master,另外還有個開發版本的分支develop,我們不能直接把兩個分支合併,這樣會導致穩定版本混亂,但是又想增加develop中的一個功能到master中,這裏就可以使用cherry-pick了。

$ git checkout master
$ git cherry-pick 38361a68

# 38361a68 爲develop分支下對應想添加功能的commit ID
$ git checkout develop
$ git log
commit 38361a68138140827b31b72f8bbfd88b3705d77a
Author: xiaojun <xiaojun@stargraph.cn>
Date:   Sat Apr 21 18:49:42 2018 +0800

      feat(xx):新增功能xx

當執行完 cherry-pick 以後,將會自動在master生成一個新的提交,只更新對應commit的內容;這個新的提交的哈希值和develop中原來的不同,但message一樣。


總結:本文希望通過將git操作的流程基於git目錄結構圖形化,讓初學者可以更清晰地瞭解git命令的作用,能夠更加自如地應對其他複雜的應用場景。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章