干貨|工作中要使用Git,看這篇文章就夠了
本文將從 Git 入門到進(jìn)階、由淺入深,從常用命令、分支管理、提交規(guī)范、vim 基本操作、進(jìn)階命令、沖突預(yù)防、沖突處理等多方面展開,足以輕松應(yīng)對工作中遇到的各種疑難雜癥,如果覺得有所幫助,還望看官高抬貴手給個(gè)贊唄,感謝!
雖說現(xiàn)在工作中使用 Git 都會用一些圖形化管理工具來提高開發(fā)效率。可事實(shí)上使用圖形管理化工具的前提,也是基于對命令都基本了解。還有比如我平時(shí)用的工具 Github Desktop 因?yàn)椴粠У谌胶喜⒐ぞ撸荒苁謩咏鉀Q沖突,而且有的功能沒有,只能配合自己手動敲命令。
即使是工具也沒有那么完美的工具,掌握命令才是漁,工具只是魚。其他的 Git 可視化管理工具比如:小烏龜、SourceTree、還有我們開發(fā)用的 IDE 集成的,本篇不過多介紹。
基本概念
Git 是一個(gè)開源的分布式版本控制系統(tǒng),用以有效、高速的處理從很小到非常大的項(xiàng)目版本管理。

Git 的作用與好處是:
可以幫我們保存文件的所有修改記錄,并且使用版本號進(jìn)行區(qū)分,讓我們隨時(shí)可以瀏覽歷史版本、對比不同版本的差異、還原到指定版本,起到恢復(fù)和保護(hù)作用的同時(shí),還能和其他人同時(shí)修改,然后通過 Git 來合并修改的部分文件,超級方便。主要有以下特點(diǎn):
- 分支更快、更容易。
- 支持離線工作;本地提交可以稍后提交到服務(wù)器上。
- Git 提交都是原子的,且是整個(gè)項(xiàng)目范圍的,而不像 CVS 中一樣是對每個(gè)文件的。
- Git 中的每個(gè)工作樹都包含一個(gè)具有完整項(xiàng)目歷史的倉庫。
- 沒有哪一個(gè) Git 倉庫會天生比其他倉庫更重要。

不熟的同學(xué)別和 Github 搞混了,Git 是工具,Github 是平臺,沒有什么必然的聯(lián)系,就像 Java 和 JavaScript 也沒有什么必然聯(lián)系一樣
Github 是一個(gè)主流的代碼托管平臺。可以理解為存放和管理代碼的網(wǎng)盤,可以把自己的代碼傳上去進(jìn)行共享和維護(hù)。

安裝配置
安裝地址:Git - Downloads (git-scm.com)
安裝好后,命令行窗口是使用 Git Bash、CMD、Powershell、終端、或者編譯器內(nèi)置的都行,這個(gè)就看個(gè)人喜好。
接著可以再配置下默認(rèn)用戶名和郵箱,比如配置全局的就用如下兩條命令,替換成自己的用戶名和郵箱,以后所有的項(xiàng)目都會默認(rèn)這里配置的用戶信息
git config --global user.name 'xxxx'
git config --global user.email 'xxxx@xx.com'
如果只需要在某個(gè)特定的項(xiàng)目中用其他的名字和郵箱,不用全局的,就把上面命令中的 --global 去掉在項(xiàng)目下執(zhí)行即可,或者不執(zhí)行命令,直接在項(xiàng)目下的 .git/config 文件里添加如下,也可以
# xxx 指的是填你自己的用戶名和郵箱,不是真的寫 xxxx 上去
[user]
name = xxxx
email = xxxx@xx.com
基本操作
先了解一下幾個(gè)基本概念:
- 工作區(qū):開發(fā)的地方,開發(fā)過程就是對工作區(qū)的操作
- 暫存區(qū):執(zhí)行
git add xxx命令后,會把當(dāng)前修改過的文件添加到暫存區(qū) - 本地倉庫:執(zhí)行
git commit命令完成后,會把當(dāng)前暫存區(qū)的文件放入本地倉庫 - 遠(yuǎn)程倉庫:就是用來托管代碼的服務(wù)器(如:Github、Gitee、GitLab、工蜂、Bitbucket..),執(zhí)行
git push命令后,會把本地倉庫的文件提交到遠(yuǎn)程倉庫
常見選項(xiàng)
再認(rèn)識一下幾個(gè)后面會用到多次的命令。
| 命令 | 縮寫 | 意思 |
|---|---|---|
| --all | -a | 全部 |
| --force | -f | 強(qiáng)制 |
| --delete | -d | 刪除 |
| --delete --force | -D | 強(qiáng)制刪除 |
| --move | -m | 移動或重命名 |
| --move --force | -M | 強(qiáng)制移動或重命名 |
| -u | 設(shè)置默認(rèn)遠(yuǎn)程分支 |
基本用法

上面的四條命令在工作目錄、暫存目錄(也叫做索引)和倉庫之間復(fù)制文件。
git add *files*把當(dāng)前文件放入暫存區(qū)域。git commit給暫存區(qū)域生成快照并提交。git reset -- *files*用來撤銷最后一次git add *files*,你也可以用git reset撤銷所有暫存區(qū)域文件。git checkout -- *files*把文件從暫存區(qū)域復(fù)制到工作目錄,用來丟棄本地修改。
你可以用 git reset -p, git checkout -p, or git add -p進(jìn)入交互模式。
也可以跳過暫存區(qū)域直接從倉庫取出文件或者直接提交代碼。

git commit -a相當(dāng)于運(yùn)行git add把所有當(dāng)前目錄下的文件加入暫存區(qū)域再運(yùn)行。git commit.git commit files進(jìn)行一次包含最后一次提交加上工作目錄中文件快照的提交。并且文件被添加到暫存區(qū)域。git checkout HEAD -- files回滾到復(fù)制最后一次提交。
拉取遠(yuǎn)程項(xiàng)目
拉取遠(yuǎn)程項(xiàng)目到本地,先復(fù)制遠(yuǎn)程項(xiàng)目鏈接,再在本地執(zhí)行如下命令
# 拉項(xiàng)目
git clone https://xxxx
# 拉項(xiàng)目的同時(shí)自動初始化并更新項(xiàng)目中的每一個(gè)子模塊
git clone --recursive https://xxxx
上傳本地項(xiàng)目
本地新建的項(xiàng)目,還沒有提交到遠(yuǎn)程倉庫,就需要先關(guān)聯(lián)遠(yuǎn)程倉庫。先在遠(yuǎn)程創(chuàng)建一個(gè)空項(xiàng)目,并復(fù)制該項(xiàng)目的鏈接,然后在本地項(xiàng)目根目錄依次執(zhí)行下面命令即可
git init // 初始化本地 Git 倉庫,會生成一個(gè) .git 隱藏文件夾
git remote add origin https://xxxx // 將本地項(xiàng)目關(guān)聯(lián)遠(yuǎn)程倉庫,后面的 https://xxxx 就是復(fù)制的遠(yuǎn)程倉庫的鏈接
git pull --rebase origin master // 上傳之前更新一下,確保沒有沖突,master 為分支名稱,--rebase 后面有介紹
git add . // 添加目錄下所有發(fā)生改變的文件
git commit -m 'xxx' // 添加注釋信息
git push -u origin master // 提交到 master 分支
其中 git remote add origin https://xxxx,就是往 .git/config 文件里添加下面這一段,手動添加也可以,意思就是與遠(yuǎn)程倉庫建立關(guān)聯(lián)。其他的幾條命令后面有介紹,我們先認(rèn)識下 origin 為后面做鋪墊;
[remote "origin"]
url = https://github.com/rdif/xxxx.git
fetch = +refs/heads/*:refs/remotes/origin/*
命令里的 origin 類似變量命名,這是默認(rèn)的而已,沒什么特別的意思,可以隨便寫,假如改成 abc,后面的 git push origin xxx 改成 git push abc xxx 即可,方便區(qū)分遠(yuǎn)程倉庫的
由此可得出一個(gè)結(jié)論,就是一個(gè)項(xiàng)目可以關(guān)聯(lián)多個(gè)遠(yuǎn)程倉庫,命不同的名就行了
沒錯(cuò)
git remote -v 可以快速查看當(dāng)前已經(jīng)關(guān)聯(lián)的遠(yuǎn)程倉庫列表
關(guān)聯(lián)多個(gè)遠(yuǎn)程倉庫
可以使用 git remote add xxx 添加多個(gè),或者直接動在 .git/config 文件里添加。
比如一個(gè)項(xiàng)目同時(shí)關(guān)聯(lián)一個(gè) Github 倉庫和一個(gè) Gitee 倉庫,添加一個(gè) remote 就是了,比如如下:
[remote "github"]
url = https://github.com/rdif/xxxx.git
fetch = +refs/heads/*:refs/remotes/github/*
[remote "gitee"]
url = https://gitee.com/xxxx/xxxx.git
fetch = +refs/heads/*:refs/remotes/gitee/*
[remote "all"]
url = https://github.com/rdif/xxxx.git
url = https://gitee.com/xxxx/xxxx.git
fetch = +refs/heads/*:refs/remotes/all/*
這樣當(dāng)我們提交代碼的時(shí)候,想提交到 Github 就用 git push github master,想同時(shí)提交到 Github 和 Gitee 的倉庫,只需要 git push all master 即可
以命令的方法在某個(gè) remote 下添加 url 如下,比如在上面 remote github 下再添加一個(gè) url:
git remote set-url --add github https:/xxxx.git
常用命令 add/commit/fetch/merge/pull/push
git add
# 添加一個(gè)文件 test.js 到暫存區(qū),多個(gè)文件以空格隔開
git add test.js
# 添加全部文件到暫存區(qū)
git add .
git commit
# 會打開 vim 編輯器,vim 編輯器操作在下面展開說明
git commit
# 提交暫存區(qū)的文件到本地倉庫,并備注當(dāng)前 commit 記錄
git commit -m '備注信息'
# 相當(dāng)于 git add . 加上 git commit -m 'xxxx'
git commit -am 'xxxx'
# 用本地提交替換上次提交,比如不想保留上一次提交或者上一次提交描述信息寫錯(cuò)了之類的
git commit --amend
git fetch
# 獲取 remote origin 對應(yīng)遠(yuǎn)程倉庫指定 master 分支的變更,但是不和本地的合并
git fetch origin master
# 意思一個(gè)樣,拉默認(rèn)的分支而已
git fetch origin
# 也是,等效于 git fetch origin master:master,就是分支配置的默認(rèn)值
git fetch
# 獲取默認(rèn)遠(yuǎn)程倉庫所有分支的變更
git fetch -a
git merge
# 把本地的 test 分支分并到我當(dāng)前分支
git merge test
# 合并 remote origin 對應(yīng)遠(yuǎn)程倉庫的 master 分支到當(dāng)前分支
git merge origin/master
# --on-ff 是 no-fast-forward簡寫,合并并且會在分支上重新生成一個(gè)新的 commit 節(jié)點(diǎn)
git merge --on-ff origin/master
# 加入 --squash 表示合并,但是不生成 commit 記錄,通常用于把本地分支合入遠(yuǎn)程分支
git merge test --squash
# 取消合并
git merge --abort
git pull
pull 和 fetch 都是下載遠(yuǎn)程分支,區(qū)別是 pull 會和當(dāng)前分支合并,fetch 不會
# 拉取 remote origin 對應(yīng)的遠(yuǎn)程倉庫的 master 分支合并到本地的 test 分支
git pull origin master:test
# 這種同理就不解釋了
git pull origin
# git pull --merge 的簡寫,默認(rèn)是 --merge 模式
# 等于 git fetch 加上 git merge,拉遠(yuǎn)程默認(rèn)分支到當(dāng)前分支
git pull
# 把合并模式切換成 rebase,等于 git fetch 加上 git rebase,rebase 后面進(jìn)階有介紹
git pull --rebase origin master
git push
# 推送本地 test 分支到 remote origin 對應(yīng)的遠(yuǎn)程倉庫的 master 分支
git push origin test:master
# 上面同理,推送到遠(yuǎn)程默認(rèn)分支
git push origin test
# 縮寫,同理,用默認(rèn)分支
git push origin
git push
# 相當(dāng)于 git push origin master 加上 git branch --set-upstream master origin/master
# 推送并設(shè)置默認(rèn)遠(yuǎn)程分支
git push -u origin master
# 強(qiáng)制推送,就算本地和遠(yuǎn)程有差異也推上去
git push -f origin master
# 刪除遠(yuǎn)程主機(jī)的 master 分支
git push origin -d master
vim 基本操作
一點(diǎn)點(diǎn)小插曲
比如 git commit 就會打開一個(gè) vim 的終端編輯器,讓我們寫提交說明,新手很容易在這個(gè)編輯器上面踩坑,不知道怎么輸入,不知道怎么退出,最后只能關(guān)閉終端窗口,這也沒辦法,vim 的操作確實(shí)有些反人類。
vim 打開默認(rèn)是不能輸入的,要按 a 或者 i 進(jìn)入編輯模式,輸入完成后,再按 Esc 退出編輯模式,這時(shí)左下角會有輸入框,輸入如下英文字符,注意冒號別打成中文字符,回車即可退出 vim 回到終端:
:w:保存:q:退出:wq:保存并退出!:強(qiáng)制的意思,不能保存時(shí):w!強(qiáng)制保存,不能退出時(shí):q!或:wq!強(qiáng)制退出
我們繼續(xù) git
分支管理 branch/switch/checkout
一個(gè)人玩,可能分支的作用沒那么大,但是團(tuán)隊(duì)協(xié)作,離不開分支管理。
比如本文開頭圖片那樣一個(gè)版本一個(gè)分支多方便,是吧
或者現(xiàn)有一個(gè)新需求一個(gè)頁面分為多個(gè)模塊,分配給多個(gè)人負(fù)責(zé),每人做一個(gè)模塊,最后合并成一個(gè)完整的頁面,如果都在同一個(gè)分支上開發(fā),各種邏輯相互穿插,那沖突真的是人都要搞麻了,如果每個(gè)人都新建一個(gè)分支,開發(fā)自己負(fù)責(zé)的那個(gè)功能,最后再合并到同一個(gè)分支上去就非常方便了
然后因?yàn)槎嗳藚f(xié)作肯定不是在一臺電腦上,所以就需要一個(gè)服務(wù)器,來搭建一個(gè) Git 倉庫服務(wù),或者用公共的云服務(wù)器倉庫存儲,常見的代碼托管平臺有比如:Github、碼云(Gitee)、騰訊工蜂、GitLab、Bitbucket...,關(guān)于這個(gè)本篇文章不過多展開。
創(chuàng)建分支
# 創(chuàng)建本地分支 test,但不切換
git branch test
# 創(chuàng)建 test 分支,并切換到 test 分支
git branch -M test
# 創(chuàng)建 test 分支,并切換到 test 分支
git checkout -b test
# 創(chuàng)建 test 分支,并切換到 test 分支
git switch -c test
# 創(chuàng)建本地與遠(yuǎn)程對應(yīng)的 test 分支,并切換到 test 分支,全稱最好一致
git checkout -b test origin/test
查看分支
# 查看所有本地分支
git branch
# 查看所有遠(yuǎn)程分支
git branch -r
# 查看本地和遠(yuǎn)程所有分支
git branch -a
切換分支
checkout 和 switch 的共同點(diǎn)是都能切換分支,不同點(diǎn)是:
switch語義上好點(diǎn)switch僅僅用于切換和創(chuàng)建并切換,checkout還能用來還原工作區(qū),后面進(jìn)階那有介紹
# 切換到 test 分支
git checkout test
# 新建 test 分支,并切換到 test 分支
git checkout -b test
# 切換到 test 分支
git switch test
# 新建 test 分支,并切換到 test 分支
git switch -c test
刪除分支
# 刪除本地 test 分支
git branch -d test
# 刪除遠(yuǎn)程主機(jī)的 master 分支
git push origin -d master
刪除分支后恢復(fù)
# 查看記錄,找到對應(yīng)的 hash
git reflog
# 創(chuàng)建test分支,并取對應(yīng)hash分支所有內(nèi)容,相當(dāng)于恢復(fù)了被刪除的分支
git checkout -b test hash
重命名分支
# 把本地的 master 分支重命名為 test
git branch -m master test
# 遠(yuǎn)程分支沒法直接重命名,只能刪了重建,主要分幾步
# 1. git push origin --delete test 刪除遠(yuǎn)程分支
# 2. git push origin newtest 上傳新的遠(yuǎn)程分支
# 3. 把修改后的本地分支關(guān)聯(lián)遠(yuǎn)程分支
git branch --set-upstream-to origin/newtest
合并分支
其實(shí)就是上面的 git merge。比如要把 test 分支合并到 master 分支,就:
# 先切換到 master 分支
git checkout master
# 拉一下,看有沒有更新
git pull
# 把 test 分支合進(jìn)來
git merge test
# 查看狀態(tài),看有沒有沖突的,有就打開 IDE 解決一下
git status
# 然后 add、commit、push 幾個(gè)命令來一輪就 ok 了
git commit 提交規(guī)范
git commit 提交規(guī)范指的就是 git commit -am 'xxxx' 里的 xxxx 的書寫規(guī)范,比如我在工作中開發(fā)了一個(gè)新功能提交的時(shí)候一般這么寫:
git commit -am 'feat: 添加掃碼登錄git commit -am 'feat(mobile):添加掃碼登錄,或者加個(gè)范圍說明是添加哪方面的功能
feat 就是添加新功能的時(shí)候用,更多說明如下:
feat:添加新功能fix:修復(fù)問題/BUGstyle:注意不是指CSS,而是修改了如空格、縮進(jìn)、逗號等代碼風(fēng)格相關(guān),且不影響運(yùn)行結(jié)果的perf:優(yōu)化相關(guān)的,比如功能優(yōu)化、性能提升、提升體驗(yàn)等refactor:代碼重構(gòu),沒有加新功能或者修復(fù) bugrevert:撤消編輯,回滾到上一個(gè)版本、撤銷上一次的 commit 之類的test:測試相關(guān),比如單元測試、集成測試等docs:修改文檔/注釋,比如 README、CHANGELOG、CONTRIBUTE 等chore:依賴更新/腳手架配置修改等,比如有改變構(gòu)建流程、或者增加依賴庫、工具之類的workflow:工作流程改進(jìn)ci:持續(xù)集成types:類型定義文件更改
到這里,基礎(chǔ)部分內(nèi)容就結(jié)束了
問個(gè)問題:git branch -M ac 是啥意思?不許翻上面
進(jìn)階操作
常用命令
Git 別名(alias)
命令難記?沒有關(guān)系
Git 并不會在你輸入部分命令時(shí)自動推斷出你想要的命令。 如果不想每次都輸入完整的 Git 命令,可以通過 git config 文件來輕松地為每一個(gè)命令設(shè)置一個(gè)別名。
// 配置全局 branch 命令別名為 b
git config --global alias.b branch
然后比如想創(chuàng)建一個(gè)名為 test 的本地分支,如下即可
git b test
在創(chuàng)建你認(rèn)為應(yīng)該存在的命令時(shí)這個(gè)技術(shù)會很有用。
檢出 git checkout/git restore
checkout命令用于從歷史提交(或者暫存區(qū)域)中拷貝文件到工作目錄,也可用于切換分支。
restore指令使得在工作空間但是不在暫存區(qū)的文件撤銷更改(內(nèi)容恢復(fù)到?jīng)]修改之前的狀態(tài))
# 四個(gè)都是:撤銷 test.js 從上次提交之后的所有修改
git checkout -- test.js
git checkout - test.js
git checkout test.js
git restore test.js
# 只把 test.js 還原成上一個(gè)版本的,HEAD^表示上一個(gè)版本,HEAD^^上上一個(gè)版本
git checkout HEAD^ - test.js
# 只把 test.js 重置到某個(gè)指定版本
git checkout commitID test.js
# 把 master 分支的 test.js 拿過來替換當(dāng)前分支的 test.js
git checkout master - test.js
# 都是撤銷上一次 commit 之后的所有文件的所有修改
git checkout -- *
git checkout -- .
git checkout .
git restore .
# 把暫存區(qū)的 test.js 重新放回工作區(qū),和下面的 git reset HEAD test.js 作用一樣
git restore --staged test.js
重置 git reset
git reset 通常用來把代碼重置到過去的某個(gè)版本,有五種模式(--mixed、--soft、--hard、--merge),注意看注釋有說明區(qū)別。
另外 git reset 比較暴力,要慎用,比如現(xiàn)在提交五次了,然后使用這個(gè)命令重置到第一次,那么第二三四五次提交記錄會全部沒了的,找不回來的,這種情況記得新建個(gè)分支來執(zhí)行這種操作就沒事了,或者使用 git revert
# 后面一長串就是我復(fù)制的 commitID 或者說是 hash,長得就是這樣子的
# 等同于 git reset commitID,因?yàn)?--mixed 是默認(rèn)模式,所以可以不寫
# 重置并撤銷 git commit 以及 git add,保留編輯器中所有修改
git reset --mixed afcfbcb940164de24cc4f8c866e1da3a18382e10
# 重置并撤銷 git commit,但不撤銷 git add,保留編輯器中所有修改
git reset --soft commitID
# 重置并撤銷 git commit 以及 git add,并且刪除編輯器中所有修改
git reset --hard commitID
# 取消某次合并
git reset --merge commitID
git reset --keep commitID
# 把暫存區(qū)所有文件退回到工作區(qū),相當(dāng)于撤銷 git add .
git reset HEAD
# 把暫存區(qū)的 test.js 重新放回工作區(qū),和 git restore --staged test.js 作用一樣
git reset HEAD test.js
# 重置到上一個(gè)版本
git reset --hard HEAD^
# 重置到上上一個(gè)版本,以此類推
git reset --hard HEAD^^
# 重置到指定版本
git reset --hard commitID
commitID 可以通過三種方法查看
- 執(zhí)行
git log命令能看到當(dāng)前分支本地所有提交記錄,上面每一條記錄都有對應(yīng)一個(gè)commitID - 去遠(yuǎn)程代碼倉庫查看歷史提交記錄,那里每一條提交記錄都有一個(gè)對應(yīng)的
commitID git tag查看標(biāo)簽列表,如果有的話,再git show 標(biāo)簽名查看標(biāo)簽詳情,里面也會有commitID
# 查看當(dāng)前分支所有提交記錄,詳細(xì)列表,一條記錄有幾行信息
git log
# 查看當(dāng)前分支所有提交記錄,簡要列表,一條記錄一行
git log --pretty=oneline
#
git log --oneline -n5
另外關(guān)于叫法本地倉庫一般說重置、還原、撤銷都行,遠(yuǎn)程倉庫一般叫回滾
還原 git revert
git revert 和 git reset 有點(diǎn)類似,只是比 reset 稍微溫柔一點(diǎn),沒那么暴力。git revert是用于“反做”某一個(gè)版本,以達(dá)到撤銷該版本的修改的目的。
上面介紹了假如現(xiàn)在是第五版,用 reset 在重置回第一版本的時(shí)候,二三四五版全都會沒了,而 revert 重置回第一版的時(shí)候,只是新增一條提交記錄“第六版”,代碼變成第一版的代碼,原本的一二三四五版記錄都會有
另外 revert 還要分兩種情況,一種是還原正常的 commit,也就是 git commit 提交的 commit,另一種是用 merge 合并的 commit,如下
# 第一種查看正常提交的 commit,如下
git show 68be9e548
commit 68be9e548dadbe7b9677874b705662a8f95efd21
# 第二種查看 merge 合并的 commit 如下,多了一行 Merge,后面指的是從哪兩個(gè) commit 合并過來的
git show 9c810c1db
commit 9c810c1dbf72627dbff10d621c2974b32ed6d929
Merge: 3f6acb587 68be9e548
# 撤銷正常提交的 commit
git revert commitID
# 撤銷 merge 的 commit 提交需要加參數(shù)來區(qū)分撤銷哪一個(gè)分支上的內(nèi)容
# 也就是指定上面 Merge: 3f6acb587 68be9e548,這兩個(gè) id 中的哪一個(gè)
# -m 接收一個(gè)參數(shù)是數(shù)字,取值 1 或 2,表示 Merge 的第一個(gè)還是第二個(gè) id
git revert -m 1 9c810c1db
# 刪除最后一次遠(yuǎn)程提交
git revert HEAD
git push origin master
git reset --hard HEAD^
git push origin master -f
# 還原某次提交
git revert commitID
挑揀 git cherry-pick
比如有兩個(gè)分支 master 和 test,在 test 上修改了,并且提交了 commit 之后,這時(shí)候想把這次的提交也給弄到 master 上,就可以復(fù)制 test 的 commitID,再換到 master 分支后執(zhí)行 git cherry-pick commitID 就可以了
what?這不就是 merge?
和 merge 不同的是:cherry-pick 合并的是某一次 commit 提交的文件,merge 合并的是整個(gè)分支。且 merge 會額外多一條 merge commit 的記錄,而 cherry-pick 不會。
而且 cherry-pick 更加靈活,在需要把某個(gè)/或多個(gè)分支中的 commit,合入其他分支的時(shí)候都可以用,示例如下
# 這樣就把其他分支的一個(gè) commit 合入當(dāng)前分支了
git cherry-pick commitID
# 如果需要把多個(gè) commit 合過來如下,這多個(gè) commitID 可以是來自不同分支的
git cherry-pick commitID1 commitID2 commitID3
變基 git rebase
git rebase 和 git merge 的區(qū)別
git merge 和 git rebase 都是可以合并分支,合并用法也是一樣,不同的一個(gè)是在 commit 記錄的處理上:
git merge會新建一條新的 commit,然后兩個(gè)分支以前的 commit 記錄都指向這個(gè)新 commit 記錄。這種方法會保留之前每個(gè)分支的 commit 歷史。git rebase會先找到兩個(gè)分支的第一個(gè)共同的 commit 祖先記錄,然后將提取當(dāng)前分支這之后的所有 commit 記錄,放到目標(biāo)分的最新提交后面。經(jīng)過這個(gè)合并后,兩個(gè)分支合并后的 commit 記錄就變?yōu)榱司€性的記錄了。
這么說可能不太好理解,看如下示例:
# 如下,需要把本地 test 分支合入 dev
# 為方便理解,字母表示commit記錄,數(shù)字表示提交時(shí)間順序,可以理解為1就是1點(diǎn)提交的
dev -> A1 -> B3 -> 這一行是遠(yuǎn)程 dev 分支的commit記錄,A1/B3是你同事提交的
↘ X2 -> Y4↗ 這一行是拉取了 dev 分支后在本地的 test 分支 commit 記錄
# 現(xiàn)在需要把你本地的分支合并到遠(yuǎn)程的分支去
# 用merge合并后,dev 分支看到的記錄是這樣的,M為merge記錄的commit
dev -> A1 -> X2 -> B3 -> Y4 -> M
# 用rebase合并后,dev 分支看到的記錄是這樣的,注意順序,且沒有合并記錄的commit
# 簡單說就是直接把 test 分支的所有新的 commit 拿出來直接拼到 dev 分支末尾,不管提交時(shí)間先后
dev -> A1 -> B3 -> X2 -> Y4
- 然后是解決沖突的問題上,merge 是解決一次沖突就行了,rebase 需要一次一次地解決,如上示例的記錄順序也能看出來
- 再就是
rebase可以合并多次 commit。比如本地分支提交了三個(gè) commit,但沒有 push 到遠(yuǎn)程,最后想提交到遠(yuǎn)程的時(shí)候,為了簡潔,我們希望把本地的三個(gè) commit 合并成一個(gè) commit 再提交到遠(yuǎn)程,遠(yuǎn)程只產(chǎn)生一條 commit 記錄,就可以用git rebase -i處理下先,這命令可以刪除指定記錄,或者合并多個(gè) commit,對 commit 消息編輯等
# 刪除某次提交,^表示 commitID 的前一次提交
git rebase -i 'commitID'^
# 修改多個(gè)提交信息
git rebase -i HEAD~3
貯藏 git stash
git stash 常用于把修改儲存起來,需要的時(shí)候再取出來。常用于:
- 切換分支并且需要保留修改的時(shí)候
- 切換分支并且需要把修改帶到新的分支的時(shí)候
# 把當(dāng)前分支的修改儲存起來,兩個(gè)一樣的
git stash
git stash save
# 存儲并添加備注,方便查找
git stash save '備注信息'
# 查看儲存列表
git stash list
# 取出儲存中最近一次的修改并刪除儲存記錄
git stash pop
# 取出儲存中的指定部分修改,stash@{0} 0是默認(rèn)的不寫也行,是啥只要查看儲存列表你就知道了
git stash apply stash@{0}
# 刪除指定儲存
git stash drop stash@{1}
# 刪除所有的儲存
git stash clear
# 創(chuàng)建一個(gè)新分支 test,并恢復(fù)儲存工作時(shí)所在的提交到該分支上,并扔掉儲藏
git stash branch test stash@{1}
# 不儲存暫存區(qū)的,也就是 git add 了的
git stash --keep-index
清理 git clean
和 git reset 的區(qū)別是:reset 刪除的是己跟蹤的文件,并且將已 commit 的回退。clean 刪除的是未跟蹤的文件/目錄
# 顯示如果執(zhí)行后面刪除的命令將會刪除的文件和目錄,相當(dāng)于給提前給我們確認(rèn)下
git clean -n
# 刪除工作目錄中所有沒被追蹤的文件(-f)以及空的子目錄(-d),一起就是 -df
git clean -df
差異 git diff
用來找出倉庫或者文件之間的差異,可以用來預(yù)測或者阻止可能產(chǎn)生沖突的合并
# 工作區(qū) vs 暫存區(qū)
git diff
# 工作區(qū) vs 版本庫
git diff head
# 暫存區(qū) vs 版本庫
git diff –cached
有多種方法查看兩次提交之間的變動,如下面是一些示例。

問題預(yù)防
- 不要對已經(jīng)提交到遠(yuǎn)程倉庫的 commit 進(jìn)行 rebase 變基操作,除非是你一個(gè)人玩的分支
- 在切換分支,或者合并分支,或者重置/回滾之前,最好不要有未
commit的文件,如果有并且不想提交就用git stash先存起來,再執(zhí)行操作,如果用命令操作的話,取出之后記得清理 - 遠(yuǎn)程倉庫回滾前記得做好備份,比如拉一個(gè)分支在本地。并且需要通知團(tuán)隊(duì)其他成員,不要悄摸摸地就搞了
解決問題
切換分支保留修改
有時(shí)候比如我們在 test 分支上開發(fā)了一半,由于某些原因需要切換到 master 分支,但現(xiàn)在又不想提交,又想保留修改并且不帶到 master 分支上去,就可以這樣:
# 把當(dāng)前分支的修改儲存起來
git stash
# 切換到其他分支干你的事
git checkout master
# 干完了
# 切換回 test 分支
git checkout test
# 取出儲存中所有的修改
git stash pop
# 刪除所有的儲存
git stash clear
切換分支轉(zhuǎn)移修改
有的時(shí)候我們需要在 test 分支上開發(fā),但是忘記了,活快干完了才發(fā)現(xiàn)當(dāng)前原來是 master 分支,可是已經(jīng)開發(fā)了,這時(shí)候就需要切換分支到 test,并且把已經(jīng)開發(fā)的部分內(nèi)容也從 master 分支帶到 test 分支來,就可以這樣:
# 儲存修改
git stash
# 切換到 test 分支
git checkout test
# 取出儲存中的全部修改
git stash pop
# 或者
# 查看儲存列表
git stash list
# 取出儲存中的指定部分修改,stash@{0} 是啥只要查看儲存列表你就知道了
git stash apply stash@{0}
# 再清掉儲存
git stash clear
合并時(shí)發(fā)生沖突用 git merge abort 或 git reset --merge 都可以取消合并
比如把不想要的代碼 commit 了,但是沒有 push 比如剛更新的代碼出問題了,需要還原這次提交的代碼 比如某次提交了不想提交的東西,需要清除掉它
revert 之后重新上線 diff 丟失
- 比如在 dev 分到開發(fā)了個(gè)功能,提交后會產(chǎn)生一條 commit 記錄,為了方便理解,我們先把這次提交標(biāo)記為 a
- 然后合并到 master 后,我們把這次合并記錄標(biāo)記為 b
- 結(jié)果出現(xiàn)了 bug 需要撤銷合并,使用 revert b 撤銷了,這會產(chǎn)生了一條新的記錄 我們標(biāo)記為 c
- 然后繼續(xù)在 dev 分支開發(fā)完成提交,提交記錄標(biāo)記為 d
- 這時(shí)候再合并到 master 上去,此時(shí)合并后的內(nèi)容不會包含 a 的提交,因?yàn)?a 被 revert 丟棄過,不會參與 diff,如果需要包含 a,需要先 revert c 意思是撤銷某一次的撤銷,再來合并,就 ok 了
合并沖突不想合并了
合并時(shí)、或者拉取時(shí)等,發(fā)現(xiàn)有沖突,可能是其他同事提交的,自己不知道怎么沖突怎么選擇,或者其他原因,總之不想合并了,都可以用 --abort 取消,比如合并的時(shí)候發(fā)現(xiàn)有沖突不想合并了
git merge --abort 取消合并即可
解決沖突
有的時(shí)候合并分支沖突是由于本地主分支沒有更新導(dǎo)致,或者有時(shí) git pull 的時(shí)候沖突,只需要掉本地主分支,再重新拉一下遠(yuǎn)程分支就好了。
有的時(shí)候沖突就只能解決沖突,使用 git status 看由于沖突導(dǎo)致沒有合并成功的文件是哪些,然后去編輯器打開沖突的文件即可,也可用 cat <文件路徑> 查看指定文件里沖突的部分,直接去編輯器改
或者就是用命令,比如把 test 分支,合入 master 分支時(shí)產(chǎn)生沖突。
# 只保留 test 的修改
git checkout --theirs test.js
# 只保留 master 的修改
git checkout --ours test.js
# 都保留
git checkout --ours/theirs test.js
# 查看沖突,都行
git diff --theirs
git diff --ours
# 這個(gè) --theirs 和 --ours 是啥?比如沖突的時(shí)候是這樣的
# <<<<<<<<< HEAD
# console.log('master') // 這個(gè)就是 --ours
# =========
# console.log('test') // 這個(gè)就是 --theirs
# >>>>>>>>> test
Git與SVN的最主要的區(qū)別?
Git是分布式版本控制系統(tǒng),那么它就沒有中央服務(wù)器的,每個(gè)人的電腦就是一個(gè)完整的版本庫,這樣,工作的時(shí)候就不需要聯(lián)網(wǎng)了,因?yàn)榘姹径际窃谧约旱碾娔X 上。既然每個(gè)人的電腦都有一個(gè)完整的版本庫,那多個(gè)人如何協(xié)作呢?比如說自己在電腦上改了文件A,其他人也在電腦上改了文件A,這時(shí),你們兩之間只需把各 自的修改推送給對方,就可以互相看到對方的修改了。
SVN是集中式版本控制系統(tǒng),版本庫是集中放在中央服務(wù)器的,而干活的時(shí)候,用的都是自己的電腦,所以首先要從中央服務(wù)器哪里得到最新的版本,然后干活, 干完后,需要把自己做完的活推送到中央服務(wù)器。集中式版本控制系統(tǒng)是必須聯(lián)網(wǎng)才能工作,如果在局域網(wǎng)還可以,帶寬夠大,速度夠快,如果在互聯(lián)網(wǎng)下,如果網(wǎng) 速慢的話,就納悶了。
參考資料:
圖解GIT: http://marklodato.github.io/visual-git-guide/index-zh-cn.html
Git官方:https://git-scm.com/
Git參考手冊:https://git-scm.com/docs
結(jié)語
如果本文對你有一點(diǎn)點(diǎn)幫助,點(diǎn)個(gè)贊支持一下吧,你的每一個(gè)【贊】都是我創(chuàng)作的最大動力 _
更多干貨技術(shù)文章可前往:http://www.guosisoft.com/article,大家一起共同交流和進(jìn)步呀!
前往了解國思RDIF低代碼開發(fā)平臺:http://www.guosisoft.com

作者:
RDIF
出處:
http://www.rzrgm.cn/huyong/
Email:
406590790@qq.com
QQ:
406590790
微信:
13005007127(同手機(jī)號)
框架官網(wǎng):
http://www.guosisoft.com/
http://www.rdiframework.net/
框架其他博客:
http://blog.csdn.net/chinahuyong
http://www.rzrgm.cn/huyong
國思RDIF開發(fā)框架
,
給用戶和開發(fā)者最佳的.Net框架平臺方案,為企業(yè)快速構(gòu)建跨平臺、企業(yè)級的應(yīng)用提供強(qiáng)大支持。
關(guān)于作者:系統(tǒng)架構(gòu)師、信息系統(tǒng)項(xiàng)目管理師、DBA。專注于微軟平臺項(xiàng)目架構(gòu)、管理和企業(yè)解決方案,多年項(xiàng)目開發(fā)與管理經(jīng)驗(yàn),曾多次組織并開發(fā)多個(gè)大型項(xiàng)目,在面向?qū)ο蟆⒚嫦蚍?wù)以及數(shù)據(jù)庫領(lǐng)域有一定的造詣。現(xiàn)主要從事基于
RDIF
框架的技術(shù)開發(fā)、咨詢工作,主要服務(wù)于金融、醫(yī)療衛(wèi)生、鐵路、電信、物流、物聯(lián)網(wǎng)、制造、零售等行業(yè)。
如有問題或建議,請多多賜教!
本文版權(quán)歸作者和CNBLOGS博客共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,如有問題,可以通過微信、郵箱、QQ等聯(lián)系我,非常感謝。

本文將從 Git 入門到進(jìn)階、由淺入深,從常用命令、分支管理、提交規(guī)范、vim 基本操作、進(jìn)階命令、沖突預(yù)防、沖突處理等多方面展開,足以輕松應(yīng)對工作中遇到的各種疑難雜癥,如果覺得有所幫助,還望看官高抬貴手給個(gè)贊唄,感謝!
雖說現(xiàn)在工作中使用 Git 都會用一些圖形化管理工具來提高開發(fā)效率。可事實(shí)上使用圖形管理化工具的前提,也是基于對命令都基本了解。還有比如我平時(shí)用的工具 `Github Desktop` 因?yàn)椴粠У谌胶喜⒐ぞ撸荒苁謩咏鉀Q沖突,而且有的功能沒有,只能配合自己手動敲命令。
浙公網(wǎng)安備 33010602011771號