unpushed - github move commits
Move the most recent commit(s) to a new branch with Git (8)
I'd like to move the last several commits I've committed to master to a new branch and take master back to before those commits were made. Unfortunately, my Git-fu is not strong enough yet, any help?
I.e. How can I go from this
master A - B - C - D - E
newbranch C - D - E / master A - B
The method exposed by sykora is the best option in this case. But sometimes is not the easiest and it's not a general method. For a general method use git cherry-pick:
To achieve what OP wants, its a 2-step process:
Step 1 - Note which commits from master you want on a
git checkout master git log
Note the hashes of (say 3) commits you want on
newbranch. Here I shall use:
Note: You can use the first seven characters or the whole commit hash
Step 2 - Put them on the
git checkout newbranch git cherry-pick 612ecb3 git cherry-pick 453ac3d git cherry-pick 9aa1233
OR (on Git 1.7.2+, use ranges)
git checkout newbranch git cherry-pick 612ecb3~1..9aa1233
git cherry-pick applies those three commits to newbranch.
Much simpler solution using git stash
- Your primary purpose is to roll back
- You want to keep changes but don't particularly care about the individual commits, and
- You haven't pushed yet, and
- You want this to be easy and not complicated with temp branches and other headaches
Then the following is far simpler (starting on branch
master that has three mistaken commits):
git reset HEAD~3 git stash git checkout newbranch git stash pop
What this does, by line number
- Undoes the last three commits (and their messages) to
master, but leaves all working files intact
- Stashes away all the working file changes, making the
masterworking tree equal to the HEAD~3 state
- Switches to an existing branch
- Applies the stashed changes to your working directory and clears the stash
You can now use
git add and
git commit as you normally would. All new commits will be added to
What this doesn't do
- It doesn't leave random temporary branches cluttering your tree
- It doesn't preserve the mistaken commits and commit messages, so you'll need to add a new commit message to this new commit
The OP stated the goal was to "take master back to before those commits were made" without losing changes and this solution does that.
I do this at least once a week when I accidentally make new commits to
master instead of
develop. Usually I have only one commit to rollback in which case using
git reset HEAD^ on line 1 is a simpler way to rollback just one commit.
Don't do this if you pushed master's changes upstream
Someone else may have pulled those changes. If you are only rewriting your local master there's no impact when it's pushed upstream, but pushing a rewritten history to collaborators can cause headaches.
Moving to a new branch
WARNING: This method works because you are creating a new branch with the first command:
git branch newbranch. If you want to move commits to an existing branch you need to merge your changes into the existing branch before executing
git reset --hard HEAD~3 (see Moving to an existing branch below). If you don't merge your changes first, they will be lost.
Unless there are other circumstances involved, this can be easily done by branching and rolling back.
# Note: Any changes not committed will be lost. git branch newbranch # Create a new branch, saving the desired commits git reset --hard HEAD~3 # Move master back by 3 commits (GONE from master) git checkout newbranch # Go to the new branch that still has the desired commits
But do make sure how many commits to go back. Alternatively, you can instead of
HEAD~3, simply provide the hash of the commit (or the reference like origin/master) you want to "revert back to" on the master (/current) branch, e.g:
git reset --hard a1b2c3d4
*1 You will only be "losing" commits from the master branch, but don't worry, you'll have those commits in newbranch!
WARNING: With Git version 2.0 and later, if you later
git rebase the new branch upon the original (
master) branch, you may need an explicit
--no-fork-point option during the rebase to avoid losing the carried-over commits. Having
branch.autosetuprebase always set makes this more likely. See John Mellor's answer for details.
Moving to an existing branch
If you want to move your commits to an existing branch, it will look like this:
git checkout existingbranch git merge master git checkout master git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work. git checkout existingbranch
1) Create a new branch, which moves all your changes to new_branch.
git checkout -b new_branch
2) Then go back to old branch.
git checkout master
3) Do git rebase
git rebase -i <short-hash-of-B-commit>
4) Then the opened editor contains last 3 commit information.
... pick <C's hash> C pick <D's hash> D pick <E's hash> E ...
drop in all those 3 commits. Then save and close the editor.
... drop <C's hash> C drop <D's hash> D drop <E's hash> E ...
6) Now last 3 commits are removed from current branch (
master). Now push the branch forcefully, with
+ sign before branch name.
git push origin +master
Had just this situation:
Branch one: A B C D E F J L M \ (Merge) Branch two: G I K N
git branch newbranch git reset --hard HEAD~8 git checkout newbranch
I expected that commit I would be the HEAD, but commit L is it now...
To be sure to land on the right spot in the history its easier to work with the hash of the commit
git branch newbranch git reset --hard ######### git checkout newbranch
This doesn't "move" them in the technical sense but it has the same effect:
A--B--C (branch-foo) \ ^-- I wanted them here! \ D--E--F--G (branch-bar) ^--^--^-- Opps wrong branch! While on branch-bar: $ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range) A--B--C (branch-foo) \ \ D-(E--F--G) detached ^-- (branch-bar) Switch to branch-foo $ git cherry-pick E..G A--B--C--E'--F'--G' (branch-foo) \ E--F--G detached (This can be ignored) \ / D--H--I (branch-bar) Now you won't need to worry about the detached branch because it is basically like they are in the trash can waiting for the day it gets garbage collected. Eventually some time in the far future it will look like: A--B--C--E'--F'--G'--L--M--N--... (branch-foo) \ \ D--H--I--J--K--.... (branch-bar)
Yet another way to do this, using just 2 commands. Also keeps your current working tree intact.
git checkout -b newbranch # switch to a new branch git branch -f master HEAD~3 # make master point to some older commit
Old version - before I learned about
git branch -f
git checkout -b newbranch # switch to a new branch git push . +HEAD~3:master # make master point to some older commit
Being able to
. is a nice trick to know.
You can do this is just 3 simple step that i used.
1) make new branch where you want to commit you recent update.
git branch <branch name>
2) Find Recent Commit Id for commit on new branch.
3) Copy that commit id note that Most Recent commit list take place on top. so you can find your commit. you also find this via message.
git cherry-pick d34bcef232f6c...
you can also provide some rang of commit id.
git cherry-pick d34bcef...86d2aec
Now your job done. If you picked correct id and correct branch then you will success. So before do this be careful. else another problem can occur.
Now you can push your code