@(版本控制)[git]
前面通過(guò) Git使用記錄 - 基礎(chǔ) 一文記錄了平時(shí)的一些git基礎(chǔ)操作沪袭。由于篇幅限制其馏,只能作為一個(gè)基礎(chǔ)參考虐唠,更加詳細(xì)建議閱讀《git 權(quán)威指南》 或官方提供的文檔荣赶。
本文主要記錄在不同情景下,如何恰當(dāng)?shù)爻蜂N錯(cuò)誤操作刽虹。
個(gè)人開(kāi)發(fā)環(huán)境 ubuntu 14.04
說(shuō)明:
- $ 表示終端執(zhí)行命令
- # 命令注釋
- [] 表示可選
撤銷本地(工作區(qū))的修改
場(chǎng)景:我直接修改 pySerial.py 做個(gè)小測(cè)試, 測(cè)試后想取消掉那些修改酗捌。
$ git checkout pySerial.py
$ 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: pySerial.py
以上操作用于撤銷保存在工作區(qū)修改,但是不會(huì)撤銷暫存區(qū)中的修改涌哲。
由于修改還沒(méi)記錄到 git 中胖缤,撤銷無(wú)法恢復(fù),請(qǐng)慎重阀圾!
修正最后一個(gè)commit
場(chǎng)景:我修正了一個(gè)驚天大 bug哪廓,趕緊提交炫耀一下,然后下一秒初烘,我發(fā)現(xiàn)提交說(shuō)明拼寫(xiě)錯(cuò)誤涡真,好尷尬怎么辦分俯。
使用 git commit 加 "--amend" 用于修改最后一條 commit。
$ git commit -m "#110 Fix for a real a bug bug"
[master 6665748] Fix for a real a bug bug
1 file changed, 1 insertion(+), 3 deletions(-)
$ git commit --amend -m "#110 Fix for a real big bug"
[master 6375a9b] Fix for a real big bug
1 file changed, 1 insertion(+), 3 deletions(-)
再比如提交后發(fā)現(xiàn)漏了某些文件哆料, 可以添加修改到暫存區(qū)后執(zhí)行上述命令修正缸剪。
注意到上述提交的 SHA 修正后發(fā)生改變,說(shuō)明改變了 git 的歷史东亦,所以對(duì)于已經(jīng)推到共享服務(wù)器的 commit杏节,修改也可能導(dǎo)致其他合并沖突!
撤銷本地提交
場(chǎng)景:修改提交了幾個(gè) commit典阵,但是后面發(fā)現(xiàn)簡(jiǎn)直難看或著啥來(lái)的奋渔,決定撤銷掉(這里還在本地,沒(méi)有推到共享服務(wù)器)
找到你想保留的最后一條 commit 的 SHA_last
$ git reset [--mixed] SHA_last
git reset 默認(rèn)使用模式 --mixed
, 操作后壮啊,原先提交的 commit 被撤銷嫉鲸,但是對(duì)應(yīng)的文件修改依然會(huì)保留在工作區(qū)。
如果想把修改內(nèi)容也拋棄歹啼,可以使用參數(shù) --hard
玄渗, 之后,全部都干凈了染突。
重置上面的操作 (抬頭..就上面)
場(chǎng)景:我把前面幾個(gè) commit 撤銷了捻爷,而且還使用了 --hard
辈灼,而后份企,我發(fā)現(xiàn)把有用的提交也不小心撤銷了,怎么撤銷上面的撤銷....
使用 git log 已經(jīng)無(wú)法查看想回退版本的 SHA巡莹,但是秉承走過(guò)就一定會(huì)留下痕跡(浮現(xiàn)老大那輕蔑的眼神司志,又提了什么傻逼commit然后偷偷回退....)的理念, 方法就是使用git reflog
降宅,查看到你提交過(guò)所有痕跡骂远,包括已經(jīng)撤銷的(其實(shí)git 回定期清除用不到的對(duì)象,所以時(shí)間太長(zhǎng)久腰根,分支改動(dòng)刪除了的激才,就不要指望記錄還在了)。
如列子额嘿, 我回退到 83a852b
, 發(fā)現(xiàn)出錯(cuò)瘸恼,想跳回到d2ef270
,使用 git log 沒(méi)有記錄册养,使用 git reflog东帅, 可以看到對(duì)應(yīng) SHA,然后直接 reset 到對(duì)應(yīng)提交球拦。
$ git log --pretty=format:"%h %an %ar : %s"
83a852b luchaodong 20 hours ago : fix uart error with thread & add setup.py
5ec962d luchaodong 12 days ago : add doc 9b16bc4 luchaodong 12 days ago : add py serial rx/tx
$ git reflog
83a852b HEAD@{0}: reset: moving to 83a852b
d2ef270 HEAD@{1}: commit: test more commit
4e50ae7 HEAD@{2}: commit (amend): #110 Fix for a real big bug
c2e7dbb HEAD@{3}: commit: #110 Fix for a real a bug bug
83a852b HEAD@{4}: commit: fix uart error with thread & add setup.py
5ec962d HEAD@{5}: commit: add doc
9b16bc4 HEAD@{6}: commit (initial): add py serial rx/tx
$ git reset d2ef270
Unstaged changes after reset:
M pySerial.py
$ git log --pretty=format:"%h %an %ar : %s"
d2ef270 luchaodong 69 seconds ago : test more commit
4e50ae7 luchaodong 2 minutes ago : #110 Fix for a real big bug
83a852b luchaodong 20 hours ago : fix uart error with thread & add setup.py
5ec962d luchaodong 12 days ago : add doc
9b16bc4 luchaodong 12 days ago : add py serial rx/tx
另外也可以記錄對(duì)應(yīng)幾個(gè)提交的 SHA靠闭,然后通過(guò)git cherry-pick SHA
把那幾個(gè)提交撤銷重置帐我。
提交到錯(cuò)誤分支的處理方法
場(chǎng)景:開(kāi)發(fā)并提了幾個(gè) commit,發(fā)現(xiàn)當(dāng)前在 mater 分支愧膀,但是之前的這幾個(gè)提交是新功能拦键,還不想提交到主分支。
你可以這么做:
$ git branch new_feture # 保存當(dāng)前的提交到新分支
$ git reset --hard origin/master # 恢復(fù)主分支
$ git checkout new_feture
保證在最新上更新
場(chǎng)景:幾天前你從 master 分支創(chuàng)建 new_fea 分支開(kāi)發(fā)新特性檩淋,但是到了今天矿咕,master 分支有了其他提交,new_feam 已經(jīng)滯后master 分支狼钮,但是你希望這幾天開(kāi)發(fā)的新特性是從今天開(kāi)始的碳柱,而不是滯后那么多天。
當(dāng)然你可以直接 merge 或者 reset 暫存更新再重新提交熬芜,但是這里有一種更加優(yōu)雅的做法時(shí) rebase
莲镣。
$ git rebase master
上述 rebase 過(guò)程如下:
- 找到當(dāng)前分支與 master 的共同祖先
- Reset 到共同祖先位置,暫存 new_fea 后續(xù)的提交
- Fast merge 到 master 末尾涎拉,然后再重新 commit 暫存的 new_fea 提交
撤銷多個(gè)不連續(xù)的commit
場(chǎng)景:需要修改到一個(gè)早期提交的消息瑞侮;發(fā)現(xiàn)一個(gè)早期提交漏了一些修改,想把幾個(gè)提交合并鼓拧,讓log更加簡(jiǎn)潔的時(shí)候等可以嘗試以下方法半火。
$ git rebase -i SHA_last
使用參數(shù) -i 打開(kāi)缺省編輯器
我剛測(cè)試提交了#1111-1 -- #1111-6 6個(gè)提交,輸入后會(huì)看到如下
按時(shí)間先后排下來(lái)每個(gè)提交:第一列是執(zhí)行的命令季俩,第二列是SHA钮糖, 第三列是提交說(shuō)明
里面也有詳細(xì)的使用說(shuō)明
pick e77c88d #1111-1 test - edit commit
pick 5a1425b #1111-2 test - edit commit
pick b1d7e93 #1111-3 test - edit commit
pick 240d1b7 #1111-4 test - edit commit
pick 2073df0 #1111-5 test - edit commit
pick f61e1ee #1111-6 test - edit commit
# Rebase 83a852b..f61e1ee onto 83a852b
#
# 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
執(zhí)行操作
1 撤銷某個(gè)commit及其修改 : 在編輯器里面直接刪除對(duì)應(yīng)那一行。
2 修改 commit 消息 : 把第一列的 pick 替換為 reword (或者直接用 r); 退出保存后酌住, 會(huì)提示重新編輯消息店归。
3 把兩個(gè) commit 合并到一起 : 使用 squash 或 fixup 命令 “向上” 合并
帶有這兩個(gè)命令的 commit 會(huì)被合并到它的 前一個(gè)(更早的提交) commit 里。
- squash酪我, Git 會(huì)提示我們給新合并的 commit 一個(gè)新的 commit 消息消痛;
- fixup 則會(huì)把合并清單里第一個(gè) commit 的消息直接給新合并的 commit 。
4 改變提交順序 : 修改每一行的順序來(lái)改變對(duì)應(yīng)commit 的順序都哭。
很容易失敗
撤銷一個(gè)已經(jīng)有副本的commit
場(chǎng)景:做錯(cuò)事了秩伞,而且 push 到服務(wù)器,并且被其他人 pull欺矫,使用前面的 reset 可能給后續(xù)帶來(lái)沖突纱新。
聚集反物質(zhì),把你之前的提交抵消掉汇陆,回產(chǎn)生一條新記錄怒炸,但是內(nèi)容被重置。
$ git revert SHA_I_dont_want_you
這是 Git 最安全毡代、最基本的撤銷場(chǎng)景阅羹,因?yàn)樗⒉粫?huì)改變歷史, 然后勇敢地push 到服務(wù)器吧勺疼。
停止追蹤文件
場(chǎng)景 : .gitignore 會(huì)阻止 Git 追蹤文件的修改,甚至不關(guān)注文件是否存在捏鱼,但這只是針對(duì)那些以前從來(lái)沒(méi)有追蹤過(guò)的文件执庐。一旦有個(gè)文件被加入并提交了,Git 就會(huì)持續(xù)關(guān)注該文件的改變导梆。
如果你希望從 Git 的追蹤對(duì)象中刪除那個(gè)本應(yīng)忽略的文件轨淌,
$ git rm --cached file_name
Git 會(huì)從追蹤對(duì)象中刪除它,但讓文件在磁盤上保持原封不動(dòng)看尼。因?yàn)楝F(xiàn)在它已經(jīng)被忽略了递鹉,你在 git status 里就不會(huì)再看見(jiàn)這個(gè)文件,也不會(huì)再偶然提交該文件的修改了藏斩。