原文 : 与佳期的个人博客(gonghonglou.com)
因为一次 git reset 操作回滚提交差点丢掉近一周的代码,而且还是明天就要提测的紧急项目,慌得一匹。。。
事故过程:
1、从 branchA 分支的 commitA1 节点牵出一个 branchB 分支
2、branchA 分支的 commitA1、commitA2 ... commitAn 提交记录
3、branchB 分支的 commitB1、commitB2 ... commitBn 提交记录
4、branchB 分支开发完成后,打算将 branchA 分支合并到 branchB 分支上
5、合并之后发现有冲突,并且解决起来太麻烦,所以打算取消合并,暂时只提测 branchB 分支的代码,然后执行了回滚操作
因为 branchB 分支只有我一个人在工作,且合并代码的那次提交记录是无用的,所以执行了 git reset
操作,且加了 --hard
(抛弃合并那次的提交) ,并强推到了远程:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git reset --hard 1f88a09e3d359aa2213a0750e32d08f2ff4086e0
HEAD is now at 1f88a09e update
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git push -f
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for feature/917, visit:
remote: http://git.xxxxxxxx.com/ios/TDFMemberPod/merge_requests/new?merge_request%5Bsource_branch%5D=feature%2F917
remote:
To git.xxxxxxxx.com:ios/TDFMemberPod.git
+ 7ff865d7...1f88a09e feature/917 -> feature/917 (forced update)
理想其况下执行上述操作是没问题的,但当时因为 commitAn 的提交信息和 commitBn 的提交信息是一样的,没有仔细查看节点信息,commit 的 hash 值写错了,实际执行的操作是:
git reset --hard commitAn
git push -f
但正确的执行的操作应该是:
git reset --hard commitBn
git push -f
然后发现 branchB 分支上的代码只有 branchA 分支的代码,而原来 branchB 分支的代码被删除了,而且已经推送到了远程,前边说过了 branchB 分支只有我一个人在工作,这下本地和远程都丢失了代码。。。慌得一匹。。。
解决过程:
虽然慌得一匹,但总感觉 git 应该有应对这样操作失误的方法,打电话给师兄求助,解决流程如下。
执行 git reset
操作后,再执行 git log
是看不到回滚的那部分提交的,能看到只是现在分支上存在的提交,只剩下 branchA 分支上的提交:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git log
commit 1f88a09e3d359aa2213a0750e32d08f2ff4086e0 (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20)
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 18:36:14 2018 +0800
update
commit 4ae03f23a72955290f0daffa2ae3696c69067776
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 15:56:46 2018 +0800
update:账单页面 ui修改
commit ef7140f36c99ca3940b95a51a7cda3a88c8efca2
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 14:08:59 2018 +0800
服务端下发
commit 38c67dcf627a3e2c7342dc5ca12c68b2b71a6c7e
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 14:07:03 2018 +0800
......
这时候只有执行 git reflog
命令,可以看到 git reset
回滚的提交:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git reflog
1f88a09e (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20) HEAD@{0}: reset: moving to HEAD
1f88a09e (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20) HEAD@{1}: reset: moving to 1f88a09e3d359aa2213a0750e32d08f2ff4086e0
7ff865d7 HEAD@{2}: checkout: moving from release/0.7.20 to feature/917
1f88a09e (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20) HEAD@{3}: reset: moving to HEAD
1f88a09e (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20) HEAD@{4}: checkout: moving from feature/917 to release/0.7.20
7ff865d7 HEAD@{5}: commit (merge): Merge branch 'release/0.7.20' into feature/917
7d5f5fc3 HEAD@{6}: reset: moving to HEAD
7d5f5fc3 HEAD@{7}: checkout: moving from release/0.7.20 to feature/917
1f88a09e (HEAD -> feature/917, origin/release/0.7.20, origin/feature/917, release/0.7.20) HEAD@{8}: pull origin release/0.7.20: Fast-forward
555bc18b HEAD@{9}: checkout: moving from feature/917 to release/0.7.20
7d5f5fc3 HEAD@{10}: commit: update
65ed2c95 HEAD@{11}: commit: 跳转url
5bcc6ce4 HEAD@{12}: commit: update json/js from setting_model
a519a43a HEAD@{13}: commit: update json/js from setting_model
5562d3a3 HEAD@{14}: commit: 修改报名及预览
52915778 HEAD@{15}: commit: update json/js from setting_model
53f49fe1 HEAD@{16}: commit: 917json拷贝
......
找到 branchB 分支上的 commitBn 提交的 hash 值,再执行 git reset commitBn
,回到合并前的正确的提交节点上:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git reset 7d5f5fc3
Unstaged changes after reset:
M Classes/AccurateMarking/Assets/directPreview.js
D Classes/Assets/917_coupons.js
D Classes/Assets/917_coupons.json
D Classes/Assets/917_register.js
D Classes/Assets/917_register.json
M Classes/Assets/member_base_info.js
M Classes/Assets/member_base_info.json
M Classes/Assets/member_card_detail.js
......
此时查看 git ststus
:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git status
On branch feature/917
Your branch and 'origin/feature/917' have diverged,
and have 19 and 68 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: Classes/AccurateMarking/Assets/directPreview.js
deleted: Classes/Assets/917_coupons.js
deleted: Classes/Assets/917_coupons.json
deleted: Classes/Assets/917_register.js
deleted: Classes/Assets/917_register.json
modified: Classes/Assets/member_base_info.js
modified: Classes/Assets/member_base_info.json
......
modified: TDFMemberPod/Info.plist
modified: TDFMemberPod/ViewController.m
modified: fileCopy/config
Untracked files:
(use "git add <file>..." to include in what will be committed)
Classes/MarketingPlan/
no changes added to commit (use "git add" and/or "git commit -a")
此时虽然节点回到了正确的地方,但是代码还是包含了 branchA 分支上合过来的代码,而这些代码应该是存在了暂存区,所以执行 git log
能看到到提交记录只有 branchA 分支的:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git log
commit 7d5f5fc36a4874200dea0b7e255e654c474eaf0e (HEAD -> feature/917)
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:31:23 2018 +0800
update
commit 65ed2c955a53d0864403ac08609a9367cae6d650
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:17:59 2018 +0800
跳转url
commit 5bcc6ce453bdfe94dc5efac39b46d2123caf5de1
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:17:28 2018 +0800
update json/js from setting_model
......
执行 git reset --hard
命令抛弃 branchA 分支合过来的代码,并回到合并前的正确的提交节点上:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git reset --hard 7d5f5fc3
HEAD is now at 7d5f5fc3 update
执行 git log
能看到现在的提交只包含了 branchB 分支上的提交记录,代码也是正确的:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git log
commit 7d5f5fc36a4874200dea0b7e255e654c474eaf0e (HEAD -> feature/917)
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:31:23 2018 +0800
update
commit 65ed2c955a53d0864403ac08609a9367cae6d650
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:17:59 2018 +0800
跳转url
commit 5bcc6ce453bdfe94dc5efac39b46d2123caf5de1
Author: xxxxxxxx <xxxxxxxx@xxxx.com>
Date: Tue Aug 21 21:17:28 2018 +0800
update json/js from setting_model
......
这时执行 git push -f
强制覆盖远程代码:
yujiaqideMacBook-Pro:TDFMemberPod gonghonglou$ git push -f
Counting objects: 176, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (171/171), done.
Writing objects: 100% (176/176), 35.19 KiB | 2.35 MiB/s, done.
Total 176 (delta 122), reused 5 (delta 5)
remote: Resolving deltas: 100% (122/122), completed with 22 local objects.
remote:
remote: To create a merge request for feature/917, visit:
remote: http://git.xxxxxxxx.com/ios/TDFMemberPod/merge_requests/new?merge_request%5Bsource_branch%5D=feature%2F917
remote:
To git.xxxxxxxx:ios/TDFMemberPod.git
+ 1f88a09e...7d5f5fc3 feature/917 -> feature/917 (forced update)
经验教训
1、git reset --hard
会清除当前节点到回滚节点之间的所有提交,直接回退节点,不留痕迹。
2、执行了 git reset --hard
操作后,是不能直接执行 git push
来推送了,需要加强制命令 git push -f
来覆盖远程代码。
2、即使分支只有一个人在工作,但执行回滚操作是还是应当慎用 git reset
,或者可以使用 git revet
来执行回滚。两者比较直观的区别是 git reset
会抛弃当前节点到将要回滚节点之间的提交,直接回退节点,而 git revet
是将之前的提交操作逆向执行一遍,回到将要回滚的节点的状态,并生成一个新的提交,这样所有的操作都在 git 上有记录。
3、即使错误的执行了 git reset
操作,并强推到了远程,要保护好自己本地的工作目录,通过 git reflog
命令查看 git reset
操作,找到之前的节点重新 git reset
一次。
4、如果本地工作目录缺失,只能通过共同工作于该分支的同事的本地记录来尽量挽回损失了,如果有共同工作于该分支的同事的话。
5、git:https://git-scm.com/book/zh/v2
后记
小白出手,请多指教。如言有误,还望斧正!
转载请保留原文地址:http://gonghonglou.com/2018/08/21/git-reset-accident/