乾貨|工作中要使用Git,看這篇文章就夠了

2023-04-25 12:01:07

本文將從 Git 入門到進階、由淺入深,從常用命令、分支管理、提交規範、vim 基本操作、進階命令、衝突預防、衝突處理等多方面展開,足以輕鬆應對工作中遇到的各種疑難雜症,如果覺得有所幫助,還望看官高擡貴手給個讚唄,感謝!

雖說現在工作中使用 Git 都會用一些圖形化管理工具來提高開發效率。可事實上使用圖形管理化工具的前提,也是基於對命令都基本瞭解。還有比如我平時用的工具 Github Desktop 因為不帶第三方合併工具,只能手動解決衝突,而且有的功能沒有,只能配合自己手動敲命令。

即使是工具也沒有那麼完美的工具,掌握命令才是,工具只是。其他的 Git 視覺化管理工具比如:小烏龜、SourceTree、還有我們開發用的 IDE 整合的,本篇不過多介紹。

基本概念

Git 是一個開源的分散式版本控制系統,用以有效、高速的處理從很小到非常大的專案版本管理。

Git 的作用與好處是:

可以幫我們儲存檔案的所有修改記錄,並且使用版本號進行區分,讓我們隨時可以瀏覽歷史版本、對比不同版本的差異、還原到指定版本,起到恢復和保護作用的同時,還能和其他人同時修改,然後通過 Git 來合併修改的部分檔案,超級方便。主要有以下特點:

  • 分支更快、更容易。
  • 支援離線工作;本地提交可以稍後提交到伺服器上。
  • Git 提交都是原子的,且是整個專案範圍的,而不像 CVS 中一樣是對每個檔案的。
  • Git 中的每個工作樹都包含一個具有完整專案歷史的倉庫。
  • 沒有哪一個 Git 倉庫會天生比其他倉庫更重要。

不熟的同學別和 Github 搞混了,Git 是工具,Github 是平臺,沒有什麼必然的聯絡,就像 Java 和 JavaScript 也沒有什麼必然聯絡一樣

Github 是一個主流的程式碼託管平臺。可以理解為存放和管理程式碼的網路硬碟,可以把自己的程式碼傳上去進行共用和維護。

安裝設定

安裝地址:Git - Downloads (git-scm.com)

安裝好後,命令列視窗是使用 Git BashCMDPowershell終端、或者編譯器內建的都行,這個就看個人喜好。

接著可以再設定下預設使用者名稱和郵箱,比如設定全域性的就用如下兩條命令,替換成自己的使用者名稱和郵箱,以後所有的專案都會預設這裡設定的使用者資訊

git config --global user.name 'xxxx'
git config --global user.email '[email protected]'

如果只需要在某個特定的專案中用其他的名字和郵箱,不用全域性的,就把上面命令中的 --global 去掉在專案下執行即可,或者不執行命令,直接在專案下的 .git/config 檔案裡新增如下,也可以

# xxx 指的是填你自己的使用者名稱和郵箱,不是真的寫 xxxx 上去
[user]
    name = xxxx
    email = [email protected]

基本操作

先了解一下幾個基本概念:

  • 工作區:開發的地方,開發過程就是對工作區的操作
  • 暫存區:執行 git add xxx 命令後,會把當前修改過的檔案新增到暫存區
  • 本地倉庫:執行 git commit 命令完成後,會把當前暫存區的檔案放入本地倉庫
  • 遠端倉庫:就是用來受控程式碼的伺服器(如:Github、Gitee、GitLab、工蜂、Bitbucket..),執行 git push 命令後,會把本地倉庫的檔案提交到遠端倉庫

常見選項

再認識一下幾個後面會用到多次的命令。

命令 縮寫 意思
--all -a 全部
--force -f 強制
--delete -d 刪除
--delete --force -D 強制刪除
--move -m 移動或重新命名
--move --force -M 強制移動或重新命名
-u 設定預設遠端分支

基本用法

上面的四條命令在工作目錄、暫存目錄(也叫做索引)和倉庫之間複製檔案。

  • git add *files* 把當前檔案放入暫存區域。
  • git commit 給暫存區域生成快照並提交。
  • git reset -- *files* 用來複原最後一次git add *files*,你也可以用git reset 復原所有暫存區域檔案。
  • git checkout -- *files* 把檔案從暫存區域複製到工作目錄,用來丟棄本地修改。

你可以用 git reset -p, git checkout -p, or git add -p進入互動模式。

也可以跳過暫存區域直接從倉庫取出檔案或者直接提交程式碼。

  • git commit -a 相當於執行 git add 把所有當前目錄下的檔案加入暫存區域再執行。git commit.
  • git commit files 進行一次包含最後一次提交加上工作目錄中檔案快照的提交。並且檔案被新增到暫存區域。
  • git checkout HEAD -- files 回滾到複製最後一次提交。

拉取遠端專案

拉取遠端專案到本地,先複製遠端專案連結,再在本地執行如下命令

# 拉專案
git clone https://xxxx
# 拉專案的同時自動初始化並更新專案中的每一個子模組
git clone --recursive https://xxxx

上傳本地專案

本地新建的專案,還沒有提交到遠端倉庫,就需要先關聯遠端倉庫。先在遠端建立一個空專案,並複製該專案的連結,然後在本地專案根目錄依次執行下面命令即可

git init                             // 初始化本地 Git 倉庫,會生成一個 .git 隱藏資料夾
git remote add origin https://xxxx   // 將本地專案關聯遠端倉庫,後面的 https://xxxx 就是複製的遠端倉庫的連結
git pull --rebase origin master      // 上傳之前更新一下,確保沒有衝突,master 為分支名稱,--rebase 後面有介紹
git add .                            // 新增目錄下所有發生改變的檔案
git commit -m 'xxx'                  // 新增註釋資訊
git push -u origin master            // 提交到 master 分支

其中 git remote add origin https://xxxx,就是往 .git/config 檔案裡新增下面這一段,手動新增也可以,意思就是與遠端倉庫建立關聯。其他的幾條命令後面有介紹,我們先認識下 origin 為後面做鋪墊;

[remote "origin"]
	url = https://github.com/rdif/xxxx.git
	fetch = +refs/heads/*:refs/remotes/origin/*

命令裡的 origin 類似變數命名,這是預設的而已,沒什麼特別的意思,可以隨便寫,假如改成 abc,後面的 git push origin xxx 改成 git push abc xxx 即可,方便區分遠端倉庫的

由此可得出一個結論,就是一個專案可以關聯多個遠端倉庫,命不同的名就行了

沒錯

git remote -v 可以快速檢視當前已經關聯的遠端倉庫列表

關聯多個遠端倉庫

可以使用 git remote add xxx 新增多個,或者直接動在 .git/config 檔案裡新增。

比如一個專案同時關聯一個 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/*

這樣當我們提交程式碼的時候,想提交到 Github 就用 git push github master,想同時提交到 GithubGitee 的倉庫,只需要 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 到暫存區,多個檔案以空格隔開
git add test.js
# 新增全部檔案到暫存區
git add .

git commit

# 會開啟 vim 編輯器,vim 編輯器操作在下面展開說明
git commit
# 提交暫存區的檔案到本地倉庫,並備註當前 commit 記錄
git commit -m '備註資訊'
# 相當於 git add . 加上 git commit -m 'xxxx'
git commit -am 'xxxx'
# 用本地提交替換上次提交,比如不想保留上一次提交或者上一次提交描述資訊寫錯了之類的
git commit --amend

git fetch

# 獲取 remote origin 對應遠端倉庫指定 master 分支的變更,但是不和原生的合併
git fetch origin master
# 意思一個樣,拉預設的分支而已
git fetch origin
# 也是,等效於 git fetch origin master:master,就是分支設定的預設值
git fetch
# 獲取預設遠端倉庫所有分支的變更
git fetch -a

git merge

# 把原生的 test 分支分併到我當前分支
git merge test
# 合併 remote origin 對應遠端倉庫的 master 分支到當前分支
git merge origin/master
# --on-ff 是 no-fast-forward簡寫,合併並且會在分支上重新生成一個新的 commit 節點
git merge --on-ff origin/master
# 加入 --squash 表示合併,但是不生成 commit 記錄,通常用於把本地分支合入遠端分支
git merge test --squash
# 取消合併
git merge --abort

git pull

pullfetch 都是下載遠端分支,區別是 pull 會和當前分支合併,fetch 不會

# 拉取 remote origin 對應的遠端倉庫的 master 分支合併到原生的 test 分支
git pull origin master:test
# 這種同理就不解釋了
git pull origin
# git pull --merge 的簡寫,預設是 --merge 模式
# 等於 git fetch 加上 git merge,拉遠端預設分支到當前分支
git pull
# 把合併模式切換成 rebase,等於 git fetch 加上 git rebase,rebase 後面進階有介紹
git pull --rebase origin master

git push

# 推播本地 test 分支到 remote origin 對應的遠端倉庫的 master 分支
git push origin test:master
# 上面同理,推播到遠端預設分支
git push origin test
# 縮寫,同理,用預設分支
git push origin
git push

# 相當於 git push origin master 加上 git branch --set-upstream master origin/master
# 推播並設定預設遠端分支
git push -u origin master
# 強制推播,就算本地和遠端有差異也推上去
git push -f origin master
# 刪除遠端主機的 master 分支
git push origin -d master

vim 基本操作

一點點小插曲

比如 git commit 就會開啟一個 vim 的終端編輯器,讓我們寫提交說明,新手很容易在這個編輯器上面踩坑,不知道怎麼輸入,不知道怎麼退出,最後只能關閉終端視窗,這也沒辦法,vim 的操作確實有些反人類。

vim 開啟預設是不能輸入的,要按 a 或者 i 進入編輯模式,輸入完成後,再按 Esc 退出編輯模式,這時左下角會有輸入框,輸入如下英文字元,注意冒號別打成中文字元,回車即可退出 vim 回到終端:

  • :w:儲存
  • :q:退出
  • :wq:儲存並退出
  • !:強制的意思,不能儲存時 :w! 強制儲存,不能退出時 :q!:wq! 強制退出

我們繼續 git

分支管理 branch/switch/checkout

一個人玩,可能分支的作用沒那麼大,但是團隊共同作業,離不開分支管理。

比如本文開頭圖片那樣一個版本一個分支多方便,是吧

或者現有一個新需求一個頁面分為多個模組,分配給多個人負責,每人做一個模組,最後合併成一個完整的頁面,如果都在同一個分支上開發,各種邏輯相互穿插,那衝突真的是人都要搞麻了,如果每個人都新建一個分支,開發自己負責的那個功能,最後再合併到同一個分支上去就非常方便了

然後因為多人共同作業肯定不是在一臺電腦上,所以就需要一個伺服器,來搭建一個 Git 倉庫服務,或者用公共的雲伺服器倉庫儲存,常見的程式碼託管平臺有比如:Github碼雲(Gitee)騰訊工蜂GitLabBitbucket...,關於這個本篇文章不過多展開。

建立分支

# 建立本地分支 test,但不切換
git branch test
# 建立 test 分支,並切換到 test 分支
git branch -M test
# 建立 test 分支,並切換到 test 分支
git checkout -b test
# 建立 test 分支,並切換到 test 分支
git switch -c test
# 建立本地與遠端對應的 test 分支,並切換到 test 分支,全稱最好一致
git checkout -b test origin/test

檢視分支

# 檢視所有本地分支
git branch
# 檢視所有遠端分支
git branch -r
# 檢視本地和遠端所有分支
git branch -a

切換分支

checkoutswitch 的共同點是都能切換分支,不同點是:

  • switch 語意上好點
  • switch 僅僅用於切換和建立並切換,checkout 還能用來還原工作區,後面進階那有介紹
# 切換到 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
# 刪除遠端主機的 master 分支
git push origin -d master

刪除分支後恢復

# 檢視記錄,找到對應的 hash
git reflog
# 建立test分支,並取對應hash分支所有內容,相當於恢復了被刪除的分支
git checkout -b test hash

重新命名分支

# 把原生的 master 分支重新命名為 test
git branch -m master test
# 遠端分支沒法直接重新命名,只能刪了重建,主要分幾步
# 1. git push origin --delete test 刪除遠端分支
# 2. git push origin newtest 上傳新的遠端分支
# 3. 把修改後的本地分支關聯遠端分支
git branch --set-upstream-to origin/newtest

合併分支

其實就是上面的 git merge。比如要把 test 分支合併到 master 分支,就:

# 先切換到 master 分支
git checkout master
# 拉一下,看有沒有更新
git pull
# 把 test 分支合進來
git merge test
# 檢視狀態,看有沒有衝突的,有就開啟 IDE 解決一下
git status
# 然後 add、commit、push 幾個命令來一輪就 ok 了

git commit 提交規範

git commit 提交規範指的就是 git commit -am 'xxxx' 裡的 xxxx 的書寫規範,比如我在工作中開發了一個新功能提交的時候一般這麼寫:

  • git commit -am 'feat: 新增掃碼登入
  • git commit -am 'feat(mobile):新增掃碼登入,或者加個範圍說明是新增哪方面的功能

feat 就是新增新功能的時候用,更多說明如下:

  • feat:新增新功能
  • fix:修復問題/BUG
  • style:注意不是指CSS,而是修改瞭如空格、縮排、逗號等程式碼風格相關,且不影響執行結果的
  • perf:優化相關的,比如功能優化、效能提升、提升體驗等
  • refactor:程式碼重構,沒有加新功能或者修復 bug
  • revert:撤消編輯,回滾到上一個版本、復原上一次的 commit 之類的
  • test:測試相關,比如單元測試、整合測試等
  • docs:修改檔案/註釋,比如 README、CHANGELOG、CONTRIBUTE 等
  • chore:依賴更新/腳手架設定修改等,比如有改變構建流程、或者增加依賴庫、工具之類的
  • workflow:工作流程改進
  • ci:持續整合
  • types:型別定義檔案更改

到這裡,基礎部分內容就結束了

問個問題:git branch -M ac 是啥意思?不許翻上面

進階操作

常用命令

Git 別名(alias)

命令難記?沒有關係

Git 並不會在你輸入部分命令時自動推斷出你想要的命令。 如果不想每次都輸入完整的 Git 命令,可以通過 git config 檔案來輕鬆地為每一個命令設定一個別名。

// 設定全域性 branch 命令別名為 b
git config --global alias.b branch

然後比如想建立一個名為 test 的本地分支,如下即可

git b test

在建立你認為應該存在的命令時這個技術會很有用。

檢出 git checkout/git restore

checkout命令用於從歷史提交(或者暫存區域)中拷貝檔案到工作目錄,也可用於切換分支。

restore指令使得在工作空間但是不在暫存區的檔案復原更改(內容恢復到沒修改之前的狀態)

# 四個都是:復原 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 拿過來替換當前分支的 test.js
git checkout master - test.js

# 都是復原上一次 commit 之後的所有檔案的所有修改
git checkout -- *
git checkout -- .
git checkout .
git restore .

# 把暫存區的 test.js 重新放回工作區,和下面的 git reset HEAD test.js 作用一樣
git restore --staged test.js

重置 git reset

git reset 通常用來把程式碼重置到過去的某個版本,有五種模式(--mixed--soft--hard--merge),注意看註釋有說明區別。

另外 git reset 比較暴力,要慎用,比如現在提交五次了,然後使用這個命令重置到第一次,那麼第二三四五次提交記錄會全部沒了的,找不回來的,這種情況記得新建個分支來執行這種操作就沒事了,或者使用 git revert

# 後面一長串就是我複製的 commitID 或者說是 hash,長得就是這樣子的
# 等同於 git reset commitID,因為 --mixed 是預設模式,所以可以不寫
# 重置並復原 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

# 把暫存區所有檔案退回到工作區,相當於復原 git add .
git reset HEAD
# 把暫存區的 test.js 重新放回工作區,和 git restore --staged test.js 作用一樣
git reset HEAD test.js
# 重置到上一個版本
git reset --hard HEAD^
# 重置到上上一個版本,以此類推
git reset --hard HEAD^^
# 重置到指定版本
git reset --hard commitID

commitID 可以通過三種方法檢視

  1. 執行 git log 命令能看到當前分支本地所有提交記錄,上面每一條記錄都有對應一個 commitID
  2. 去遠端程式碼倉庫檢視歷史提交記錄,那裡每一條提交記錄都有一個對應的 commitID
  3. git tag 檢視標籤列表,如果有的話,再 git show 標籤名 檢視標籤詳情,裡面也會有 commitID
# 檢視當前分支所有提交記錄,詳細列表,一條記錄有幾行資訊
git log
# 檢視當前分支所有提交記錄,簡要列表,一條記錄一行
git log --pretty=oneline
# 
git log --oneline -n5

另外關於叫法本地倉庫一般說重置、還原、復原都行,遠端倉庫一般叫回滾

還原 git revert

git revertgit reset 有點類似,只是比 reset 稍微溫柔一點,沒那麼暴力。git revert是用於「反做」某一個版本,以達到復原該版本的修改的目的。

上面介紹了假如現在是第五版,用 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 提交需要加引數來區分復原哪一個分支上的內容
# 也就是指定上面 Merge: 3f6acb587 68be9e548,這兩個 id 中的哪一個
# -m 接收一個引數是數位,取值 1 或 2,表示 Merge 的第一個還是第二個 id
git revert -m 1 9c810c1db
# 刪除最後一次遠端提交
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 上,就可以複製 test 的 commitID,再換到 master 分支後執行 git cherry-pick commitID 就可以了

what?這不就是 merge?

和 merge 不同的是:cherry-pick 合併的是某一次 commit 提交的檔案,merge 合併的是整個分支。且 merge 會額外多一條 merge commit 的記錄,而 cherry-pick 不會。

而且 cherry-pick 更加靈活,在需要把某個/或多個分支中的 commit,合入其他分支的時候都可以用,範例如下

# 這樣就把其他分支的一個 commit 合入當前分支了
git cherry-pick commitID

# 如果需要把多個 commit 合過來如下,這多個 commitID 可以是來自不同分支的
git cherry-pick commitID1 commitID2 commitID3

變基 git rebase

git rebasegit merge 的區別

git merge 和 git rebase 都是可以合併分支,合併用法也是一樣,不同的一個是在 commit 記錄的處理上:

  • git merge 會新建一條新的 commit,然後兩個分支以前的 commit 記錄都指向這個新 commit 記錄。這種方法會保留之前每個分支的 commit 歷史。
  • git rebase會先找到兩個分支的第一個共同的 commit 祖先記錄,然後將提取當前分支這之後的所有 commit 記錄,放到目標分的最新提交後面。經過這個合併後,兩個分支合併後的 commit 記錄就變為了線性的記錄了。

這麼說可能不太好理解,看如下範例:

# 如下,需要把本地 test 分支合入 dev
# 為方便理解,字母表示commit記錄,數位表示提交時間順序,可以理解為1就是1點提交的
dev -> A1 -> B3 ->    這一行是遠端 dev 分支的commit記錄,A1/B3是你同事提交的
      ↘ X2 -> Y4↗   這一行是拉取了 dev 分支後在原生的 test 分支 commit 記錄

# 現在需要把你原生的分支合併到遠端的分支去
# 用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 到遠端,最後想提交到遠端的時候,為了簡潔,我們希望把原生的三個 commit 合併成一個 commit 再提交到遠端,遠端只產生一條 commit 記錄,就可以用 git rebase -i 處理下先,這命令可以刪除指定記錄,或者合併多個 commit,對 commit 訊息編輯等
# 刪除某次提交,^表示 commitID 的前一次提交
git rebase -i 'commitID'^
# 修改多個提交資訊
git rebase -i HEAD~3

貯藏 git stash

git stash 常用於把修改儲存起來,需要的時候再取出來。常用於:

  • 切換分支並且需要保留修改的時候
  • 切換分支並且需要把修改帶到新的分支的時候
# 把當前分支的修改儲存起來,兩個一樣的
git stash
git stash save
# 儲存並新增備註,方便查詢
git stash save '備註資訊'
# 檢視儲存列表
git stash list
# 取出儲存中最近一次的修改並刪除儲存記錄
git stash pop
# 取出儲存中的指定部分修改,stash@{0} 0是預設的不寫也行,是啥只要檢視儲存列表你就知道了
git stash apply stash@{0}
# 刪除指定儲存
git stash drop stash@{1}
# 刪除所有的儲存
git stash clear
# 建立一個新分支 test,並恢復儲存工作時所在的提交到該分支上,並扔掉儲藏
git stash branch test stash@{1}
# 不儲存暫存區的,也就是 git add 了的
git stash --keep-index

清理 git clean

git reset 的區別是:reset 刪除的是己跟蹤的檔案,並且將已 commit 的回退。clean 刪除的是未跟蹤的檔案/目錄

# 顯示如果執行後面刪除的命令將會刪除的檔案和目錄,相當於給提前給我們確認下
git clean -n
# 刪除工作目錄中所有沒被追蹤的檔案(-f)以及空的子目錄(-d),一起就是 -df
git clean -df

差異 git diff

用來找出倉庫或者檔案之間的差異,可以用來預測或者阻止可能產生衝突的合併

# 工作區 vs 暫存區
git diff
# 工作區 vs 版本庫
git diff head
# 暫存區 vs 版本庫
git diff –cached

有多種方法檢視兩次提交之間的變動,如下面是一些範例。

問題預防

  • 不要對已經提交到遠端倉庫的 commit 進行 rebase 變基操作,除非是你一個人玩的分支
  • 在切換分支,或者合併分支,或者重置/回滾之前,最好不要有未 commit 的檔案,如果有並且不想提交就用 git stash 先存起來,再執行操作,如果用命令操作的話,取出之後記得清理
  • 遠端倉庫回滾前記得做好備份,比如拉一個分支在本地。並且需要通知團隊其他成員,不要悄摸摸地就搞了

解決問題

切換分支保留修改

有時候比如我們在 test 分支上開發了一半,由於某些原因需要切換到 master 分支,但現在又不想提交,又想保留修改並且不帶到 master 分支上去,就可以這樣:

# 把當前分支的修改儲存起來
git stash
# 切換到其他分支幹你的事
git checkout master
# 幹完了
# 切換回 test 分支
git checkout test
# 取出儲存中所有的修改
git stash pop
# 刪除所有的儲存
git stash clear

切換分支轉移修改

有的時候我們需要在 test 分支上開發,但是忘記了,活快乾完了才發現當前原來是 master 分支,可是已經開發了,這時候就需要切換分支到 test,並且把已經開發的部分內容也從 master 分支帶到 test 分支來,就可以這樣:

# 儲存修改
git stash
# 切換到 test 分支
git checkout test
# 取出儲存中的全部修改
git stash pop
# 或者
# 檢視儲存列表
git stash list
# 取出儲存中的指定部分修改,stash@{0} 是啥只要檢視儲存列表你就知道了
git stash apply stash@{0}
# 再清掉儲存
git stash clear

合併時發生衝突用 git merge abortgit reset --merge 都可以取消合併

比如把不想要的程式碼 commit 了,但是沒有 push 比如剛更新的程式碼出問題了,需要還原這次提交的程式碼 比如某次提交了不想提交的東西,需要清除掉它

revert 之後重新上線 diff 丟失

  • 比如在 dev 分到開發了個功能,提交後會產生一條 commit 記錄,為了方便理解,我們先把這次提交標記為 a
  • 然後合併到 master 後,我們把這次合併記錄標記為 b
  • 結果出現了 bug 需要復原合併,使用 revert b 復原了,這會產生了一條新的記錄 我們標記為 c
  • 然後繼續在 dev 分支開發完成提交,提交記錄標記為 d
  • 這時候再合併到 master 上去,此時合併後的內容不會包含 a 的提交,因為 a 被 revert 丟棄過,不會參與 diff,如果需要包含 a,需要先 revert c 意思是復原某一次的復原,再來合併,就 ok 了

合併衝突不想合併了

合併時、或者拉取時等,發現有衝突,可能是其他同事提交的,自己不知道怎麼衝突怎麼選擇,或者其他原因,總之不想合併了,都可以用 --abort 取消,比如合併的時候發現有衝突不想合併了

git merge --abort 取消合併即可

解決衝突

有的時候合併分支衝突是由於本地主分支沒有更新導致,或者有時 git pull 的時候衝突,只需要掉本地主分支,再重新拉一下遠端分支就好了。

有的時候衝突就只能解決衝突,使用 git status 看由於衝突導致沒有合併成功的檔案是哪些,然後去編輯器開啟衝突的檔案即可,也可用 cat <檔案路徑> 檢視指定檔案裡衝突的部分,直接去編輯器改

或者就是用命令,比如把 test 分支,合入 master 分支時產生衝突。

# 只保留 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的最主要的區別?

Git是分散式版本控制系統,那麼它就沒有中央伺服器的,每個人的電腦就是一個完整的版本庫,這樣,工作的時候就不需要聯網了,因為版本都是在自己的電腦 上。既然每個人的電腦都有一個完整的版本庫,那多個人如何共同作業呢?比如說自己在電腦上改了檔案A,其他人也在電腦上改了檔案A,這時,你們兩之間只需把各 自的修改推播給對方,就可以互相看到對方的修改了。

SVN是集中式版本控制系統,版本庫是集中放在中央伺服器的,而幹活的時候,用的都是自己的電腦,所以首先要從中央伺服器哪裡得到最新的版本,然後幹活, 幹完後,需要把自己做完的活推播到中央伺服器。集中式版本控制系統是必須聯網才能工作,如果在區域網還可以,頻寬夠大,速度夠快,如果在網際網路下,如果網 速慢的話,就納悶了。

參考資料:

圖解GIT: http://marklodato.github.io/visual-git-guide/index-zh-cn.html

Git官方:https://git-scm.com/

Git參考手冊:https://git-scm.com/docs

結語

如果本文對你有一點點幫助,點個贊支援一下吧,你的每一個【贊】都是我創作的最大動力 _

更多幹貨技術文章可前往:http://www.guosisoft.com/article,大家一起共同交流和進步呀!


前往瞭解國思RDIF低程式碼開發平臺:http://www.guosisoft.com