翻译自 Git Out Of Trouble。
搭建练习环境
- 在 Github.com 上创建仓库并 clone 到本地;
- 创建一个新分支,叫作
test
; 创建一系列 commit,可使用如下脚本:
Bash
for d in {1..6}; do touch file$d.md; git add file$d.md; git commit -m "adding file $d"; done
PowerShell
for ($d=1; $d -le 6;$d++) { touch file$d.md; git add file$d.md; git commit -m "adding file$d.md"; }
创建了太多细碎的 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
。