git 如何用 revert 回滚代码到某个 commit? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
zeroten
V2EX    git

git 如何用 revert 回滚代码到某个 commit?

  •  
  •   zeroten 2016-08-01 10:47:10 +08:00 34987 次点击
    这是一个创建于 3408 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如有 commit asda21313123,我给它打了 tag v100 ,如果使用git revert git revert v100..HEAD的方式,如果中间有 merge commit 就不行。

    要求不能用 reset 、 rebase 这样重写提交记录的方法。

    第 1 条附言    2016-08-01 11:53:05 +08:00
    要回滚的是主干分之 master , reset 可能会给团队中其他人带来困扰,且 reset 太暴力,操作不当可能丢失提交记录
    第 2 条附言    2016-08-01 11:55:21 +08:00
    现在有
    8
    7
    6
    5
    4
    3
    2
    1
    若干提交, 1 是最前面的,现在想回滚到 4 , git revert git revert 4..8 命令可以把 5678 逐个 revert ,但是如果其中有 merge commit 就不能这么用。那么该怎么做?
    第 3 条附言    2016-08-01 11:57:12 +08:00
    简而言之,就是不修改提交记录的回滚回去
    45 条回复    2021-01-15 11:27:22 +08:00
    jsfaint
        1
    jsfaint  
       2016-08-01 11:00:20 +08:00
    为啥不能用 git reset ?
    git reset --hard 不就是做这事的吗?
    henius
        2
    henius  
       2016-08-01 11:08:59 +08:00
    git reset --hard
    hosiet
        3
    hosiet  
       2016-08-01 11:13:22 +08:00 via Android
    为啥不能用 git reset?

    说实在的,只想检出代码又怕影响历史纪录的话, git checkout 都行,就是不知道你的需求是什么

    如果想用一个提交解决一切, git diff 导出区别再 apply 如何?
    zeroten
        4
    zeroten  
    OP
       2016-08-01 11:39:26 +08:00
    @jsfaint
    @henius
    @hosiet 不想用 reset 是为了避免其他人如果从 v101 checkout 一个分之开发去了,现在 reset 到 v100 ,那么他如果再合并代码不就又会把 v100 带回来或者产生冲突,这些不必要的麻烦。
    zeroten
        5
    zeroten  
    OP
       2016-08-01 11:39:50 +08:00
    @hosiet diff 再 apply 是怎么个方案,可以说具体点么
    Busy
        6
    Busy  
       2016-08-01 11:50:54 +08:00
    你的需求到底是什么,有点看不懂。
    如果要从 v100 从头开始来过, reset/checkout 都行,最好是 checkout 个分支,人家仍然 push 到原分支。
    zeroten
        7
    zeroten  
    OP
       2016-08-01 11:51:51 +08:00
    简而言之, reset 可能会给团队中其他人带来困扰,且 reset 太暴力,操作不当可能丢失提交记录
    zeroten
        8
    zeroten  
    OP
       2016-08-01 11:56:43 +08:00
    @Havee 见问题补充
    zeroch
        9
    zeroch  
       2016-08-01 12:05:47 +08:00
    你要知道, 如果你在 remote master branch 上进行了回滚操作,然后在 push 回到 master 上面.那么, 无论如何你已经和 diverge, *不可避免*的对别人造成影响..

    如果你在 local 的任意 branch 上操作..上面的回复说的, 不论是 reset 还是 checkout 都是可以的。甚至还有一种方法.你先 checkout 1, 然后从 1 到 4 进行 cherry-pick 。 cherry-pick 不会 hash 出新的 commit id 。
    fangdingjun
        10
    fangdingjun  
       2016-08-01 12:26:34 +08:00
    像这样, 用历史文件覆盖当前文件,并产生一个新的 commit

    git checkout -b temp
    git reset --hard c7
    git archive HEAD > /tmp/t.tar
    git checkout master
    tar xf /tmp/t.tar
    git add .
    git commit -m 'reset to c7'
    axb
        11
    axb  
       2016-08-01 12:32:04 +08:00
    xi_lin
        12
    xi_lin  
       2016-08-01 12:42:51 +08:00
    BOYPT
        13
    BOYPT  
       2016-08-01 13:26:37 +08:00
    感觉就像朋友圈里面那些不许用方程解小学数学题,好难~
    networm
        14
    networm  
       2016-08-01 15:48:45 +08:00 via iPhone   1
    git reset --hard 4
    git reset --soft 8
    git commit -m 'Reverted 5 6 7 8'

    其实楼主怕的是丢失提交记录,而不是使用 reset rebase 命令
    julyclyde
        15
    julyclyde  
       2016-08-01 15:52:01 +08:00
    revert 是回滚某个 commit ,不是回滚“到”某个
    你需要 checkout 或者 reset 之类的
    zzzreg
        16
    zzzreg  
       2016-08-01 16:51:34 +08:00
    切个新 branch 再 reset 怎么样?
    pagxir
        17
    pagxir  
       2016-08-01 17:03:48 +08:00 via Android
    这么简单的操作,有你们想的那么复杂吗。
    git rm -r -f *
    git checkout <rev> .
    git commit -m xxxx
    就所有文件恢复到版本 rev 的状态,同时不进行分支修剪。
    zeroten
        18
    zeroten  
    OP
       2016-08-01 17:20:44 +08:00
    @julyclyde 你看我主题中发的 git revert git revert v100..HEAD ,就有了回滚“到”的效果,只是有 merge commit 就不行了
    zeroten
        19
    zeroten  
    OP
       2016-08-01 17:22:06 +08:00
    @BOYPT reset 那些会丢失提交记录,会产生冲突等等
    zeroten
        20
    zeroten  
    OP
       2016-08-01 17:27:05 +08:00
    那些用 reset 、 rebase 的同学就不考虑到团购开发中不可能给所有人强制提交 master 的权限,而且这种操作太危险。而用 revert 或其他不修改提交记录的方式,就可以走正常的分之开发流程。
    @jsfaint @henius @hosiet @Havee @zeroch @fangdingjun @axb @xi_lin @BOYPT @networm @julyclyde @zzzreg @pagxir
    lightening
        21
    lightening  
       2016-08-01 17:51:42 +08:00
    赞同 @networm

    你 reset 后并不 force push ,不会修改 history 的。

    他所做的本质上就是手动提交一个新 commit ,其内容是 revert 你的那些 commits 。

    我稍微修改一下,帮助理解,本质上和 @newworm 是一样的:

    git checkout 4
    # 把你 checkout 的代码状态更新到 4 的状态,此时你是 detached HEAD 状态,没有在任何 branch 上

    git reset --soft <your_branch_name>
    # 把你的 branch 状态回复到原先的 branch 。因为是 soft reset , checkout 的代码还是 4 的状态

    git add .
    git commit -m "Revert 5 6 7 8"
    # 此时再提交一个新的 commit 。由于你的代码是 4 的状态,但是你此时 history 处于 8 的位置,再移交一个 commit 就是 9 了。其内容正好是变回 4 的状态,也就是说实际上 commit 9 正好 revert 了 5 6 7 8.
    clino
        22
    clino  
       2016-08-01 17:58:16 +08:00
    "且 reset 太暴力,操作不当可能丢失提交记录" 怕丢历史就先新建一个 backup 分支
    zxq1002
        23
    zxq1002  
       2016-08-01 18:06:47 +08:00 via Android
    git branch tmp
    git checkout tmp
    git reset --soft 4
    git commit -m "revert from 8 to 4"
    git checkout <your branch>
    git cherry-pick <the hash id of commit: revert from 8 to 4> or git merge tmp
    git branch -d tmp
    zxq1002
        24
    zxq1002  
       2016-08-01 18:11:38 +08:00 via Android
    @zxq1002 不好意思,少了 git reset --soft <the hash id of commit: revert from 8 to 4>
    git commit -m "revert"
    同意 21 楼答案
    jsfaint
        25
    jsfaint  
       2016-08-01 18:11:44 +08:00
    @zeroten reset,rebase 用在本地的 unmerged branch 上有什么关系?
    在远端即使你使用 revert 也依然会对其他人造成困扰的。除非对应的 branch 只有你一个人在用,不过既然只有你一个人用, rebase , reset 又有什么关系呢……
    lightening
        26
    lightening  
       2016-08-01 18:11:59 +08:00   1
    OK 找到一个更清晰的方法:

    git checkout 4 -- ./ # 直接取出 4 的代码,不改变 branch
    git commit -m "Revert 5 6 7 8" # 然后提交 commit 9
    O3YwA1ENkb7i35XJ
        27
    O3YwA1ENkb7i35XJ  
       2016-08-01 18:20:07 +08:00
    @zxq1002 按你的做法, 最终 cherry-pick 的时候, 会得到一个提示:

    nothing to commit, working directory clean

    因为你在 commit 那步 提交的文件与你 原分支上的代码是一样的, 所以最终 cherry-pick 会显示没有什么可拿过来的,
    如果非要拿过来, 请加一个 --allow-empty 参数.
    O3YwA1ENkb7i35XJ
        28
    O3YwA1ENkb7i35XJ  
       2016-08-01 18:40:14 +08:00
    @lightening 你的方法存在问题吧?
    楼主已经说了 他要 revert 的内容中有 merge , 你直接从某个 commit 点提取出来的代码, 并不是 revert 后的结果.
    举个最简单的例子.

    ==10
    ==9
    8===6
    7===5
    ==4
    ==3
    ==2
    ==1

    > 由于 v2 在评论中对格式展示的不好, 所以用 = 号来表示空格, 请自行替换后, 感受一下 git log 目前的情况.

    9 是由 6/8 合并而来, 现在要还原的 commit 为 10,9,6,5

    按你的做法是 checkout 4 -- ./ 然后 commit

    这么做的后果是 8/7 的 commit 没了.

    楼主的情况应该就是这种, 所以 git 要求他, 选择 parent.
    zeroten
        29
    zeroten  
    OP
       2016-08-01 18:53:17 +08:00
    @xqin 那有没有什么好的方法能不收购处理 merge commit 呢?比如“ 2016 年 7 月 1 日 3 点上线的那个版本”,这个版本是明确的,我应该如何能记录这个版本,并且能够方便快速的回滚的,目标是一行命令或者脚本,且不需要人工干预。
    xi_lin
        30
    xi_lin  
       2016-08-01 19:01:55 +08:00
    @zeroten 为啥在 reset 的那个里 @我?我的回复是 revert -m 让你选 parent 啊
    xi_lin
        31
    xi_lin  
       2016-08-01 19:03:23 +08:00
    @zeroten 不过正常来说 master 上的都是 fast forward 的 merge ,用楼上给的 reset soft 也不是不行
    zxq1002
        32
    zxq1002  
       2016-08-01 19:04:22 +08:00 via Andoid
    @xqin 我后面已经补充了,少了两步操作
    O3YwA1ENkb7i35XJ
        33
    O3YwA1ENkb7i35XJ  
       2016-08-01 19:05:46 +08:00
    @zeroten 你不都已经打了 Tag 了吗? 那还 revert 什么?
    你直接从那个 tag 中检出一个分支, 然后你想干嘛干嘛嘛.

    另外代码回滚 是你发布工具的事情 与 git 无关, 如果你代码中有 bug,只管在 git 中修复即可.

    线上的代码如果要回滚的话, 一般情况下 发布系统(至少我们发布系统会)都会有保留之前站点前几个版本的内容, 比如每次使用的时候使用不同的文件夹, 如果要回滚, 直接将站点切回之前的文件夹即可. 根本不需要 git 参与嘛.

    比如当前的代码在 A 目录, 然后发布一次使用 B 目录, 再发一次使用 C 目录,

    如果 C 目前的代码有问题,直接将站点切换回 B 目录即可.
    lightening
        34
    lightening  
       2016-08-01 19:23:32 +08:00
    @xqin 因为楼主一直说是要“回滚到”某个以前的版本,我觉得他其实就是想把所有的 merge 都不要了。

    楼主说“ 2016 年 7 月 1 日 3 点上线的那个版本”这个需求,应该就是所有的 commit 都不要的意思吧。
    caiya21
        35
    caiya21  
       2016-08-01 20:26:21 +08:00
    楼主可以考虑 用下 source tree (逃
    8rB61FLBPVSxW2C8
        36
    8rB61FLBPVSxW2C8  
       2016-08-01 21:09:57 +08:00
    git branch newbranch commitid
    zhx1991
        37
    zhx1991  
       2016-08-01 21:47:35 +08:00
    太长了

    我就一个问题

    中间的提交还要不要
    msg7086
        38
    msg7086  
       2016-08-02 03:39:48 +08:00   3
    重写分支太危险 -> 你需要一个好用的工具。我做历史重写从来没丢过东西。

    至于 reset ,谁告诉你 reset 一定要重写历史的?
    如果你要让线上的版本滚回到精确的某个提交的状态,那么先 checkout 历史提交,然后做 reset mixed 到 HEAD ,再做一次提交就行了,这个提交就包含了两者之间所有更改的 revert 。

    git checkout 4 # 回到历史
    git reset --mixed master # 把历史带到脑袋
    git checkout master # 签出脑袋
    git commit # 把历史和脑袋的 revert diff 提交
    cszhiyue
        39
    cszhiyue  
       016-08-02 09:13:30 +08:00
    想到的方案同样和 @lightening 一致
    @xqin 这个没冲突啊。如果想 revert 10,9,5,6 的同时保留 7,8,直接把 checkout 4 改成 checkout 8 就可以了
    xx314327475
        40
    xx314327475  
       2017-03-22 11:33:41 +08:00
    @msg7086 就服你,比人不服
    Youthink
        41
    Youthink  
       2017-12-21 23:37:13 +08:00
    遇到了和楼主一样的问题。 @networm 的回答帮助了我。
    aoTao
        42
    aoTao  
       2018-01-23 10:35:36 +08:00
    遇到和楼主同样的问题 , 按照 @networm 的方式完美解决!
    njwangchuan
        43
    njwangchuan  
       2018-07-09 14:35:55 +08:00
    用了 @newtorm 的方法感觉挺好,请问有啥副作用没。
    williamwue
        44
    williamwue  
       2018-08-03 10:24:01 +08:00
    @msg7086 非常棒的方案!实测通过
    njwangchuan
        45
    njwangchuan  
       2021-01-15 11:27:22 +08:00
    @msg7086 简单,实用,解决了大问题。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     830 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 27ms UTC 22:06 PVG 06:06 LAX 14:06 JFK 17:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86