git 怎么删除 指定 commit 快照 ? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
frylkrttj
V2EX    git

git 怎么删除 指定 commit 快照 ?

  •  
  •   frylkrttj 2019 年 1 月 27 日 7681 次点击
    这是一个创建于 2539 天前的主题,其中的信息可能已经有所发展或是发生改变。

    git reset --hard <commit_id>

    我运行该命令为什么不是删除这个快照而是调到这个快照了。前几个小时实验的,应该不会记错。

    45 条回复    2019-01-29 11:06:26 +08:00
    akatquas
        1
    akatquas  
       2019 年 1 月 27 日 via iPhone
    rebase ?
    frylkrttj
        2
    frylkrttj  
    OP
       2019 年 1 月 27 日
    frylkrttj
        3
    frylkrttj  
    OP
       2019 年 1 月 27 日
    @ akatquas 找过好多教程了,rebase 也试过了总不是删除我指定的那个 commit,我还想同时删除多个 commit 不知道怎么做。
    des
        4
    des  
       2019 年 1 月 27 日 via Android
    “彻底回退到某个版本”
    是退回到这个版本,不是上一个
    你应该这样,不过新手不建议,不然怎么恢复都不知道
    git reset --hard hash^
    CRVV
        5
    CRVV  
       2019 年 1 月 27 日 via Android
    des
        6
    des  
       2019 年 1 月 27 日 via Anroid
    @frylkrttj

    另外完全删除是不可能的,或者说超级麻烦(危险),比如你提交了一个密码文件,想要删除
    xupefei
        7
    xupefei  
       2019 年 1 月 27 日   1
    你找的那个教程太坑人了,那不是删单个 commit,而是把那个 commit 之后的全删掉。
    正确的办法是 rebase: https://stackoverflow.com/questions/2938301/remove-specific-commit
    capric
        8
    capric  
       2019 年 1 月 27 日 via Android
    使用 rebase 交互模式
    rebase -i HEAD~N # 向前 N 个 commit,必须包含你要删除的那些 commit
    d commit_hash # 把你要删除的的 commit 前面的指令修改成 d(drop,删除、丢弃的意思)
    在唤起的编辑器保存退出即可
    xml123
        9
    xml123  
       2019 年 1 月 27 日   1
    lz 相问的可能是 revert ?
    ayase252
        10
    ayase252  
       2019 年 1 月 27 日   1
    rebase -i
    reset --hard 是将 HEAD (分支的指针),索引(暂存区)以及工作目录全部恢复到指定 commit
    https://git-scm.com/book/zh/v2/Git-%E5%B7%A5%E5%85%B7-%E9%87%8D%E7%BD%AE%E6%8F%AD%E5%AF%86
    yuikns
        11
    yuikns  
       2019 年 1 月 28 日
    @xupefei 那个链接表述似乎并没有什么问题。楼主中文欠佳的感觉
    xiri
        12
    xiri  
       2019 年 1 月 28 日 via Android
    求求楼主去把 git book 看完再来提问吧!有中文版的,你的问题基本都能找到答案,,,,,
    https://git-scm.com/book/zh/v2

    你看不懂 git 的原理没关系,至少把 git book 上的操作过一遍吧,,,,,
    frylkrttj
        13
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @capric 跳出编辑器的时候那么多备注我就懵了
    frylkrttj
        14
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @xiri 很多看不懂 #12
    Yggdroot
        15
    Yggdroot  
       2019 年 1 月 28 日 via Android
    @des 你的回答是第一个正确回答,直接被提问者无视了。
    frylkrttj
        16
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @Yggdroot #15 每条回复我都看了 ,@akatquas #1 的回复我发帖前也找过教程 试过 rebase 没达到我删除 commit 的目的。

    看了大家的回复,感觉删除 commit 比学习 git 入门教程还难。
    youstu
        17
    youstu  
       2019 年 1 月 28 日
    rebase 交互模式可以删除
    frylkrttj
        18
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @youstu #17 看大家的回复跟我的测试结果:删除 commit 是复杂的,因为有不同情况的 commit 不知道我实验的时候是什么情况的 commit 应该用什么样的删除方式。反正 rebase 我试过一次不行。
    thinkmore
        19
    thinkmore  
       2019 年 1 月 28 日
    一般回退代码使用 reset 或者 revert 更多一些吧.其实就就算是 rebase -i,也只是复制你需要的节点形成新的分支而已,而你不需要的节点仍然是不会被删除的.也不太建议删除某一个 commit object
    SakuraKuma
        20
    SakuraKuma  
       2019 年 1 月 28 日   1
    rebase -i 呀..

    https://learngitbranching.js.org/ 推荐个学习地..
    frylkrttj
        21
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @thinkmore @thinkmore @youstu
    我找的有些教程说,删除中间的 commit 其实是合并,那么问题来了,我到底找合并还是删除 commit 的方法。

    我自己实验的结果:删除 头部 commit, 跟中部 commit,跟尾部 commit,都是不一样的。

    谁可以把这个说的清楚! @all
    youstu
        22
    youstu  
       2019 年 1 月 28 日   1
    @frylkrttj
    不熟悉当然就觉得复杂。 也就看你要达到什么目的,如果你只是想把某几次提交回退,revert 就好。如果你是想让你的 log 好看,让某个 commit 消失,rebase 交互就可以达到目的。 至于 reset hard,你可以先 checkout 一个分支备份当前分支,然后 reset hard 到你想删除的前一个 commit,然后从备份分支上把之后的提交全部 pick 过来,中间那个 commit 也就看不见了,实际上跟 rebase 是一样的。
    youstu
        23
    youstu  
       2019 年 1 月 28 日
    建议把教程看一遍吧: https://git-scm.com/book/zh/v2
    thinkmore
        24
    thinkmore  
       2019 年 1 月 28 日
    Hilong
        25
    Hilong  
       2019 年 1 月 28 日 via Android
    https://juejin.im/entry/5b0c0dac6fb9a00a2d3970e3 看看我这篇文章?写了怎么删除特定提交,就是通过 rebase,带截图操作的。
    boileryao
        26
    boileryao  
       2019 年 1 月 28 日 via Android
    说一个不用 rebase 的方法吧
    对于 ABCDE 五个 commit,想删掉 B,可以从 A checkout 新分支然后 cherry-pick C..E,这个新分支就已经把 B 删掉了。

    删掉一个 commit 很可能会丢数据,尽量 revert 或者通过新的提交“抵消”掉原来的更改
    justicelove
        27
    justicelove  
       2019 年 1 月 28 日
    git revert commit
    itskingname
        28
    itskingname  
       2019 年 1 月 28 日 via iPhone
    https://www.kingname.info/2015/01/08/清空 Github 上某个文件的历史 /
    RoshanWu
        29
    RoshanWu  
       2019 年 1 月 28 日
    revert 是正解,但可能会产生冲突。所以简单的建议 revert,复杂的建议 rebase。
    lazyfighter
        30
    lazyfighter  
       2019 年 1 月 28 日
    rebase
    capric
        31
    capric  
       2019 年 1 月 28 日
    @frylkrttj 退出的时候,自动生成的备注是 commit msg,是可以全部删除,自己编辑的,也可以保留一部分,删除不要的
    lyb11232345688
        32
    lyb11232345688  
       2019 年 1 月 28 日
    git revert 取消某次提交。 删除是没有的,除非你重写提交记录
    0xNone
        33
    0xNone  
       2019 年 1 月 28 日
    你说的是这个吗?

    我们在使用 git 的时候可能会出现提交了错误的版本,这时候我们将代码修改完成了,需要覆盖之前错误的版本,这时候就可以使用一些小技巧。

    注意: 操作会覆盖掉错误版本之后其他人提交的 commit,使用需谨慎

    使用 git pull 保持代码同步状态
    设置 git reset <commit-id> 当前 git 版本指针到错误的版本上
    使用 git stash 错误版本之后的修改,以及我们修改的内容
    使用 git push --force 强制覆盖当前远程服务器上的 commit 历史
    使用 git stash pop,释放暂存的修改,或继续修改代码
    接下来就是一套连招,git add . -> git commit -m "message" -> git push
    frylkrttj
        34
    frylkrttj  
    OP
       2019 年 1 月 28 日
    @0xNone #33 你这是单个场景,认真看我#21。

    假设我仓库现在只有两个 commit 快照,恐怕你这方法不适用。
    yuikns
        35
    yuikns  
       2019 年 1 月 28 日   1
    commit 本质是计算上一个和当前两个版本得到 diff,然后生成的 patch。 第一个 commit 的 diff 是从 orphan 开始算。see https://git-scm.com/docs/git-checkout/1.7.3.1#git-checkout---orphan

    因此“删除”最近一个或若干 commit,简单回滚即可。( reset )
    “删除”某个中间的 commit,后面其实全部改了,只是用 rebase 可以快速编辑一下某几个 commit,然后后面 replay 一下。但实际上 sha1 全变了。
    “删除”第一个 commit,那么就需要重开一个 branch, 从什么都没有开始做。

    git checkout --orphan brand-new-branch [first-sha-1, in case you need to edit]

    replay 也不能用 merge 了,因为它们并没有共同祖先节点。非要用也可以用 cherry-pick ( https://git-scm.com/docs/git-cherry-pick )
    wbswjc
        36
    wbswjc  
       2019 年 1 月 29 日   1
    # 如果你想要删除该提交及其中内容:

    你需要 rebase 中的 drop 操作。

    git 仓库中有 a, b, c, d 4 个文件,依次提交,形成以下内容:

    $ git log
    > commit f3fe836c34642927f57e8f2e6cc8a62382c93c0c
    > d
    > commit 0e4f4862a0ab3256d28ced2f26950e2e4312c5b4
    > c
    > commit a4c409545f056bb6a21f9f82d2749f6faadde70a
    > b
    > commit f3134e02ebfe4d5b70999c3dc03c8f31161cf209
    > a

    以首个提交,即 a 为基准,进入 rebase 模式:

    $ git rebase -i f313
    > pick a4c4095 b
    > pick 0e4f486 c
    > pick f3fe836 d

    修改 rebase 策略如下,表示删除第 3 次提交,即 c:
    > pick a4c4095 b
    > drop 0e4f486 c
    > pick f3fe836 d

    :wq 或 :x 退出 vim,开始 rebase:

    因为只有一个 drop 操作,且没有影响其后任何一个 commit,所以直接全部成功:

    > Successfully rebased and updated refs/heads/master.

    这时候:

    $ git log
    > commit 7eafc41ab349feed33c060e5898278509a71d373
    > d
    > commit a4c409545f056bb6a21f9f82d2749f6faadde70a
    > b
    > commit f3134e02ebfe4d5b70999c3dc03c8f31161cf209
    > a
    wbswjc
        37
    wbswjc  
       2019 年 1 月 29 日   1
    # 如果你想要删除该提交,不过保留其修改的文件:

    你需要 rebase 中的 squash 操作。

    git 仓库中有 a, b, c, d 4 个文件,依次提交,形成以下内容:

    $ git log
    > commit f3fe836c34642927f57e8f2e6cc8a62382c93c0c
    > d
    > commit 0e4f4862a0ab3256d28ced2f26950e2e4312c5b4
    > c
    > commit a4c409545f056bb6a21f9f82d2749f6faadde70a
    > b
    > commit f3134e02ebfe4d5b70999c3dc03c8f31161cf209
    > a

    以首个提交,即 a 为基准,进入 rebase 模式:

    $ git rebase -i f313
    > pick a4c4095 b
    > pick 0e4f486 c
    > pick f3fe836 d

    修改 rebase 策略如下,表示把 c 并入其前一个 commit,即 b:
    > pick a4c4095 b
    > squash 0e4f486 c
    > pick f3fe836 d

    :wq 或 :x 退出 vim,开始 rebase:

    因为只有一个 squash 操作,所以直接进入该操作:

    > # This is a combination of 2 commits.
    > # This is the 1st commit message:
    > b
    > # This is the commit message #2:
    > c

    可以修改 b 和 c 合并( squash )后的提交信息,修改完(也可不改)后 :wq 或 :x 退出。

    后面没有其他操作,所以成功:

    > Successfully rebased and updated refs/heads/master.

    这时候:

    $ git log
    > commit db58ecd2a2cd017a34274781dc8b8c61531147b9
    > d
    > commit 0baa7789a1533c9178874d2ab3b93c44f2adf1b3
    > b
    > c
    > commit f3134e02ebfe4d5b70999c3dc03c8f31161cf209
    > a
    fan123199
        38
    fan123199  
       2019 年 1 月 29 日
    /div>
    LZ 到底后续试了之后出现什么问题啊?理论上 rebase -i 是可以解决开头说的问题。
    limuyan44
        39
    limuyan44  
       2019 年 1 月 29 日 via Android
    revert 呀,干嘛要删除啊....
    frylkrttj
        40
    frylkrttj  
    OP
       2019 年 1 月 29 日
    @fan123199 #38 之前用 rebase -i commit_id 认为是删除该 快照,哪知道它弹出编辑器还带一堆备注我看了就懵了根本不知道怎么回事,以为是没用的废话,就关闭保存了,结果不是我要得结果,根本没有删除该快照。所以就再也没考虑这个命令了。

    我一直以为删除一个 commit_id 应该跟 rm 删除一个文件一样,看来不是。 @all 请问你有没有直接删除一个快照的命令。

    @wbswjc #37 #38 的回复让我知道那一堆备注是怎么回事了。不这样删除一个快照也太绕了吧,正常人的脑子都不会想到 rebase -i commit_id 选中的这个 commit_id 不是用来删除的。特别鸣谢 @wbswjc
    frylkrttj
        41
    frylkrttj  
    OP
       2019 年 1 月 29 日
    @limuyan44
    A,B,C 三个 commit 其中 A 是几乎空白的提交,而 B 是不小心用了 "git add ." 把密码本提交到了 B,于是我删除了密码本文件又提交了一个 C 快照。

    现在看你表演了。
    lfzyx
        42
    lfzyx  
       2019 年 1 月 29 日
    julyclyde
        43
    julyclyde  
       2019 年 1 月 29 日
    单个 commit 如果没有后继的话,可以删除:没有其它东西指向它,然后 fsck 掉
    如果有后继,那就只能连它带后继一起重做一遍
    fan123199
        44
    fan123199  
       2019 年 1 月 29 日
    @frylkrttj 并没有一个删除 commit 的命令(除了最近一个)。因为删除单个 commit 可能会对后续 commit 有影响,必须要 rebase 一条龙解决。

    假设有三个 commit,A->B->C,改动分别是往文件中写入 a,b,c 字符。假设按你的理解要删去 B,也就是删去加入 b 这个字符。 那么这时 C 其实无法存在的,因为你删去了 B,也就是没有 b,而 C 是在 ab 上加入 c,没法简单变成 A->C。 所以 rebase -i <commit>的内核是, 让你重写所有那个 commit 之后的所有记录。如果按 hash 值来看,rebase 后的 C 并不是 C,而是 C'。你删去 B 后的历史应该是 A->C'。因为这是危险动作,需要一堆备注让你看清楚。
    fan123199
        45
    fan123199  
       2019 年 1 月 29 日
    @frylkrttj 所以,还是 revert 最靠谱,最推荐。只是不适合强迫症。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2674 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 31ms UTC 11:39 PVG 19:39 LAX 03:39 JFK 06:39
    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