git命令

reset
常用參數(shù):
// 暫存區(qū)和HEAD的提交保持一致
git reset HEAD // 回滾未推送到遠程的commit,并且清空暫存區(qū)的內(nèi)容到工作區(qū)
git reset HEAD~2 // 回滾未推到遠程的commit最新的兩個到工作區(qū),并且清空暫存區(qū)的內(nèi)容到工作區(qū)
git reset --hard HEAD // 工作區(qū)、暫存區(qū)和HEAD保持一致 HEAD可以是提交sha
git reset --soft HEAD // 回滾歷史,并且將回滾的更改放到暫存區(qū)
詳細描述:
--soft 回退后a分支修改的代碼被保留并標(biāo)記為add的狀態(tài)(git status 是綠色的狀態(tài))。<br/>
--mixed 重置索引,但不重置工作樹,更改后的文件標(biāo)記為未提交(add)的狀態(tài)。默認(rèn)操作。。<br/>
--hard 重置索引和工作樹,并且a分支修改的所有文件和中間的提交,沒提交的代碼都被丟棄了。<br/>
--merge 和--hard類似,只不過如果在執(zhí)行reset命令之前你有改動一些文件并且未提交,merge會保留你的這些修改,hard則不會。【注:如果你的這些修改add過或commit過,merge和hard都將刪除你的提交】<br/>
--keep 和--hard類似,執(zhí)行reset之前改動文件如果是a分支修改了的,會提示你修改了相同的文件,不能合并。如果不是a分支修改的文件,會移除緩存區(qū)。git status還是可以看到保持了這些修改。
rebase (合并衍合變基)
rebase 即變基,顧名思義,就是改變基準(zhǔn)點,以 commit 為基準(zhǔn)點可以隨意修改 commit
歷史,以分支為基準(zhǔn)點可以合并分支,同時整理 commit。
rebase合并分支
git rebase dev
歷史記錄回滾到最后一個公共父節(jié)點,如果當(dāng)前節(jié)點和目標(biāo)節(jié)點中間還有節(jié)點,則會復(fù)制中間所有節(jié)點內(nèi)容,會把當(dāng)前節(jié)點指向dev最新的節(jié)點。
一般我們從develop拉一個分支出來,但是develop更新的時候,新的分支又要和develop保持一致,這個時候,不要又從develop直接合過來,我們可以用rebase,直接將當(dāng)前分支移到develop最新節(jié)點上,這個看下面參考鏈接2。
(參考鏈接:https://juejin.im/post/6844903729209016327#heading-10
https://juejin.im/post/6844903593015787534#heading-9)
注意: 多人開發(fā),已經(jīng)push到遠端的代碼,請不要使用rebase合并提交,因為rebase會改變提交線,極易造成沖突的產(chǎn)生。
拉取最新代碼
rebase 也可以在本地分支push到服務(wù)器倉庫前進行git rebase origin (branch)保證拉取最新代碼。(有時候要慎用,情況及解決方案見底部備注1)
rebase合并commit
git rebase -i HEAD~3
git rebase命令的i參數(shù)表示互動(interactive),這時git會打開一個互動界面,進行下一步操作。
常見合并commit命令:
- pick:正常選中
- reword:選中,并且修改提交信息;
- edit:選中,rebase時會暫停,允許你修改這個commit(參考這里)
- squash:選中,會將當(dāng)前commit與上一個commit合并
- fixup:與squash相同,但不會保存當(dāng)前commit的提交信息
- exec:執(zhí)行其他shell命令
revert (撤銷)
新建一個commit,用來撤銷指定commit
后者的所有變化都將被前者抵消,并且應(yīng)用到當(dāng)前分支
- 對于單一 parent 的 commit,直接使用 git revert commit_id;
- 對于具有多個 parent 的 commit,需要結(jié)合 -m 屬性:git revert commit_id -m parent_id;
- 對于從 branch 合并到 master 的 merge commit,master 的 parent_id 是1,branch 的 parent_id 是2, 反之亦然;(1,2的目的是決定哪個分支會被保留下來,如果當(dāng)前分支是develop,合并過來的分支是feature,那么參數(shù)為1,則會保留當(dāng)前的develop分支,如果是2,則會保留feature分支)
這些都是丟棄某次提交的操作
但是,有時候我們想把丟棄的提交在找回來,我們就可以用git revert把之前的revert丟棄掉,就相當(dāng)于找回之前的提交。
stash (開發(fā)暫存)
暫時將未提交的變化移除,稍后再移入
git stash // 當(dāng)前修改代碼存入棧中,你的棧里將充滿了未提交的代碼
git stash save "work in progress for foo feature" // 增加stash日志信息
git stash list // 將當(dāng)前的Git棧信息打印出來,你只需要將找到對應(yīng)的版本號
git stash apply stash@{1} // 將你指定版本號為stash@{1}的工作取出來
git stash pop // 將最后一次stash工作區(qū)提取出來
git stash clear // 來將棧清空
常見問題
1. git rebase后出現(xiàn)(xxx|REBASE-i)的解決辦法
git rebase --abort // 代碼回退 回到git rebase之前的狀態(tài)
2. git在提交代碼時需要先和遠程代碼進行同步
git fetch origin
$ git rebase origin/master
3. --no-ff作用
// 對Develop分支進行合并
git merge --no-ff develop
作用,提供清晰合并記錄,加上這個就是合并會以新的提交記錄出現(xiàn),不加則是一條提交記錄線,不夠清晰(http://www.ruanyifeng.com/blog/2012/07/git.html)
4. 撤銷git rebase
使用git reflog + git reset --hard
git reflog // 獲取更改列表
git reset --hard HEAD@{23}
一些規(guī)范
禁止反向拉取 develop 分支
使用rebase讓分支移到最新代碼上
不經(jīng)過 Pull Request 的合并
Pull Request 可以進行簡單的codeReview
重復(fù)使用已經(jīng)合并的分支
移除已完成的分支,讓提交記錄更清晰
沒有意義的 Commit Message
commit 沒有任何意義
備注
備注1 git rebase origin/master 可能遇到的坑
git fetch origin dev && git rebase origin/dev這種操作在大部分情況下是沒問題的,但這里至少有兩個坑。第一個坑比較常見,有些倉庫里remote.origin.fetch由于某些原因沒有配置,或者配置的值是錯的,或者配置的值不夠通用,導(dǎo)致git fetch origin dev并不會更新origin/dev,因而rebase的時候origin/dev指向的commit并不是預(yù)期的commit。另一個問題比較少見,那就是在遠程倉庫里可能存在好幾個不同的dev,譬如dev分支,dev tag,甚至其它叫dev的ref。那這里僅僅寫dev的話,可能拉取到的并不是refs/heads/dev,而是譬如refs/comments/dev,那也會導(dǎo)致origin/dev不會更新。
針對第一個坑,當(dāng)你的操作依賴origin/dev這種remote tracking branch時,務(wù)必確定remote.origin.fetch的值是對的??寺∩傻膫}庫里,它的值會被自動配置為
+refs/heads/:refs/remotes/origin/。git init創(chuàng)建的倉庫里這個需要手動添加git config remote.origin.fetch +refs/heads/:refs/remotes/origin/
另一個比較方便的做法是不要用origin/dev,改用FETCH_HEAD。FETCH_HEAD里面存儲的是拉取ref當(dāng)前指向的commit,即使remote.origin.fetch沒有配置也可以按預(yù)期工作。當(dāng)一次拉取多個ref時,F(xiàn)ETCH_HEAD里存的是排序以后排第一位的ref的commit,所以一次拉取多個的話,還是用origin/dev這樣的更可靠。
FETCH_HEAD無法應(yīng)付第二個坑。針對第二個坑,在fetch或者pull時,使用ref的全名可破。譬如拉分支dev,就寫refs/heads/dev,拉tag dev,就寫refs/tags/dev等等。這樣就可以避免歧義了。日常提交代碼時很少遇到這種情況,可以還是寫dev比較省事,因為出問題了大概率當(dāng)場就會發(fā)現(xiàn)。但在自動化腳本里,譬如構(gòu)建腳本里,盡量用全稱避免潛在的問題,否則默默跑了一段時間才發(fā)現(xiàn)問題就坑大了。
參考鏈接:
Git分支管理策略:
http://www.ruanyifeng.com/blog/2012/07/git.html
Git 工作流程:
http://www.ruanyifeng.com/blog/2015/12/git-workflow.html
簡介我的 Git Work Flow:
https://juejin.im/post/6844903593015787534