当前位置:  开发笔记 > 编程语言 > 正文

如何轻松修复过去的提交?

如何解决《如何轻松修复过去的提交?》经验,为你挑选了5个好方法。

我刚刚读过修改git过去提交中的单个文件,但不幸的是,接受的解决方案"重新排序"了提交,这不是我想要的.所以这是我的问题:

我偶尔会在处理(无关)功能时发现我的代码中存在错误.然后快速git blame揭示该错误已经被引入了一些提交之前(我提交了很多,所以通常它不是引入该错误的最新提交).此时,我通常这样做:

git stash                      # temporarily put my work aside
git rebase -i ~1   # rebase one step before the bad commit
                               # mark broken commit for editing
vim          # fix the bug
git add      # stage fixes
git commit -C      # commit fixes using same log message as before
git rebase --continue          # base all later changes onto this

然而,这种情况经常发生,上述序列变得烦人.特别是'互动式底板'很无聊.上面的序列是否有任何快捷方式,这可以让我修改过去的任意提交和分阶段的更改?我完全清楚这会改变历史,但我经常犯错误,所以我真的很喜欢这样的事情.

vim              # fix bug
git add -p       # Mark my 'fixup' hungs for staging
git fixup              # amend the specified commit with staged changes,
                                   # rebase any successors of bad commit on rewritten 
                                   # commit.

也许是一个可以使用管道工具重写提交的智能脚本?



1> Frerich Raab..:

更新的答案

不久之前,--fixup添加了一个新参数git commit,可用于构造一个适合日志消息的提交git rebase --interactive --autosquash.因此,现在修复过去提交的最简单方法是:

$ git add ...                           # Stage a fix
$ git commit --fixup=a0b1c2d3           # Perform the commit to fix broken a0b1c2d3
$ git rebase -i --autosquash a0b1c2d3~1 # Now merge fixup commit into broken commit

原始答案

这是我前一段时间写的一个Python脚本,它git fixup在我原来的问题中实现了我希望的逻辑.该脚本假定您暂存了一些更改,然后将这些更改应用于给定的提交.

注意:此脚本是特定于Windows的; 它使用查找git.exe和设置GIT_EDITOR环境变量set.根据其他操作系统的需要进行调整.

使用这个脚本,我可以准确地实现我要求的'修复损坏的源,阶段修复,运行git fixup'工作流程:

#!/usr/bin/env python
from subprocess import call
import sys

# Taken from http://stackoverflow.com/questions/377017/test-if-executable-exists-in python
def which(program):
    import os
    def is_exe(fpath):
        return os.path.exists(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

if len(sys.argv) != 2:
    print "Usage: git fixup "
    sys.exit(1)

git = which("git.exe")
if not git:
    print "git-fixup: failed to locate git executable"
    sys.exit(2)

broken_commit = sys.argv[1]
if call([git, "rev-parse", "--verify", "--quiet", broken_commit]) != 0:
    print "git-fixup: %s is not a valid commit" % broken_commit
    sys.exit(3)

if call([git, "diff", "--staged", "--quiet"]) == 0:
    print "git-fixup: cannot fixup past commit; no fix staged."
    sys.exit(4)

if call([git, "diff", "--quiet"]) != 0:
    print "git-fixup: cannot fixup past commit; working directory must be clean."
    sys.exit(5)

call([git, "commit", "--fixup=" + broken_commit])
call(["set", "GIT_EDITOR=true", "&&", git, "rebase", "-i", "--autosquash", broken_commit + "~1"], shell=True)


你可以在你的rebase周围使用`git stash`和`git stash pop`,不再需要一个干净的工作目录

2> Kris Jenkins..:

我所做的是:

git add ...           # Add the fix.
git commit            # Committed, but in the wrong place.
git rebase -i HEAD~5  # Examine the last 5 commits for rebasing.

您的编辑器将打开最近5次提交的列表,随时可以插入.更改:

pick 08e833c Good change 1.
pick 9134ac9 Good change 2.
pick 5adda55 Bad change!
pick 400bce4 Good change 3.
pick 2bc82n1 Fix of bad change.

...至:

pick 08e833c Good change 1.
pick 9134ac9 Good change 2.
pick 5adda55 Bad change!
f 2bc82n1 Fix of bad change. # Move up, and change 'pick' to 'f' for 'fixup'.
pick 400bce4 Good change 3.

保存并退出编辑器,修复程序将被压缩回它所属的提交.

在你做了几次之后,你会在睡眠中在几秒钟内完成.交互式变基是真正让我用git卖给我的功能.它对这个以及更多......非常有用


显然你可以将HEAD~5更改为HEAD~n以进一步返回.你不会想干涉你上游的任何历史记录,所以我通常输入'git rebase -i origin/master'来确保我只改变未按下的历史记录.
这很像我一直以来做的事情; FWIW,您可能对`git rebase`的`--autosquash`开关感兴趣,它会自动为您重新编写编辑器中的步骤.请参阅我对脚本的响应,该脚本利用它来实现`git fixup`命令.

3> dschlyter..:

派对有点晚了,但这里有一个解决方案,正如作者想象的那样.

将其添加到.gitconfig:

[alias]
    fixup = "!sh -c '(git diff-files --quiet || (echo Unstaged changes, please commit or stash with --keep-index; exit 1)) && COMMIT=$(git rev-parse $1) && git commit --fixup=$COMMIT && git rebase -i --autosquash $COMMIT~1' -"

用法示例:

git add -p
git fixup HEAD~5

但是,如果您有未分级的更改,则必须在rebase之前存储它们.

git add -p
git stash --keep-index
git fixup HEAD~5
git stash pop

您可以自动修改别名以隐藏,而不是发出警告.但是,如果修复不能完全应用,则需要在修复冲突后手动弹出存储.手动执行保存和弹出似乎更一致,更少混淆.


修改的问题是我不记得该如何拼写。我总是想,是修改还是修改,这不好。

4> Sérgio..:

要修正一个提交:

git commit --fixup a0b1c2d3 .
git rebase --autosquash -i HEAD~2

其中a0b1c2d3是要修复的提交,而2是要更改的+1粘贴的提交数。

注意:不带-i的git rebase --autosquash不起作用,但带-i则起作用,这很奇怪。



5> Deiwin..:

更新:现在可以在这里找到更清晰的脚本版本:https://github.com/deiwin/git-dotfiles/blob/docs/bin/git-fixup.

我一直在寻找类似的东西.但是,这个Python脚本似乎太复杂了,因此我将自己的解决方案拼凑在一起:

首先,我的git别名看起来像那样(从这里借来):

[alias]
  fixup = !sh -c 'git commit --fixup=$1' -
  squash = !sh -c 'git commit --squash=$1' -
  ri = rebase --interactive --autosquash

现在bash函数变得非常简单:

function gf {
  if [ $# -eq 1 ]
  then
    if [[ "$1" == HEAD* ]]
    then
      git add -A; git fixup $1; git ri $1~2
    else
      git add -A; git fixup $1; git ri $1~1
    fi
  else
    echo "Usage: gf  "
  fi
}

此代码首先显示所有当前更改(如果您希望自己暂存文件,则可以删除此部分).然后创建fixup(也可以使用squash,如果这是你需要的)提交.之后,它会启动一个交互式rebase,并--autosquash在您提供的提交的父级作为参数.这将打开您配置的文本编辑器,因此您可以验证所有内容是否符合预期,只需关闭编辑器即可完成此过程.

使用if [[ "$1" == HEAD* ]]部分(从这里借用),因为如果你使用HEAD~2作为你的提交(你想要修改当前更改的提交)引用,那么在创建fixup commit之后HEAD将被替换你需要使用HEAD~3来引用同一个提交.

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有