好慌,我程式碼沒了!不會是變基變出問題了吧?

Kagol發表於2022-12-07

大家好,我是 Kagol,Vue DevUI 開源元件庫和 EditorX 富文字編輯器建立者,專注於前端元件庫建設和開源社群運營。

前兩天檢視程式碼時,發現PR裡面有兩個提交的描述資訊一模一樣,於是我提出應該將這兩個提交合併成一個,保持提交樹的清晰。

先儲存起來!

而同事這時正在開發別的特性,工作區不是乾淨的,沒法直接執行 git rebase 操作,於是很自然地執行

git stash

將正在修改的內容儲存到一個棧中,並維持當前工作區乾淨。

這樣就可以執行切換分支、變基等操作,這些操作能執行的前提是當前工作區是乾淨的。

變基吧!少年!

我們先執行 git log 命令,找到要合併的兩個提交之前的那個提交:cdedd430

commit ec0218ff
    feat: 增加國際化
commit 89f3d02c
    feat: 增加國際化
commit cdedd430
    refactor: pnpm工程改造

然後執行 git rebase 變基命令:

git rebase -i cdedd430

這時會進入一個互動式命令列介面:

pick 89f3d02 feat: 增加國際化
pick ec0218f feat: 增加國際化

# Rebase cdedd43..ec0218f onto cdedd43 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
"~/my-project/.git/rebase-merge/git-rebase-todo" 28L, 1232B

這時你可以移動游標,但是無法輸入字元,因為這是個只讀的介面,需要先輸入 i 字元進入編輯態,此時介面底部會出現 -- INSERT -- 標識。

...
# Note that empty commits are commented out
-- INSERT --

下面那些以 # 開頭的都是註釋,只有前面兩行比較關鍵。

pick 89f3d02 feat: 增加國際化
pick ec0218f feat: 增加國際化

# ...

每一行都由三部分組成:

  • Command:需要執行的命令
  • Commit ID:提交 ID
  • Commit message:提交的描述資訊

我們需要將 ec0218f 合併到 89f3d02 上,因此需要將第二行的 pick 改成 squash(s) 或 fixup(f),這兩個命令的區別在於:

  • squash(s) 是將當前的提交合併到上一行的提交上,保留兩個提交的描述資訊,可以在下一步中進行提交資訊的編輯
  • fixup(f) 也是將當前的提交合併到上一行的提交上,但不保留當前提交的描述資訊

由於我們兩次提交資訊完全一致,沒必要保留,選擇 fixup(f):

pick 89f3d02 feat: 增加國際化
f ec0218f feat: 增加國際化

修改好之後,先按 ESC 退出編輯態,然後按 :wq 儲存,顯示以下資訊說明變基成功,兩個提交已經合併在一起

Successfully rebased and updated refs/heads/kagol/test-rebase.

執行 git log 看下效果:

commit 86930d03
    feat: 增加國際化
commit cdedd430
    refactor: pnpm工程改造

可以看到兩個提交已經合併在一起,並且生成了一個新的 Commit ID: 86930d03。

完美.png

我程式碼沒了!

1小時之後,同事慌慌張張地跟我說:

我程式碼沒了!

我心裡第一反應是:

剛才一頓變基猛如虎,不過變基變出問題來了吧?

貓貓震驚.png

作為一個成熟穩重的程式設計師,什麼大風大浪沒見過,於是輕輕地回了句:

少年,莫慌!你先講下你剛才做了什麼?

我沒,沒做什麼...

沒做什麼程式碼怎麼會自己丟了呢?

我就執行了一下 git stash pop,然後我之前寫了一上午的程式碼就沒...沒了...

突然開始心裡有點慌,把同事一上午程式碼搞沒了,我怎麼賠給人家??

image.png

但心裡不能表現出來,不著急,穩住少年!

你先執行下 git stash list 看下儲存棧裡還有沒有內容:

$ git stash list
stash@{0}: WIP on master: f90abfe Initial commit

看到之前儲存的內容還在我立馬不慌了!

不再執行下 git stash pop,我看下有沒有報什麼錯?

執行完之後果然報了一個錯:

$ git stash pop
error: Your local changes to the following files would be overwritten by merge:
        main.ts
Please commit your changes or stash them before you merge.
Aborting
The stash entry is kept in case you need it again.

大意是:

你本地修改了檔案,儲存棧裡的內容如果彈出會覆蓋掉你本地的程式碼,所以導致操作失敗。
然後建議你先提交你本地的修改或者將你本地的修改儲存起來。
並且特意提示你你儲存的內容給你保留下來了,方便你下次要用的時候可以用。

不得不說,這 Git 真是太貼心了,考慮得很周到,為 Git 點個贊?

雖然我其實已經猜到是什麼原因了,但是作為成熟穩重的程式設計師,我依然不動聲色地問了句:git rebase 之後,git stash pop 之前,中間你是不是還改了什麼東西?

哦,好像是改了 main.ts 檔案,我想起來了!

你把你改的東西先撤銷下,然後執行 git stash pop 試試?

破案!收工!

果然,執行 git stash pop 成功,之前的上百行程式碼都找回來了!

破案!收拾吃飯的傢伙,準備收工!

下班了.png

哦,不行,還有兩個小時才下班...

我是 Kagol,如果你喜歡我的文章,可以給我點個贊,關注我的掘金賬號和公眾號 Kagol,一起交流前端技術、一起做開源!

相關文章