首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
git
Pro Git
Atlassian Git Tutorial
Pro Git 简体中文翻译
GitX
V2EX  ›  git

git 怎么删除 指定 commit 快照 ?

  •  
  •   frylkrttj · 81 天前 · 3411 次点击
    这是一个创建于 81 天前的主题,其中的信息可能已经有所发展或是发生改变。

    git reset --hard <commit_id>

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

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

    另外完全删除是不可能的,或者说超级麻烦(危险),比如你提交了一个密码文件,想要删除
        7
    xupefei   81 天前   ♥ 1
    你找的那个教程太坑人了,那不是删单个 commit,而是把那个 commit 之后的全删掉。
    正确的办法是 rebase: https://stackoverflow.com/questions/2938301/remove-specific-commit
        8
    capric   81 天前 via Android
    使用 rebase 交互模式
    rebase -i HEAD~N # 向前 N 个 commit,必须包含你要删除的那些 commit
    d commit_hash # 把你要删除的的 commit 前面的指令修改成 d(drop,删除、丢弃的意思)
    在唤起的编辑器保存退出即可
        9
    xml123   81 天前   ♥ 1
    lz 相问的可能是 revert ?
        10
    ayase252   81 天前   ♥ 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
        11
    yuikns   80 天前
    @xupefei 那个链接表述似乎并没有什么问题。楼主中文欠佳的感觉
        12
    xiri   80 天前 via Android
    求求楼主去把 git book 看完再来提问吧!有中文版的,你的问题基本都能找到答案,,,,,
    https://git-scm.com/book/zh/v2

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

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

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

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

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

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

    我们在使用 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
        34
    frylkrttj   80 天前
    @0xNone #33 你这是单个场景,认真看我#21。

    假设我仓库现在只有两个 commit 快照,恐怕你这方法不适用。
        35
    yuikns   80 天前   ♥ 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 )
        36
    wbswjc   79 天前   ♥ 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
        37
    wbswjc   79 天前   ♥ 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
        38
    fan123199   79 天前
    LZ 到底后续试了之后出现什么问题啊?理论上 rebase -i 是可以解决开头说的问题。
        39
    limuyan44   79 天前 via Android
    revert 呀,干嘛要删除啊....
        40
    frylkrttj   79 天前
    @fan123199 #38 之前用 rebase -i commit_id 认为是删除该 快照,哪知道它弹出编辑器还带一堆备注我看了就懵了根本不知道怎么回事,以为是没用的废话,就关闭保存了,结果不是我要得结果,根本没有删除该快照。所以就再也没考虑这个命令了。

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

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

    现在看你表演了。
        42
    lfzyx   79 天前
        43
    julyclyde   79 天前
    单个 commit 如果没有后继的话,可以删除:没有其它东西指向它,然后 fsck 掉
    如果有后继,那就只能连它带后继一起重做一遍
        44
    fan123199   79 天前
    @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'。因为这是危险动作,需要一堆备注让你看清楚。
        45
    fan123199   79 天前
    @frylkrttj 所以,还是 revert 最靠谱,最推荐。只是不适合强迫症。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1754 人在线   最高记录 4385   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 20ms · UTC 16:41 · PVG 00:41 · LAX 09:41 · JFK 12:41
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1