版本樹 / graph / network
- 乾淨簡潔清晰
- 提交資訊明確
- 易維護易讀
舉個反例:
舉個正例:
Git 檔案狀態
通過 git status
檢視
- untracked 新檔案未加入版本管理
- unmodify
- modified
- staged 用 git add 暫存
git diff --staged
或 git diff --cached
可檢視已暫存檔案和上次提交的區別
分支和 tag
合理使用分支,分支的好處:
- 同時開發不同功能不衝突,可獨立測試
- 可集中解決衝突
- 區分功能或未來某一版本
tag 的作用是對某個提交點打上標籤,釋出版本後打 tag,便於以後回滾特定版本,而不需要 revert。
tag 是對某一版本的記錄。
開發新功能步驟
- 從開發分支拉一個功能分支
- 功能分支開發和測試
- 功能分支 rebase 開發分支(為什麼)
- 功能分支合併到開發分支
注意:
- 一次提交做一件事,寫清楚 comment
- 每次 pull 遠端分支時使用
git pull --rebase
- 分支從哪拉出來,最後合到哪回去
- 合併之前先 rebase
fix bug 步驟
測試線bug的修復
和開發步驟類似
線上bug的修復
- 從master拉一個fix分支(為什麼是master)
- 測試完後 rebase master
- 合併回master
Git 使用技巧
rebase 和 merge
git rebase
一般解釋為變基
,也有解釋為衍合
。
git merge
和 git rebase
都可以整合兩個分支的內容,最終結果沒有任何區別,但是變基使得提交歷史更加整潔。
例如現在 dev 提交了一次,master 在此之後也提交了一次,兩個分支的狀態如下:
git merge
的結果:
git rebase
的結果:
提交點順序
git merge
後,提交點的順序都和提交的時間順序相同,即 master 的提交在 dev 之後。git rebase
後,順序變成被rebase
的分支(master)所有提交都在前面,進行rebase
的分支(dev)提交都在被rebase
的分支之後,在同一分支上的提交點仍按時間順序排列。
分支變化
- dev 在 rebase master 後,由原來的兩個分岔的分支,變成重疊的分支,看起來 dev 是從最新的 master 上拉出的分支。
什麼時候使用 rebase / merge
假設場景:從 dev 拉出分支 feature-a。那麼當 dev 要合併 feature-a 的內容時,使用 git merge feature-a
;反過來當 feature-a 要更新 dev 的內容時,使用 git rebase dev
。
使用時主要看兩個分支的"主副"關係。
注意
一般來說,rebase
後的 dev 和遠端的origin/dev
會發生分離,在命令列介面中會提示:
Your branch and 'origin/dev' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
複製程式碼
這時需要用git push -f
強制推送,覆蓋遠端分支。若使用了提示中的git pull
,結果會變成合並,併產生一個合併提交點。
慎用git push -f
!
————————————————————
git merge --no-ff
--no-ff
是不快速合併的意思
與 git merge 的區別
git merge
的結果:
被merge的分支和當前分支在圖形上併為一條線,被merge的提交點逐一合併到當前分支。
git merge --no-ff
的結果:
被merge的分支和當前分支不在一條線上,被merge的提交點還在原來的分支上,同時在當前分支上產生一個新的提交點。
————————————————————
git rebase -i 操作
用於整理提交和提交資訊,貌似不太好用,看演示:
git rebase -i dev
後進入如下介面。
1 pick ffc75a4 修改
2 pick 6c2217f bbb
3 pick a615960 修改a 1
4 pick e4817b3 修改a 2
5 pick 8550690 修改a 3
6
7 # Rebase 3190ea4..8550690 onto 3190ea4 (5 command(s))
8 #
9 # Commands:
10 # p, pick = use commit
11 # r, reword = use commit, but edit the commit message
12 # e, edit = use commit, but stop for amending
13 # s, squash = use commit, but meld into previous commit
14 # f, fixup = like "squash", but discard this commit's log message
15 # x, exec = run command (the rest of the line) using shell
16 # d, drop = remove commit
17 #
18 # These lines can be re-ordered; they are executed from top to bottom.
19 #
20 # If you remove a line here THAT COMMIT WILL BE LOST.
21 #
22 # However, if you remove everything, the rebase will be aborted.
23 #
24 # Note that empty commits are commented out
複製程式碼
修改commit註釋前面的pick
,達到合併提交的目的,其中r
是保留提交,修改提交資訊,f
是保留提交但是丟棄這次提交資訊。
1 r ffc75a4 修改
2 f 6c2217f bbb
3 r a615960 修改a 1
4 f e4817b3 修改a 2
5 f 8550690 修改a 3
複製程式碼
然後進入編輯兩個打了r
的提交資訊的介面,修改提交資訊儲存即可。
這時候再看log,剛才的5次提交已經變成2次提交。
commit 94784f0c163bc4b2970f73066c91fac16b64be32
Author: ***
Date: Mon Jan 8 17:01:57 2018 +0800
修改a
commit 52907b261821afb0c38754ba95545ff8826910db
Author: ***
Date: Mon Jan 8 16:28:05 2018 +0800
修改b
複製程式碼
————————————————————
git pull --rebase
與 git pull 的區別
在一般情況下,加與不加 --rebase
是沒有區別的。
然而,從上面說的 git rebase
功能得知,某個分支可能與其遠端分支發生分離,而當你 pull
時使用 git pull
,則會變成你的本地分支和遠端分支合併。
正確的做法是git pull --rebase
,才會拉取到最新的分支。
因此推薦在任何時候 pull
遠端分支,最好加上 --rebase
引數。
————————————————————
reset 和 revert
git reset
修改 HEAD 指向的位置git revert
還原某一個提交,併產生新提交來記錄本次還原
git reset 常用命令
-
git reset HEAD {filename}
: 取消暫存檔案,恢復到已修改未暫存狀態。 -
git reset HEAD~{n}
: 表示回退到n
個提交之前。它也可以用來合併提交,下面的寫法與git commit --amend
結果是一樣的。
git reset HEAD~1
git commit
複製程式碼
-
git reset {version}
: 後面帶版本號,直接回退到指定版本。 -
git reset的三種引數
:- 使用引數
--hard
,暫存區、工作區和 HEAD 指向的目錄樹內容相同。 - 使用引數
--soft
,只更改 HEAD 的指向,暫存區和工作區不變。 - 使用引數
--mixed
或者不帶引數(預設為--mixed
),更改引用的指向及重置暫存區,但是不改變工作區。
- 使用引數
————————————————————
git reflog
檢視提交記錄的命令是git log
,而git reflog
的功能是檢視本地操作記錄,可以看到本地的commit
, merge
, rebase
等操作記錄,並帶有版本號。
b3bf634 HEAD@{0}: rebase -i (finish): returning to refs/heads/feature-rebase-i
b3bf634 HEAD@{1}: rebase -i (fixup): 完善a中的判斷和輸出
dd19de3 HEAD@{2}: rebase -i (fixup): # This is a combination of 2 commits.
c138acf HEAD@{3}: rebase -i (reword): 完善a中的判斷和輸出
a7f47b2 HEAD@{5}: rebase -i (start): checkout dev
a472934 HEAD@{6}: rebase: aborting
a7f47b2 HEAD@{7}: rebase -i (start): checkout dev
a472934 HEAD@{8}: commit: 新增a輸出
c84d5b7 HEAD@{9}: commit: 新增a中的判斷
a5a6e64 HEAD@{10}: commit: 修改a內容
a7f47b2 HEAD@{11}: checkout: moving from dev to feature-rebase-i
複製程式碼
————————————————————
git stash
把工作區內容快取到一個棧裡,之後用 git stash pop
取出。在未提交工作區內容,但是想切到其他分支時非常有用。
注意
不建議同一時間段在不同分支都使用 git stash
,涉及到多個分支的情形還是先 commit 較好,不push到遠端,下次 commit 時可用 --amend
合到上次提交中。
作者:丁香園前端團隊——lwenn