本文將從 Git 入門到進(jìn)階、由淺入深,從常用命令、分支管理、提交規(guī)范、vim 基本操作、進(jìn)階命令、沖突預(yù)防、沖突處理等多方面展開,足以輕松應(yīng)對工作中遇到的各種疑難雜癥,如果覺得有所幫助,還望看官高抬貴手給個贊唄,感謝!
雖說現(xiàn)在工作中使用 Git 都會用一些圖形化管理工具來提高開發(fā)效率??墒聦嵣鲜褂脠D形管理化工具的前提,也是基于對命令都基本了解。還有比如我平時用的工具 Github Desktop
因為不帶第三方合并工具,只能手動解決沖突,而且有的功能沒有,只能配合自己手動敲命令。
即使是工具也沒有那么完美的工具,掌握命令才是漁
,工具只是魚
。其他的 Git 可視化管理工具比如:小烏龜、SourceTree、還有我們開發(fā)用的 IDE 集成的,本篇不過多介紹。
基本概念
Git 是一個開源的分布式版本控制系統(tǒng),用以有效、高速的處理從很小到非常大的項目版本管理。
Git 的作用與好處是:
可以幫我們保存文件的所有修改記錄,并且使用版本號進(jìn)行區(qū)分,讓我們隨時可以瀏覽歷史版本、對比不同版本的差異、還原到指定版本,起到恢復(fù)和保護(hù)作用的同時,還能和其他人同時修改,然后通過 Git 來合并修改的部分文件,超級方便。主要有以下特點:
- 分支更快、更容易。
- 支持離線工作;本地提交可以稍后提交到服務(wù)器上。
- Git 提交都是原子的,且是整個項目范圍的,而不像 CVS 中一樣是對每個文件的。
- Git 中的每個工作樹都包含一個具有完整項目歷史的倉庫。
- 沒有哪一個 Git 倉庫會天生比其他倉庫更重要。
不熟的同學(xué)別和 Github 搞混了,Git 是工具,Github 是平臺,沒有什么必然的聯(lián)系,就像 Java 和 JavaScript 也沒有什么必然聯(lián)系一樣
Github 是一個主流的代碼托管平臺??梢岳斫鉃榇娣藕凸芾泶a的網(wǎng)盤,可以把自己的代碼傳上去進(jìn)行共享和維護(hù)。
安裝配置
安裝地址:Git - Downloads (git-scm.com)
安裝好后,命令行窗口是使用 Git Bash
、CMD
、Powershell
、終端
、或者編譯器內(nèi)置的都行,這個就看個人喜好。
接著可以再配置下默認(rèn)用戶名和郵箱,比如配置全局的就用如下兩條命令,替換成自己的用戶名和郵箱,以后所有的項目都會默認(rèn)這里配置的用戶信息
git config --global user.name 'xxxx'
git config --global user.email 'xxxx@xx.com'
如果只需要在某個特定的項目中用其他的名字和郵箱,不用全局的,就把上面命令中的 --global
去掉在項目下執(zhí)行即可,或者不執(zhí)行命令,直接在項目下的 .git/config
文件里添加如下,也可以
# xxx 指的是填你自己的用戶名和郵箱,不是真的寫 xxxx 上去
[user]
name = xxxx
email = xxxx@xx.com
基本操作
先了解一下幾個基本概念:
- 工作區(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)程倉庫
常見選項
再認(rèn)識一下幾個后面會用到多次的命令。
命令 | 縮寫 | 意思 |
---|---|---|
--all | -a | 全部 |
--force | -f | 強制 |
--delete | -d | 刪除 |
--delete --force | -D | 強制刪除 |
--move | -m | 移動或重命名 |
--move --force | -M | 強制移動或重命名 |
-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)于運行git add
把所有當(dāng)前目錄下的文件加入暫存區(qū)域再運行。git commit
. -
git commit files
進(jìn)行一次包含最后一次提交加上工作目錄中文件快照的提交。并且文件被添加到暫存區(qū)域。 -
git checkout HEAD -- files
回滾到復(fù)制最后一次提交。
拉取遠(yuǎn)程項目
拉取遠(yuǎn)程項目到本地,先復(fù)制遠(yuǎn)程項目鏈接,再在本地執(zhí)行如下命令
# 拉項目
git clone https://xxxx
# 拉項目的同時自動初始化并更新項目中的每一個子模塊
git clone --recursive https://xxxx
上傳本地項目
本地新建的項目,還沒有提交到遠(yuǎn)程倉庫,就需要先關(guān)聯(lián)遠(yuǎn)程倉庫。先在遠(yuǎn)程創(chuàng)建一個空項目,并復(fù)制該項目的鏈接,然后在本地項目根目錄依次執(zhí)行下面命令即可
git init // 初始化本地 Git 倉庫,會生成一個 .git 隱藏文件夾
git remote add origin https://xxxx // 將本地項目關(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)程倉庫的
由此可得出一個結(jié)論,就是一個項目可以關(guān)聯(lián)多個遠(yuǎn)程倉庫,命不同的名就行了
沒錯
git remote -v
可以快速查看當(dāng)前已經(jīng)關(guān)聯(lián)的遠(yuǎn)程倉庫列表
關(guān)聯(lián)多個遠(yuǎn)程倉庫
可以使用 git remote add xxx
添加多個,或者直接動在 .git/config
文件里添加。
比如一個項目同時關(guān)聯(lián)一個 Github
倉庫和一個 Gitee
倉庫,添加一個 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)我們提交代碼的時候,想提交到 Github
就用 git push github master
,想同時提交到 Github
和 Gitee
的倉庫,只需要 git push all master
即可
以命令的方法在某個 remote
下添加 url
如下,比如在上面 remote github
下再添加一個 url
:
git remote set-url --add github https:/xxxx.git
常用命令 add/commit/fetch/merge/pull/push
git add
# 添加一個文件 test.js 到暫存區(qū),多個文件以空格隔開
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'
# 用本地提交替換上次提交,比如不想保留上一次提交或者上一次提交描述信息寫錯了之類的
git commit --amend
git fetch
# 獲取 remote origin 對應(yīng)遠(yuǎn)程倉庫指定 master 分支的變更,但是不和本地的合并
git fetch origin master
# 意思一個樣,拉默認(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簡寫,合并并且會在分支上重新生成一個新的 commit 節(jié)點
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
# 強制推送,就算本地和遠(yuǎn)程有差異也推上去
git push -f origin master
# 刪除遠(yuǎn)程主機的 master 分支
git push origin -d master
vim 基本操作
一點點小插曲
比如 git commit
就會打開一個 vim
的終端編輯器,讓我們寫提交說明,新手很容易在這個編輯器上面踩坑,不知道怎么輸入,不知道怎么退出,最后只能關(guān)閉終端窗口,這也沒辦法,vim
的操作確實有些反人類。
vim
打開默認(rèn)是不能輸入的,要按 a
或者 i
進(jìn)入編輯模式,輸入完成后,再按 Esc
退出編輯模式,這時左下角會有輸入框,輸入如下英文字符,注意冒號別打成中文字符,回車即可退出 vim
回到終端:
-
:w
:保存 -
:q
:退出 -
:wq
:保存并退出 -
!
:強制的意思,不能保存時:w!
強制保存,不能退出時:q!
或:wq!
強制退出
我們繼續(xù) git
分支管理 branch/switch/checkout
一個人玩,可能分支的作用沒那么大,但是團(tuán)隊協(xié)作,離不開分支管理。
比如本文開頭圖片那樣一個版本一個分支多方便,是吧
或者現(xiàn)有一個新需求一個頁面分為多個模塊,分配給多個人負(fù)責(zé),每人做一個模塊,最后合并成一個完整的頁面,如果都在同一個分支上開發(fā),各種邏輯相互穿插,那沖突真的是人都要搞麻了,如果每個人都新建一個分支,開發(fā)自己負(fù)責(zé)的那個功能,最后再合并到同一個分支上去就非常方便了
然后因為多人協(xié)作肯定不是在一臺電腦上,所以就需要一個服務(wù)器,來搭建一個 Git 倉庫服務(wù),或者用公共的云服務(wù)器倉庫存儲,常見的代碼托管平臺有比如:Github
、碼云(Gitee)
、騰訊工蜂
、GitLab
、Bitbucket
...,關(guān)于這個本篇文章不過多展開。
創(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
的共同點是都能切換分支,不同點是:
-
switch
語義上好點 -
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)程主機的 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
合并分支
其實就是上面的 git merge
。比如要把 test
分支合并到 master
分支,就:
# 先切換到 master 分支
git checkout master
# 拉一下,看有沒有更新
git pull
# 把 test 分支合進(jìn)來
git merge test
# 查看狀態(tài),看有沒有沖突的,有就打開 IDE 解決一下
git status
# 然后 add、commit、push 幾個命令來一輪就 ok 了
git commit 提交規(guī)范
git commit
提交規(guī)范指的就是 git commit -am 'xxxx'
里的 xxxx
的書寫規(guī)范,比如我在工作中開發(fā)了一個新功能提交的時候一般這么寫:
git commit -am 'feat: 添加掃碼登錄
-
git commit -am 'feat(mobile):添加掃碼登錄
,或者加個范圍說明是添加哪方面的功能
feat
就是添加新功能的時候用,更多說明如下:
-
feat
:添加新功能 -
fix
:修復(fù)問題/BUG -
style
:注意不是指CSS,而是修改了如空格、縮進(jìn)、逗號等代碼風(fēng)格相關(guān),且不影響運行結(jié)果的 -
perf
:優(yōu)化相關(guān)的,比如功能優(yōu)化、性能提升、提升體驗等 -
refactor
:代碼重構(gòu),沒有加新功能或者修復(fù) bug -
revert
:撤消編輯,回滾到上一個版本、撤銷上一次的 commit 之類的 -
test
:測試相關(guān),比如單元測試、集成測試等 -
docs
:修改文檔/注釋,比如 README、CHANGELOG、CONTRIBUTE 等 -
chore
:依賴更新/腳手架配置修改等,比如有改變構(gòu)建流程、或者增加依賴庫、工具之類的 -
workflow
:工作流程改進(jìn) -
ci
:持續(xù)集成 -
types
:類型定義文件更改
到這里,基礎(chǔ)部分內(nèi)容就結(jié)束了
問個問題:git branch -M ac
是啥意思?不許翻上面
進(jìn)階操作
常用命令
Git 別名(alias)
命令難記?沒有關(guān)系
Git
并不會在你輸入部分命令時自動推斷出你想要的命令。 如果不想每次都輸入完整的 Git
命令,可以通過 git config
文件來輕松地為每一個命令設(shè)置一個別名。
// 配置全局 branch 命令別名為 b
git config --global alias.b branch
然后比如想創(chuàng)建一個名為 test
的本地分支,如下即可
git b test
在創(chuàng)建你認(rèn)為應(yīng)該存在的命令時這個技術(shù)會很有用。
檢出 git checkout/git restore
checkout命令用于從歷史提交(或者暫存區(qū)域)中拷貝文件到工作目錄,也可用于切換分支。
restore指令使得在工作空間但是不在暫存區(qū)的文件撤銷更改(內(nèi)容恢復(fù)到?jīng)]修改之前的狀態(tài))
# 四個都是:撤銷 test.js 從上次提交之后的所有修改
git checkout -- test.js
git checkout - test.js
git checkout test.js
git restore test.js
# 只把 test.js 還原成上一個版本的,HEAD^表示上一個版本,HEAD^^上上一個版本
git checkout HEAD^ - test.js
# 只把 test.js 重置到某個指定版本
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
通常用來把代碼重置到過去的某個版本,有五種模式(--mixed
、--soft
、--hard
、--merge
),注意看注釋有說明區(qū)別。
另外 git reset
比較暴力,要慎用,比如現(xiàn)在提交五次了,然后使用這個命令重置到第一次,那么第二三四五次提交記錄會全部沒了的,找不回來的,這種情況記得新建個分支來執(zhí)行這種操作就沒事了,或者使用 git revert
# 后面一長串就是我復(fù)制的 commitID 或者說是 hash,長得就是這樣子的
# 等同于 git reset commitID,因為 --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
# 重置到上一個版本
git reset --hard HEAD^
# 重置到上上一個版本,以此類推
git reset --hard HEAD^^
# 重置到指定版本
git reset --hard commitID
commitID
可以通過三種方法查看
- 執(zhí)行
git log
命令能看到當(dāng)前分支本地所有提交記錄,上面每一條記錄都有對應(yīng)一個commitID
- 去遠(yuǎn)程代碼倉庫查看歷史提交記錄,那里每一條提交記錄都有一個對應(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
有點類似,只是比 reset
稍微溫柔一點,沒那么暴力。git revert是用于“反做”某一個版本,以達(dá)到撤銷該版本的修改的目的。
上面介紹了假如現(xiàn)在是第五版,用 reset
在重置回第一版本的時候,二三四五版全都會沒了,而 revert
重置回第一版的時候,只是新增一條提交記錄“第六版”,代碼變成第一版的代碼,原本的一二三四五版記錄都會有
另外 revert 還要分兩種情況,一種是還原正常的 commit,也就是 git commit 提交的 commit,另一種是用 merge 合并的 commit,如下
# 第一種查看正常提交的 commit,如下
git show 68be9e548
commit 68be9e548dadbe7b9677874b705662a8f95efd21
# 第二種查看 merge 合并的 commit 如下,多了一行 Merge,后面指的是從哪兩個 commit 合并過來的
git show 9c810c1db
commit 9c810c1dbf72627dbff10d621c2974b32ed6d929
Merge: 3f6acb587 68be9e548
# 撤銷正常提交的 commit
git revert commitID
# 撤銷 merge 的 commit 提交需要加參數(shù)來區(qū)分撤銷哪一個分支上的內(nèi)容
# 也就是指定上面 Merge: 3f6acb587 68be9e548,這兩個 id 中的哪一個
# -m 接收一個參數(shù)是數(shù)字,取值 1 或 2,表示 Merge 的第一個還是第二個 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
比如有兩個分支 master 和 test,在 test 上修改了,并且提交了 commit 之后,這時候想把這次的提交也給弄到 master 上,就可以復(fù)制 test 的 commitID,再換到 master 分支后執(zhí)行 git cherry-pick commitID
就可以了
what?這不就是 merge?
和 merge 不同的是:cherry-pick
合并的是某一次 commit
提交的文件,merge
合并的是整個分支。且 merge
會額外多一條 merge commit
的記錄,而 cherry-pick
不會。
而且 cherry-pick
更加靈活,在需要把某個/或多個分支中的 commit,合入其他分支的時候都可以用,示例如下
# 這樣就把其他分支的一個 commit 合入當(dāng)前分支了
git cherry-pick commitID
# 如果需要把多個 commit 合過來如下,這多個 commitID 可以是來自不同分支的
git cherry-pick commitID1 commitID2 commitID3
變基 git rebase
git rebase
和 git merge
的區(qū)別
git merge 和 git rebase 都是可以合并分支,合并用法也是一樣,不同的一個是在 commit 記錄的處理上:
-
git merge
會新建一條新的 commit,然后兩個分支以前的 commit 記錄都指向這個新 commit 記錄。這種方法會保留之前每個分支的 commit 歷史。 -
git rebase
會先找到兩個分支的第一個共同的 commit 祖先記錄,然后將提取當(dāng)前分支這之后的所有 commit 記錄,放到目標(biāo)分的最新提交后面。經(jīng)過這個合并后,兩個分支合并后的 commit 記錄就變?yōu)榱司€性的記錄了。
這么說可能不太好理解,看如下示例:
# 如下,需要把本地 test 分支合入 dev
# 為方便理解,字母表示commit記錄,數(shù)字表示提交時間順序,可以理解為1就是1點提交的
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 分支末尾,不管提交時間先后
dev -> A1 -> B3 -> X2 -> Y4
- 然后是解決沖突的問題上,merge 是解決一次沖突就行了,rebase 需要一次一次地解決,如上示例的記錄順序也能看出來
- 再就是
rebase
可以合并多次 commit。比如本地分支提交了三個 commit,但沒有 push 到遠(yuǎn)程,最后想提交到遠(yuǎn)程的時候,為了簡潔,我們希望把本地的三個 commit 合并成一個 commit 再提交到遠(yuǎn)程,遠(yuǎn)程只產(chǎn)生一條 commit 記錄,就可以用git rebase -i
處理下先,這命令可以刪除指定記錄,或者合并多個 commit,對 commit 消息編輯等
# 刪除某次提交,^表示 commitID 的前一次提交
git rebase -i 'commitID'^
# 修改多個提交信息
git rebase -i HEAD~3
貯藏 git stash
git stash
常用于把修改儲存起來,需要的時候再取出來。常用于:
- 切換分支并且需要保留修改的時候
- 切換分支并且需要把修改帶到新的分支的時候
# 把當(dāng)前分支的修改儲存起來,兩個一樣的
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)建一個新分支 test,并恢復(fù)儲存工作時所在的提交到該分支上,并扔掉儲藏
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 變基操作,除非是你一個人玩的分支
- 在切換分支,或者合并分支,或者重置/回滾之前,最好不要有未
commit
的文件,如果有并且不想提交就用git stash
先存起來,再執(zhí)行操作,如果用命令操作的話,取出之后記得清理 - 遠(yuǎn)程倉庫回滾前記得做好備份,比如拉一個分支在本地。并且需要通知團(tuán)隊其他成員,不要悄摸摸地就搞了
解決問題
切換分支保留修改
有時候比如我們在 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)移修改
有的時候我們需要在 test 分支上開發(fā),但是忘記了,活快干完了才發(fā)現(xiàn)當(dāng)前原來是 master 分支,可是已經(jīng)開發(fā)了,這時候就需要切換分支到 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
合并時發(fā)生沖突用 git merge abort
或 git reset --merge
都可以取消合并
比如把不想要的代碼 commit 了,但是沒有 push 比如剛更新的代碼出問題了,需要還原這次提交的代碼 比如某次提交了不想提交的東西,需要清除掉它
revert 之后重新上線 diff 丟失
- 比如在 dev 分到開發(fā)了個功能,提交后會產(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
- 這時候再合并到 master 上去,此時合并后的內(nèi)容不會包含 a 的提交,因為 a 被 revert 丟棄過,不會參與 diff,如果需要包含 a,需要先 revert c 意思是撤銷某一次的撤銷,再來合并,就 ok 了
合并沖突不想合并了
合并時、或者拉取時等,發(fā)現(xiàn)有沖突,可能是其他同事提交的,自己不知道怎么沖突怎么選擇,或者其他原因,總之不想合并了,都可以用 --abort
取消,比如合并的時候發(fā)現(xiàn)有沖突不想合并了
git merge --abort
取消合并即可
解決沖突
有的時候合并分支沖突是由于本地主分支沒有更新導(dǎo)致,或者有時 git pull
的時候沖突,只需要掉本地主分支,再重新拉一下遠(yuǎn)程分支就好了。
有的時候沖突就只能解決沖突,使用 git status
看由于沖突導(dǎo)致沒有合并成功的文件是哪些,然后去編輯器打開沖突的文件即可,也可用 cat <文件路徑>
查看指定文件里沖突的部分,直接去編輯器改
或者就是用命令,比如把 test 分支,合入 master 分支時產(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
# 這個 --theirs 和 --ours 是啥?比如沖突的時候是這樣的
# <<<<<<<<< HEAD
# console.log('master') // 這個就是 --ours
# =========
# console.log('test') // 這個就是 --theirs
# >>>>>>>>> test
Git與SVN的最主要的區(qū)別?
Git是分布式版本控制系統(tǒng),那么它就沒有中央服務(wù)器的,每個人的電腦就是一個完整的版本庫,這樣,工作的時候就不需要聯(lián)網(wǎng)了,因為版本都是在自己的電腦 上。既然每個人的電腦都有一個完整的版本庫,那多個人如何協(xié)作呢?比如說自己在電腦上改了文件A,其他人也在電腦上改了文件A,這時,你們兩之間只需把各 自的修改推送給對方,就可以互相看到對方的修改了。
SVN是集中式版本控制系統(tǒng),版本庫是集中放在中央服務(wù)器的,而干活的時候,用的都是自己的電腦,所以首先要從中央服務(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é)語
如果本文對你有一點點幫助,點個贊支持一下吧,你的每一個【贊】都是我創(chuàng)作的最大動力 _
更多干貨技術(shù)文章可前往:http://www.guosisoft.com/article,大家一起共同交流和進(jìn)步呀!文章來源:http://www.zghlxwxcb.cn/news/detail-424668.html
前往了解國思RDIF低代碼開發(fā)平臺:http://www.guosisoft.com文章來源地址http://www.zghlxwxcb.cn/news/detail-424668.html
到了這里,關(guān)于干貨|工作中要使用Git,看這篇文章就夠了的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!