一些常用的 Git 進階知識與技巧
- 同一電腦存在多個 Git 賬號
假設我們在同一電腦上擁有多個 Git 賬號,例如公司內部使用的是 Gitlab,個人使用的是 Github 或者 Gitee。那就會遇到一種情況,上班時想給個人開源項目提交代碼,但是 Git 綁定的是公司的賬號。
在這種情況下,我們可以讓 Git 綁定多個不同的 ssh key,每個 ssh key 對應一個不同的 Git 服務器。
生成第一個 ssh key:
ssh-keygen -t rsa -C "xxx@xxx.xx"
複製代碼
生成第二個 ssh key:
ssh-keygen -t rsa -f path/to/file -C "xxx@xxx.xx"
複製代碼
參數 -f
表示指定生成的文件名, path/to/file
是文件名路徑,例如 ~/.ssh/id_rsa_github
。
執行上面兩條命令後會得到兩對 ssh key。
這時還需要在該目錄下創建一個 config
文件。寫上以下內容:
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_github # 私鑰文件路徑
Host gitlab.com
HostName gitlab.com
User git
IdentityFile ~/.ssh/id_rsa
Host gitee.com
HostName gitee.com
User git
IdentityFile ~/.ssh/id_rsa_github
複製代碼
這個配置文件的作用是指定私鑰文件位置。
然後我們可以把第一個密鑰配置到公司的 Gitlab 服務器,並把相應的 Git 賬號和郵箱設成全局。
git config --global user.name "xxx"
git config --global user.email "xxx@xxx.xx"
複製代碼
然後把另一對 ssh key 配置到 Github 上,並在電腦上的 Github 項目裏單獨配置 Git 用戶姓名和郵箱。
git config user.name "xxx"
git config user.email "xxx@xxx.xx"
複製代碼
至此,我們就大功告成了。可以同時在不同的 Gitlab 和 Github 項目上提交代碼了。
- 修改 git commit 記錄的用戶姓名和郵箱
假設電腦上同時存在 Gitlab 和 Github 項目,其中 Gitlab 用戶信息已經全局配置過了。現在新拉了一個 Github 項目,提交了一個 commit 並且已經推送到了遠程倉庫。這時發現該項目未配置 Github 的用戶信息,默認使用的是全局賬號 Gitlab 的用戶信息。
我們可以通過以下命令來修改最近一次提交的用戶信息:
git commit --amend --author="username <yyy@ccc.com>" --no-edit
複製代碼
username
是用戶名,用戶郵箱旁邊的 <>
符號不能去掉。修改後再執行 git push \-f
推送到遠程倉庫。
如果要修改多個 commit 的用戶信息怎麼辦?可以通過以下的代碼來修改:
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "tanguangzhi@shiqiao.com" ];
then
GIT_AUTHOR_;
GIT_AUTHOR_EMAIL="411020382@qq.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
複製代碼
將上述代碼中的用戶名和郵箱修改後,保存爲 .sh
格式的文件,例如 edit.sh
。然後在項目根目錄下執行 sh edit.sh
(windows 下可右擊 -> Git Bash Here
-> sh edit.sh
),再執行 git push \-f
強推即可。
- 修改某個歷史記錄的消息
假設當前分支有 a b c d
四個 commit 記錄:
a
b
c
d
複製代碼
如果你想對 c
記錄的消息進行修改。可以使用 git rebase
將 c
記錄換到最前面,然後使用 git commit \--amend
對其消息進行修改。
具體操作步驟
執行以下命令對記錄 d
前面的三個 commit 進行編輯:
git rebase -i d
複製代碼
進行 vim 編輯界面後,移動光標到 c 記錄上,按下 dd
剪切該記錄,然後移動光標到第一行,按下 p
粘貼,再輸入 :wq
保存。
執行 git commit \--amend
對切換順序後的 c
記錄進行修改。進入 vim 編輯界面後,按 i
進行修改,然後按 ESC
,再輸入 :wq
保存。
最後用前面講過的 git rebase
操作將 c
記錄恢復到原來的位置。
image
這個過程的執行結果就和上圖一樣,這是當前分支修改後和遠程分支上的對比,箭頭指向的記錄消息就是修改後的消息。
如果想把修改後的記錄同步到遠程倉庫,這時只要執行 git push \-f
就可以了。
第二種方式
-
使用
git checkout -b <branchName> c
從指定記錄切出一個分支 -
在新分支使用
git commit --amend
修改提交消息 -
使用
git cherry-pick
將b a
記錄,追加到新分支(注意,這裏的b a
提交記錄是指原分支上的 commit,也就是選取原分支上的b a
記錄添加到新分支上,這樣新分支上的記錄就變成了a b c
,並且 c 記錄的提交消息在第二步已經修改過) -
使用
git checout 原分支名
切換回原來的分支,再執行git rebase <branchName>
合併新分支,最後強推到遠程分支 -
挑選指定的 commit 進行合併
假設你切了一個 bugFix 分支來修復線上 bug,經過一段時間的努力後終於將 bug 修復了。但是爲了調試(加了很多 debug 代碼)或其他原因,bugFix 上多了很多無用的記錄消息。
commit3: 修復登錄 bug
commit2: 添加 debug 語句
commit1: 添加 console 語句
複製代碼
例如上面的三個記錄,前面的兩個記錄添加了很多調試代碼,在最後一個記錄終於修復了 bug,並且刪除了調試代碼。這時如果直接將 bugFix 分支合到 master 分支,就會把調試的記錄也合併進來。
這時可以使用 git cherry-pick
只將最後一個記錄合併到 master 分支。或者使用 git rebase
將 bugFix 分支另外兩個記錄拋棄,然後再合併。
^
和~
的區別
操作符 ^
與 ~
符一樣,後面也可以跟一個數字。~
表示向上返回幾代記錄。
但是該操作符後面的數字與 ~
後面的不同,並不是用來指定向上返回幾代,而是指定合併提交記錄的第幾個父記錄。
Git 默認選擇合併提交的 “第一個” 父記錄,在操作符 ^
後跟一個數字可以改變這一默認行爲。
單看文字可能不太好理解,下面看幾個示例。
執行命令 git checkout main^
回到第一個父記錄(原來 HEAD 指向 c3,現在指向 c1)。
執行命令 git checkout main^2
回到第二個父記錄(原來 HEAD 指向 c3,現在指向 c2)。
最後再來一個更復雜的示例:
G H I J
\ / \ /
D E F
\ | / \
\ | / |
|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2 = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
複製代碼
通過這些示例我們還能發現 ~n
等於連續的 n 個 ^
。
git revert
與git reset
的區別
git reset
可以回退 Git 的歷史記錄。例如當前分支有三個記錄,並且 HEAD 指向 c 記錄:
c <- HEAD
b
a
複製代碼
如果我們想回退到 b 記錄,只要執行 git reset b
就可以了:
b <- HEAD
a
複製代碼
接着使用 git push \-f
將回退版本後的分支強制推送到遠程倉庫,這樣本地分支和遠程分支就同步了。
git push -f
複製代碼
git revert
也可以撤銷記錄,只不過它撤銷的記錄不會消失,這一點和 git reset
不一樣。git reset
撤銷的記錄就跟消失了一樣。
現在我們用 git revert
來重新演示下剛纔的操作:
c
b
a
複製代碼
如果我們執行 git revert b
,則會在當前分支上再生成一個新的 commit 記錄,變成 a b c b'
,這個 b'
的狀態和記錄 b
是一樣的。
也就是說,執行 git reset b
後,當前的分支記錄會變成 a b
。執行 git revert b
後,當前的分支記錄會變成 a b c b'
。
如果你想讓別人知道你撤銷過記錄,就使用 git revert
,因爲它會留下撤銷的記錄,否則用 git reset
。
關於本文
作者:譚光志
https://juejin.cn/post/7022746201598459940
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/INR0tGmPxx8IPuyCqgwB-g