1. 同一電腦存在多個 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 專案上提交程式碼了。
2. 修改 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_NAME="woai3c";
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
強推即可。
3. 修改某個歷史記錄的訊息
假設當前分支有 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
記錄恢復到原來的位置。
這個過程的執行結果就和上圖一樣,這是當前分支修改後和遠端分支上的對比,箭頭指向的記錄訊息就是修改後的訊息。
如果想把修改後的記錄同步到遠端倉庫,這時只要執行 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>
合併新分支,最後強推到遠端分支
4. 挑選指定的 commit 進行合併
假設你切了一個 bugFix 分支來修復線上 bug,經過一段時間的努力後終於將 bug 修復了。但是為了除錯(加了很多 debug 程式碼)或其他原因,bugFix 上多了很多無用的記錄訊息。
commit3: 修復登入 bug
commit2: 新增 debug 語句
commit1: 新增 console 語句
例如上面的三個記錄,前面的兩個記錄新增了很多除錯程式碼,在最後一個記錄終於修復了 bug,並且刪除了除錯程式碼。這時如果直接將 bugFix 分支合到 master 分支,就會把除錯的記錄也合併進來。
這時可以使用 git cherry-pick
只將最後一個記錄合併到 master 分支。或者使用 git rebase
將 bugFix 分支另外兩個記錄拋棄,然後再合併。
5. ^
和 ~
的區別
操作符 ^
與 ~
符一樣,後面也可以跟一個數字。 ~
表示向上返回幾代記錄。
但是該操作符後面的數字與 ~
後面的不同,並不是用來指定向上返回幾代,而是指定合併提交記錄的第幾個父記錄。
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 個 ^
。
6. 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
。