git入門

image.png

1. git commit --amend

有時(shí)你提交過(guò)代碼之后,發(fā)現(xiàn)一個(gè)地方改錯(cuò)了,
你下次提交時(shí)不想保留上一次的記錄;
或者你上一次的commit message的描述有誤,
這時(shí)候你可以使用接下來(lái)的這個(gè)命令:git commit --amend
該操作會(huì)改變你原來(lái)的commit id

2. cherry-pick vs rebase vs merge

2.1. merge
merge合并

image.jpeg
那么git merge topic命令將會(huì)把在master分支上二者共同的節(jié)點(diǎn)
(E節(jié)點(diǎn))之后分離的節(jié)點(diǎn)(即topic分支的A B C節(jié)點(diǎn))重現(xiàn)在master分支上,
直到topic分支當(dāng)前的commit節(jié)點(diǎn)(C節(jié)點(diǎn)),并位于master分支的頂部。
并且沿著master分支和topic分支創(chuàng)建一個(gè)記錄
合并結(jié)果的新節(jié)點(diǎn),該節(jié)點(diǎn)帶有用戶描述合并變化的信息
2.2. cherry-pick
對(duì)于多分支的代碼庫(kù),將代碼從一個(gè)分支轉(zhuǎn)移到另一個(gè)分支是常見(jiàn)需求。
這時(shí)分兩種情況。一種情況是,你需要另一個(gè)分支的所有代碼變動(dòng),那么就采用合并(git merge)。
另一種情況是,你只需要部分代碼變動(dòng)(某幾個(gè)提交),這時(shí)可以采用 Cherry pick。
    a - b - c - d   Master
         \
           e - f - g Feature
  • git cherry-pick 分支
  • git cherry-pick <commitHash>
  • git cherry-pick <HashA> <HashB>
  • git cherry-pick A..B
2.3. rebase

概念:git rebase你其實(shí)可以把它理解成是重新設(shè)置基線,將你的當(dāng)前分支重新設(shè)置開(kāi)始點(diǎn)。這個(gè)時(shí)候才能知道你當(dāng)前分支于你需要比較的分支之間的差異。

image.png

1.  master  1-2-3 是現(xiàn)在的分支狀態(tài)
2. 這個(gè)時(shí)候從master ,checkout出來(lái)一個(gè)prod分支
3. 然后master提交了4.5,prod提交了6.7
4. 這個(gè)時(shí)候master分支狀態(tài)就是1-2-3-4-5,prod狀態(tài)變成1-2-3-6-7
5. 如果在prod上用rebase master ,prod分支狀態(tài)就成了1-2-3-4-5-6-7
6. 如果是merge 會(huì)出來(lái)一個(gè)8,這個(gè)8的提交就是把4-5合進(jìn)來(lái)的提交

好處:提交直觀 便于回退 拉取代碼有預(yù)處理階段 不用生成新的節(jié)點(diǎn)
注意:不要通過(guò)rebase對(duì)任何已經(jīng)提交到公共倉(cāng)庫(kù)中的commit進(jìn)行修改

  • git pull --rebase
  • git rebase -i [startpoint] [endpoint]
    git rebase [startpoint] [endpoint] --onto [branchName]
  • git rebase -i HEAD~n
pick:保留該commit(縮寫:p)
reword:保留該commit,但我需要修改該commit的注釋(縮寫:r)
edit:保留該commit, 但我要停下來(lái)修改該提交(不僅僅修改注釋)(縮寫:e)
squash:將該commit和前一個(gè)commit合并(縮寫:s)
fixup:將該commit和前一個(gè)commit合并,但我不要保留該提交的注釋信息(縮寫:f)
exec:執(zhí)行shell命令(縮寫:x)
drop:我要丟棄該commit(縮寫:d)

3. 什么是 HEAD

3.1 概念:

Git 中的 HEAD 可以理解為一個(gè)指針,我們可以在命令行中輸入 cat .git/HEAD 查看當(dāng)前 HEAD指向哪兒,一般它指向當(dāng)前工作目錄所在分支的最新提交或者分支。

切換分支時(shí),HEAD 會(huì)移動(dòng)到指定分支

3.2 HEAD游離狀態(tài)

使用的是 git checkout < commit id>,即切換到指定的某一次提交,HEAD就會(huì)處于 detached狀態(tài)(游離狀態(tài))

HEAD 處于游離狀態(tài)時(shí),我們可以很方便地在歷史版本之間互相切換,比如需要回到
某次提交,直接 checkout 對(duì)應(yīng)的 commit id 或者 tag 名即可。
它的弊端就是:在這個(gè)基礎(chǔ)上的提交會(huì)新開(kāi)一個(gè)匿名分支!
HEAD 就會(huì)處于 detached 狀態(tài)
可以看到,我還沒(méi)有修改和提交的情況下,切換完成就給我新建了一個(gè)分支,并且指明 HEAD 
正游離在 2772886 的 <commit id> 上。
如果不做任何修改,想回到 master 分支,直接 git checkout master 即可,
而不要 checkout master 主干所對(duì)應(yīng)的 <commit id>。
順利回到主干的話,HEAD 的游離狀態(tài)會(huì)取消,原臨時(shí)游離分支也會(huì)消失。
如果是在游離狀態(tài)做了修改和提交,則:
切換會(huì) master 分支時(shí),在游離狀態(tài)所做的修改和提交無(wú)法追溯
3.3 git reset [--soft | --mixed | --hard] HEAD^
  • --mixed 為默認(rèn),可以不用帶該參數(shù),用于重置暫存區(qū)的文件與上一次的提交(commit)保持一致,工作區(qū)文件內(nèi)容保持不變。
$ git reset HEAD^            # 回退所有內(nèi)容到上一個(gè)版本  
$ git reset HEAD^ hello.php  # 回退 hello.php 文件的版本到上一個(gè)版本  
$ git  reset  052e           # 回退到指定版本
  • --soft 參數(shù)用于回退到某個(gè)版本 保留工作目錄,并把重置 HEAD 所帶來(lái)的新的差異放進(jìn)暫存區(qū)
    image.png
什么是「重置 HEAD 所帶來(lái)的新的差異:
由于 HEAD 從 4 移動(dòng)了 3,而且在 reset 的過(guò)程中工作目錄和暫存區(qū)的內(nèi)容沒(méi)有被清理掉,
所以 4 中的改動(dòng)在 reset 后就也成了工作目錄新增的「工作目錄和 HEAD 的差異」。
這就是上面一段中所說(shuō)的「重置 HEAD 所帶來(lái)的差異」
  • --hard 參數(shù)撤銷工作區(qū)中所有未提交的修改內(nèi)容,將暫存區(qū)與工作區(qū)都回到上一次版本,并刪除之前的所有信息提交:
$ git reset –hard HEAD~3  # 回退上上上一個(gè)版本  
$ git reset –hard bae128  # 回退到某個(gè)版本回退點(diǎn)之前的所有信息。 
$ git reset --hard origin/master    # 將本地的狀態(tài)回退到和遠(yuǎn)程的一樣 
注意:謹(jǐn)慎使用 –hard 參數(shù),它會(huì)刪除回退點(diǎn)之前的所有信息。

4 Gerrit 的 Change-Id

Change-Id 是 gerrit (代碼審核平臺(tái))的概念

image.png

  • Change-Id的生成
Gerrit 提供了標(biāo)準(zhǔn)的“commit-msg”鉤子來(lái)實(shí)現(xiàn)。
Git 提供了4個(gè)提交工作流鉤子:pre-commit、prepare-commit-msg、
commit-msg、post-commit。其中 commit-msg 鉤子,
會(huì)在我們執(zhí)行 git commit 時(shí)被執(zhí)行。
本質(zhì)上,commit-msg 鉤子是一段腳本程序,放在 .git/hooks 目錄下。
commit-msg 腳本可以使用 Shell、Ruby、Python 等語(yǔ)言實(shí)現(xiàn)。
  • 案例1
### Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit
shell
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 4 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 473 bytes | 473.00 KiB/s, done.
Total 5 (delta 4), reused 0 (delta 0)
remote: Resolving deltas: 100% (4/4)
remote: Processing changes: refs: 1, done    
To ssh://sg-8-130.hst.xxxxx.net:29418/xxxx/xxxxxx
 ! [remote rejected]   HEAD -> refs/for/dev (same Change-Id in multiple changes.
Squash the commits with the same Change-Id or ensure Change-Ids are unique for each commit)
error: failed to push some refs to 'ssh://xxxxxxxx@sg-8-130.hst.xxxxxx.net:29418/xxxxx/xxxxx'
在dev分支上有重復(fù)的change-id,使用
shell
git commit --amend 
  • 案例2 缺失 Change-Id
  1. 如果缺失 Change-Id 的是最后一個(gè) (head) commit, 使用以下命令即可解決問(wèn)題
  $ git commit --amend
  1. 如果缺失 Change-Id 的不是最后一個(gè) commit,第二個(gè)提交缺失 Change-Id, 可用 reset 方法:
  $ git reset 1a9096a34322885ac101175ddcac7dab4c52665d
  $ git commit --amend
  $ git add ......
  $ git commit -m "你的提交日志"
  $ git push review HEAD:refs/for/dev
  1. 使用交互式rebase 找回任意提交位置的 Change-Id 以及有多個(gè) commit 缺失 Change-Id 的情況
// 找到缺失 Change-Id 的那個(gè) commit:
// 執(zhí)行 git rebase -i, 參數(shù)為 該提交的上一個(gè)提交的 commit-id (本例中為 "表單" 那個(gè)提交):
   $ git rebase -I d714bcde0c14ba4622d28952c4b2a80882b19927
//將缺失了 Change-Id 的 commit 前面的 pick 改為 reword 即可
//逐個(gè)編輯 commit-msg 可以不需要修改 保存推出即可
$ git log
commit 8aaaa749db4a5b105aa746659c5cd266ac82fffe
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 17:43:24 2016 +0800
 
    I am commit message 3
     
    Change-Id: Ic89d5ce6ce4de70d1dcb315ce543c86a2b3ac003
 
commit 8e1cad33bcd98e175cba710b1eacfd631a5dda41
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 17:43:00 2016 +0800
 
    I am commit message 2
     
    Change-Id: I9d2af0cc31423cf808cd235de0ad02abf451937d
 
commit 1a9096a34322885ac101175ddcac7dab4c52665d
Author: liux <liux@xxxx.cn>
Date:   Mon Dec 19 15:23:36 2016 +0800
 
    I am commit message 1
 
commit d714bcde0c14ba4622d28952c4b2a80882b19927
Author: shangsb <shangsb@czfw.cn>
Date:   Wed Dec 14 09:20:52 2016 +0800
 
    這是一個(gè)提交
     
    Change-Id: I629b2bedff95491875f63634ad3da199612735b6
$ git rebase -I d714bcde0c14ba4622d28952c4b2a80882b19927
這個(gè)命令會(huì)打開(kāi)默認(rèn)的編輯器,一般為 vi. 內(nèi)容如下:
pick 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
reword 1a9096a I am commit message 1
pick 8e1cad3 I am commit message 2
pick 8aaaa74 I am commit message 3
# Rebase d714bcd..8aaaa74 onto d714bcd
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

疑問(wèn)

  • A-B-C 應(yīng)該在最新節(jié)點(diǎn)C上追加 假如我想在B或者A上追加應(yīng)該怎么處理
  • 消息分支已經(jīng)push 并且已經(jīng)合并到master-pre 最終合并到master 而我本地追蹤的是遠(yuǎn)程master 但是還是顯示超前一個(gè)版本
  • 錯(cuò)誤操作導(dǎo)致我的分支出現(xiàn)別人的代碼節(jié)點(diǎn) 并且都處于待push的狀態(tài) 也就是超前遠(yuǎn)程倉(cāng)庫(kù)n個(gè)版本

參考文檔:
http://www.itdecent.cn/p/4079284dd970
http://www.itdecent.cn/p/4a8f4af4e803

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄: git原理 git fork & cherry-pick & rebase git打patch以及應(yīng)用pa...
    木小易Ying閱讀 1,340評(píng)論 0 5
  • git 分支命令 git 分支可以理解為代碼的平行世界,你可以在任意一個(gè)平行世界里開(kāi)發(fā)代碼,其他的平行世界不受影響...
    特立獨(dú)行的佩奇閱讀 585評(píng)論 0 0
  • 文件說(shuō)明 Git開(kāi)發(fā)常用命令,是在 hongiii 的基礎(chǔ)上在進(jìn)行補(bǔ)充 Git介紹 Git是分布式版本控制系統(tǒng) 集...
    微光北下閱讀 297評(píng)論 0 0
  • 前言 來(lái)啦老鐵! 時(shí)間過(guò)得真快啊,2個(gè)多禮拜的時(shí)間又過(guò)去了,又到了不見(jiàn)不散的學(xué)習(xí)時(shí)間~技術(shù)來(lái)源于工作(總感覺(jué)有點(diǎn)怪...
    狄仁杰666閱讀 2,229評(píng)論 0 1
  • 題外話: git命令真的很多,這里也只是列舉了一些常用的,后邊的注釋很重要,耐心看會(huì)看到不同及規(guī)律。 熱熱身:...
    3Q竹林閱讀 832評(píng)論 0 1

友情鏈接更多精彩內(nèi)容