How to modify a specified commit?

后端 未结 16 925
清酒与你
清酒与你 2020-11-22 01:53

I usually submit a list of commits for review. If I have the following commits:

  1. HEAD
  2. Commit3
  3. Commit2
相关标签:
16条回答
  • 2020-11-22 02:27

    I solved this,

    1) by creating new commit with changes i want..

    r8gs4r commit 0
    

    2) i know which commit i need to merge with it. which is commit 3.

    so, git rebase -i HEAD~4 # 4 represents recent 4 commit (here commit 3 is in 4th place)

    3) in interactive rebase recent commit will located at bottom. it will looks alike,

    pick q6ade6 commit 3
    pick vr43de commit 2
    pick ac123d commit 1
    pick r8gs4r commit 0
    

    4) here we need to rearrange commit if you want to merge with specific one. it should be like,

    parent
    |_child
    
    pick q6ade6 commit 3
    f r8gs4r commit 0
    pick vr43de commit 2
    pick ac123d commit 1
    

    after rearrange you need to replace p pick with f (fixup will merge without commit message) or s (squash merge with commit message can change in run time)

    and then save your tree.

    now merge done with existing commit.

    Note: Its not preferable method unless you're maintain on your own. if you have big team size its not a acceptable method to rewrite git tree will end up in conflicts which you know other wont. if you want to maintain you tree clean with less commits can try this and if its small team otherwise its not preferable.....

    0 讨论(0)
  • 2020-11-22 02:28

    Interactive rebase with --autosquash is something I frequently use when I need to fixup previous commits deeper in the history. It essentially speeds up the process that ZelluX's answer illustrates, and is especially handy when you have more than one commit you need to edit.

    From the documentation:

    --autosquash

    When the commit log message begins with "squash! …​" (or "fixup! …​"), and there is a commit whose title begins with the same …​, automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified

    Assume you have a history that looks like this:

    $ git log --graph --oneline
    * b42d293 Commit3
    * e8adec4 Commit2
    * faaf19f Commit1
    

    and you have changes that you want to amend to Commit2 then commit your changes using

    $ git commit -m "fixup! Commit2"
    

    alternatively you can use the commit-sha instead of the commit message, so "fixup! e8adec4 or even just a prefix of the commit message.

    Then initiate an interactive rebase on the commit before

    $ git rebase e8adec4^ -i --autosquash
    

    your editor will open with the commits already correctly ordered

    pick e8adec4 Commit2
    fixup 54e1a99 fixup! Commit2
    pick b42d293 Commit3
    

    all you need to do is save and exit

    0 讨论(0)
  • 2020-11-22 02:31

    Run:

    $ git rebase --interactive commit_hash^

    each ^ indicates how many commits back you want to edit, if it's only one (the commit hash that you specified), then you just add one ^.

    Using Vim you change the words pick to reword for the commits you want to change, save and quit(:wq). Then git will prompt you with each commit that you marked as reword so you can change the commit message.

    Each commit message you have to save and quit(:wq) to go to the next commit message

    If you want to exit without applying the changes, press :q!

    EDIT: to navigate in vim you use j to go up, k to go down, h to go left, and l to go right( all this in NORMAL mode, press ESC to go to NORMAL mode ). To edit a text, press i so that you enter the INSERT mode, where you insert text. Press ESC to go back to NORMAL mode :)

    UPDATE: Here's a great link from github listing How to undo (almost) anything with git

    0 讨论(0)
  • 2020-11-22 02:32

    Use the awesome interactive rebase:

    git rebase -i @~9   # Show the last 9 commits in a text editor
    

    Find the commit you want, change pick to e (edit), and save and close the file. Git will rewind to that commit, allowing you to either:

    • use git commit --amend to make changes, or
    • use git reset @~ to discard the last commit, but not the changes to the files (i.e. take you to the point you were at when you'd edited the files, but hadn't committed yet).

    The latter is useful for doing more complex stuff like splitting into multiple commits.

    Then, run git rebase --continue, and Git will replay the subsequent changes on top of your modified commit. You may be asked to fix some merge conflicts.

    Note: @ is shorthand for HEAD, and ~ is the commit before the specified commit.

    Read more about rewriting history in the Git docs.


    Don't be afraid to rebase

    ProTip™:   Don't be afraid to experiment with "dangerous" commands that rewrite history* — Git doesn't delete your commits for 90 days by default; you can find them in the reflog:

    $ git reset @~3   # go back 3 commits
    $ git reflog
    c4f708b HEAD@{0}: reset: moving to @~3
    2c52489 HEAD@{1}: commit: more changes
    4a5246d HEAD@{2}: commit: make important changes
    e8571e4 HEAD@{3}: commit: make some changes
    ... earlier commits ...
    $ git reset 2c52489
    ... and you're back where you started
    

    * Watch out for options like --hard and --force though — they can discard data.
    * Also, don't rewrite history on any branches you're collaborating on.



    On many systems, git rebase -i will open up Vim by default. Vim doesn't work like most modern text editors, so take a look at how to rebase using Vim. If you'd rather use a different editor, change it with git config --global core.editor your-favorite-text-editor.

    0 讨论(0)
  • 2020-11-22 02:32

    Automated interactive rebase edit followed by commit revert ready for a do-over

    I found myself fixing a past commit frequently enough that I wrote a script for it.

    Here's the workflow:

    1. git commit-edit <commit-hash>
      

      This will drop you at the commit you want to edit.

    2. Fix and stage the commit as you wish it had been in the first place.

      (You may want to use git stash save to keep any files you're not committing)

    3. Redo the commit with --amend, eg:

      git commit --amend
      
    4. Complete the rebase:

      git rebase --continue
      

    For the above to work, put the below script into an executable file called git-commit-edit somewhere in your $PATH:

    #!/bin/bash
    
    set -euo pipefail
    
    script_name=${0##*/}
    
    warn () { printf '%s: %s\n' "$script_name" "$*" >&2; }
    die () { warn "$@"; exit 1; }
    
    [[ $# -ge 2 ]] && die "Expected single commit to edit. Defaults to HEAD~"
    
    # Default to editing the parent of the most recent commit
    # The most recent commit can be edited with `git commit --amend`
    commit=$(git rev-parse --short "${1:-HEAD~}")
    message=$(git log -1 --format='%h %s' "$commit")
    
    if [[ $OSTYPE =~ ^darwin ]]; then
      sed_inplace=(sed -Ei "")
    else
      sed_inplace=(sed -Ei)
    fi
    
    export GIT_SEQUENCE_EDITOR="${sed_inplace[*]} "' "s/^pick ('"$commit"' .*)/edit \\1/"'
    git rebase --quiet --interactive --autostash --autosquash "$commit"~
    git reset --quiet @~ "$(git rev-parse --show-toplevel)"  # Reset the cache of the toplevel directory to the previous commit
    git commit --quiet --amend --no-edit --allow-empty  #  Commit an empty commit so that that cache diffs are un-reversed
    
    echo
    echo "Editing commit: $message" >&2
    echo
    
    0 讨论(0)
  • 2020-11-22 02:34

    Came to this approach (and it is probably exactly the same as using interactive rebase) but for me it's kind of straightforward.

    Note: I present this approach for the sake of illustration of what you can do rather than an everyday alternative. Since it has many steps (and possibly some caveats.)

    Say you want to change commit 0 and you are currently on feature-branch

    some-commit---0---1---2---(feature-branch)HEAD
    

    Checkout to this commit and create a quick-branch. You can also clone your feature branch as a recovery point (before starting).

    ?(git checkout -b feature-branch-backup)
    git checkout 0
    git checkout -b quick-branch
    

    You will now have something like this:

    0(quick-branch)HEAD---1---2---(feature-branch)
    

    Stage changes, stash everything else.

    git add ./example.txt
    git stash
    

    Commit changes and checkout back to feature-branch

    git commit --amend
    git checkout feature-branch
    

    You will now have something like this:

    some-commit---0---1---2---(feature-branch)HEAD
               \
                 ---0'(quick-branch)
    

    Rebase feature-branch onto quick-branch (resolve any conflicts along the way). Apply stash and remove quick-branch.

    git rebase quick-branch
    git stash pop
    git branch -D quick-branch
    

    And you end up with:

    some-commit---0'---1'---2'---HEAD(feature-branch)
    

    Git will not duplicate (although I can't really say to what extent) the 0 commit when rebasing.

    Note: all commit hashes are changed starting from the commit we originally intended to change.

    0 讨论(0)
提交回复
热议问题