moving committed (but not pushed) changes to a new branch after pull
GitGit Problem Overview
I've done a fair bit of work ("Your branch is ahead of 'origin/master' by 37 commits.") which really should have gone into its own branch rather than into master
. These commits only exist on my local machine and have not been pushed to origin
, but the situation is complicated somewhat in that other devs have been pushing to origin/master
and I've pulled those changes.
How do I retroactively move my 37 local commits onto a new branch? Based on the docs, it appears that git rebase --onto my-new-branch master
or ...origin/master
should do this, but both just give me the error "fatal: Needed a single revision". man git-rebase
says nothing about providing a revision to rebase
and its examples do not do so, so I have no idea how to resolve this error.
(Note that this is not a duplicate of https://stackoverflow.com/questions/1394797/git-how-to-move-existing-work-to-new-branch or https://stackoverflow.com/questions/556923/git-how-to-merge-my-local-working-changes-into-another-branch as those questions deal with uncommitted changes in the local working tree, not changes which have been committed locally.)
Git Solutions
Solution 1 - Git
This should be fine, since you haven't pushed your commits anywhere else yet, and you're free to rewrite the history of your branch after origin/master
. First I would run a git fetch origin
to make sure that origin/master
is up to date. Assuming that you're currently on master
, you should be able to do:
git rebase origin/master
... which will replay all of your commits that aren't in origin/master
onto origin/master
. The default action of rebase is to ignore merge commits (e.g. those that your git pull
s probably introduced) and it'll just try to apply the patch introduced by each of your commits onto origin/master
. (You may have to resolve some conflicts along the way.) Then you can create your new branch based on the result:
git branch new-work
... and then reset your master
back to origin/master
:
# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master
When doing this kind of manipulating branches with git branch
, git reset
, etc. I find it useful to frequently look at the commit graph with gitk --all
or a similar tool, just to check that I understand where all the different refs are pointing.
Alternatively, you could have just created a topic branch based on where your master is at in the first place (git branch new-work-including-merges
) and then reset master
as above. However, since your topic branch will include merges from origin/master
and you've not pushed your changes yet, I'd suggest doing a rebase so that the history is tidier. (Also, when you eventually merge your topic branch back to master, the changes will be more obvious.)
Solution 2 - Git
If you have a low # of commits and you don't care if these are combined into one mega-commit, this works well and isn't as scary as doing git rebase
:
unstage the files (replace 1 with # of commits)
git reset --soft HEAD~1
create a new branch
git checkout -b NewBranchName
add the changes
git add -A
make a commit
git commit -m "Whatever"
Solution 3 - Git
I stuck with the same issue. I have found easiest solution which I like to share.
-
Create new branch with your changes.
git checkout -b mybranch
-
(Optional) Push new branch code on remote server.
git push origin mybranch
-
Checkout back to master branch.
git checkout master
-
Reset master branch code with remote server and remove local commit.
git reset --hard origin/master
Solution 4 - Git
One more way assume branch1 - is branch with committed changes branch2 - is desirable branch
git fetch && git checkout branch1
git log
select commit ids that you need to move
git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push
Now revert unpushed commits from initial branch
git fetch && git checkout branch1
git reset --soft HEAD~1
Solution 5 - Git
Alternatively, right after you commit to the wrong branch, perform these steps:
git log
git diff {previous to last commit} {latest commit} > your_changes.patch
git reset --hard origin/{your current branch}
git checkout -b {new branch}
git apply your_changes.patch
I can imagine that there is a simpler approach for steps one and two.
Solution 6 - Git
What about:
- Branch from the current HEAD.
- Make sure you are on master, not your new branch.
git reset
back to the last commit before you started making changes.git pull
to re-pull just the remote changes you threw away with the reset.
Or will that explode when you try to re-merge the branch?
Solution 7 - Git
Here is a much simpler way:
-
Create a new branch
-
On your new branch do a
git merge master
- this will merge your committed (not pushed) changes to your new branch -
Delete you local master branch
git branch -D master
Use-D
instead of-d
because you want to force delete the branch. -
Just do a
git fetch
on your master branch and do agit pull
on your master branch to ensure you have your teams latest code.
Solution 8 - Git
A simpler approach, which I have been using (assuming you want to move 4 commits):
git format-patch HEAD~4
(Look in the directory from which you executed the last command for the 4 .patch
files)
git reset HEAD~4 --hard
git checkout -b tmp/my-new-branch
Then:
git apply /path/to/patch.patch
In whatever order you wanted.
Solution 9 - Git
-
Checkout fresh copy of you sources
git clone ........
-
Make branch from desired position
git checkout {position}
git checkout -b {branch-name}
-
Add remote repository
git remote add shared ../{original sources location}.git
-
Get remote sources
git fetch shared
-
Checkout desired branch
git checkout {branch-name}
-
Merge sources
git merge shared/{original branch from shared repository}
Solution 10 - Git
For me this was the best way:
- Check for changes and merge conflicts
git fetch
- Create a new branch
git branch my-changes
and push to remote - Change upstream to new created branch
git master -u upstream-branch remotes/origin/my-changes
- Push your commits to the new upstream branch.
- Switch back to previous upstream
git branch master --set-upstream-to remotes/origin/master