How can I easily fixup a past commit?

前端 未结 12 2334
执笔经年
执笔经年 2020-12-02 03:48

I just read amending a single file in a past commit in git but unfortunately the accepted solution \'reorders\' the commits, which is not what I want. So here\'s my question

12条回答
  •  一向
    一向 (楼主)
    2020-12-02 04:41

    UPDATED ANSWER

    A while ago, a new --fixup argument was added to git commit which can be used to construct a commit with a log message suitable for git rebase --interactive --autosquash. So the simplest way to fixup a past commit is now:

    $ 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
    

    ORIGINAL ANSWER

    Here's a little Python script I wrote a while ago which implements this git fixup logic I hoped for in my original question. The script assumes that you staged some changes and then applies those changes to the given commit.

    NOTE: This script is Windows-specific; it looks for git.exe and sets the GIT_EDITOR environment variable using set. Adjust this as needed for other operating systems.

    Using this script I can implement precisely the 'fix broken sources, stage fixes, run git fixup ' workflow I asked for:

    #!/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)
    

提交回复
热议问题