Git 手欠恢復技巧
翻譯自 Git Out Of Trouble。
搭建練習環境
在 http://Github.com 上創建倉庫並 clone 到本地;
創建一個新分支,叫作 test;
創建一系列 commit,可使用如下腳本:
Bash
for d in {1..6};n do touch file$d.md;n git add file$d.md;n git commit -m "adding file $d";n donen
PowerShell
for ($d=1; $d -le 6;$d++) {n touch file$d.md;n git add file$d.md;n git commit -m "adding file$d.md";n }n
創建了太多細碎的 Commit
在開發自己的項目的過程中,可能很多細小的改變也創建了 commit,這使得 commit 歷史很繁瑣。
還沒有 push
如果還沒有 push, 可以修改創建的 commit 而無需擔心在和協作者開發時出現問題。
確保當前分支正確,並輸入命令 git log --oneline;
在本例中,我們將 adding files 4, 5, and 6 的 commit 合併。所以找到 adding file 3 的 commit 的 SHA-1 值;
輸入命令 git reset --soft SHA-1,其中 SHA-1 為 adding file 3 的 SHA-1;
輸入 git status,將會看到 files 4, 5, 6;
輸入 git commit -m "Adding files 4, 5, and 6";
輸入 git log --oneline,此時 commit 歷史已經修改完成。
已經 push 了
此時再通過 Git 修改 commit 將可能會引起協作上的問題,所以建議使用 Squash and Merge 來修改。
翔一樣的 Commit Message
比如單詞寫錯了,寫了不該寫的東西之類的情況。
還沒有 push
首先問自己一個問題,是要修改上一個 commit 還是要修改之前的幾個 commits?
修改上一個 commit
確認在正確的分支;
輸入 git log --oneline 來確定你想要修改的 commit 在列表的最上面;
輸入 git commit --amend;
輸入你想要修改的 message。
修改之前的 commit
確認分支並輸入 git log --oneline;
找到你想要修改的 commit 的前一個 SHA-1,在本例中,使用 add file 4;
輸入 git reset --mixed SHA-1;
現在可以重新 add 和 commit 對 file 5 和 6 的修改了。
已經 push 了
此時需要使用 git push --force-with-lease 命令,該命令可能會對協作者造成嚴重的問題,如果 message 不是那麼爛,可以考慮就那樣放著。
首先問自己一個問題,是要修改上一個 commit 還是要修改之前的幾個 commits?
修改上一個 commit
確認在正確的分支;
輸入 git log --oneline 來確定你想要修改的 commit 在列表的最上面;
輸入 git commit --amend;
輸入你想要修改的 message;
輸入 git push --force-with-lease 強行向 remote 同步更改。
修改之前的 commit
確認分支並輸入 git log --oneline;
找到你想要修改的 commit 的前一個 SHA-1,在本例中,使用 add file 4;
輸入 git rebase -i SHA-1,-i 是使用交互模式,會打開編輯器,讓你更改 rebase 腳本;
找到你想要修改的 commit,將 pick 替換為 e 或是 edit,當更改完成後關閉編輯器,回到終端;
rebase 操作會停在第一個被編輯的 commit 處,輸入 git commit --amend 修改該 commit message;
關閉編輯器,輸入 git rebase --continue;
重複前兩步操作;
當全部 commit 修改完,輸入 git push --force-with-lease。
提交到了錯誤的分支
突然發現提交到了 master 分支而不是用來開發的分支。
還沒有 push
確認現在處於提交錯誤 commit 的分支,在本例中,已經提交了幾個 commits 在 test 分支中;
輸入 git log --oneline,找到錯誤 commit 之前的一個 SHA-1 值,本例中,假定 file 5 本來應該提交到另一個分支上;
輸入 git reset --mixed SHA-1,其中 SHA-1 為 adding file 4 的 SHA-1;
輸入 git status,此時 file 5 和 6 都在工作目錄中;
輸入 git checkout -b correct,創建一個名為 correct 的新分支並檢出;
輸入 git status,此時 file 5 和 6 應該還在工作目錄中;
添加 file 5 和 6,git add file*;
輸入 git status,現在 file 5 和 6 已被成功添加,等待 commit;
輸入 git commit -m "Adding file 5 and 6"。
已經 push 了
首要任務:將 master 分支修好
在 master 分支中輸入 git log --oneline,找到需要移除的 commits,在本例中,定為 adding file 3;
輸入 git revert SHA-1,可以 revert 多個 commits,用空格分開;
修改 revert commit message,或者可以直接關閉編輯器;
輸入 git push。
重建分支
現在 master 分支已經修好,創建一個新分支來整理錯誤的 commits。
創建分支,git checkout -b new-branch,或者檢出到已創建好的分支;
輸入 git reflog,找到需要重建的 commits 的 SHA-1;
輸入 git cherry-pick SHA-1,可以重建多個 SHA-1 值,用空格分開;
輸入 git push -u origin new-branch。
意外 commit
還沒有 push
確認在正確的分支,並輸入 git log --oneline;
在本例中,假定我們並不想提交 file 6,所以找到 adding file 5 的 SHA-1;
輸入 git reset --mixed SHA-1;
輸入 git status,現在 file 6 將出現在工作目錄中。
已經 push 了
首先需要 revert commits。
確認在正確的分支,並輸入 git log --oneline;
找到錯誤的 commit 的 SHA-1,本例中,使用 adding file 4;
輸入 git revert SHA-1;
輸入 revert message,或保留默認直接關閉編輯器;
輸入 git push。
恢復工作。
輸入 git log --oneline,找到 revert commit,如果是默認的,應該為 Revert "adding file 4";
輸入 git revert SHA-1,SHA-1值為 revert commit;
完成當前需要繼續的工作;
輸入 git add;
輸入 git commit --amend,將現在的修改合併到之前的 commit 中;
輸入正確的 commit message;
輸入 git push 同步工作。
推倒重來
還沒有 push
首先問自己一個問題:要徹底重來還是有一部分可以湊合留著?
徹底重來
檢出到 master 分支,git checkout master;
刪除舊分支,git branch -D BRANCH-NAME。
有一部分可以留著
如果你想看到一些炫酷的操作,請在文件瀏覽器中打開倉庫(Finder 等),然後放在能看到的地方。
確認在正確的分支,並輸入 git log --oneline;
找到你想要保留的最後一次 commit 的 SHA-1 值。在本例中,假定 file 1 和 2 是要保留的,其他部分不要,所以找到 adding file 2 的 SHA-1 值;
輸入 git reset --hard SHA-1,如果你打開了文件瀏覽器,你會發現已經出現了一些炫酷的操作!
輸入 git status 和 ls,注意到現在只有 file 1 和 2 仍保留著。
輸入 git log --oneline,adding file2.md 之後的 commits 都消失了。
等等,我好像幹了不該乾的事!
一時衝動,你「意外」地刪除了一些文件。
找回一個文件
輸入 git reflog;
找到 adding file 6 commit 的 SHA-1 值;
輸入 git cherry-pick SHA-1;
輸入 git log --oneline 和 ls,file 6 已經回來了。
全部找回
輸入 git reflog;
找到 adding file 6 commit 的 SHA-1 值;
輸入 git reset --hard SHA-1;
輸入 git log --oneline,所有文件都出現了。
已經 push 了
首先問自己一個問題:要徹底重來還是有一部分可以湊合留著?
徹底重來
檢出到 master 分支,git checkout master;
輸入 git push origin :BRANCH-NAME 或者 git push --delete BRANCH-NAME 來刪除遠程的分支;
輸入 git fetch --prune 來刪除遠程跟蹤分支;
輸入 git branch -D BRANCH-NAME 刪除分支的本地拷貝。
有一部分可以留著
確認在正確的分支,並輸入 git log --oneline;
找到你想要保留的最後一次 commit 的 SHA-1 值。在本例中,假定 file 1 和 2 是要保留的,其他部分不要,所以找到 adding file 2 的 SHA-1 值;
輸入 git reset --hard SHA-1;
輸入 git status 和 ls,注意到現在只有 file 1 和 2 仍保留著;
輸入 git push --force。
推薦閱讀:
※面向對象與函數式編程做對了什麼?
※提醒:別睡了,起來學習吧(cs61a,cs61b Sp18開課了)
※暫時不會再寫關於 Kotlin 的東西了
※PHP 7 新特性(完結篇)