ChatGPT解决这个技术问题 Extra ChatGPT

moving committed (but not pushed) changes to a new branch after pull

git

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 Move existing, uncommited work to a new branch in Git or How to merge my local uncommitted changes into another Git branch? as those questions deal with uncommitted changes in the local working tree, not changes which have been committed locally.)

Check out this solution. Seems to be easy and clean.

M
Mark Longair

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 pulls 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.)


@Olie: No, the answer is correct under the assumptions in the question and those I set out at the top of the answer. The commits that should be on a separate new branch are already in master; the rebase rewrites the master branch so that the new commits are linearly on top of origin/master, then git branch new-work creates a new-work branch pointing at the tip of master (the current branch) without switching the current branch to new-work. So now new-work contains all the new commits. Then the reset moves the current branch (still master) back to origin/master.
@Quintesse: I'm very sorry if you've lost work, but I'm sure this answer is correct for the situation described by the original questioner. (I've just replied to Olie's remarks hopefully clarifying.) Anyway, just in case it helps to get your work back, I should say that if your work was committed within the last few days (one of the assumption in this question and answer) you should be easily able to retrieve it via the git reflog.
@Olie: perhaps a better way of explaining: branches in git are just like labels that point at a particular commit; they're automatically moved to new commits if you create them while on that branch or can be moved with git reset and various other ways. The git branch new-work is just saying "create a branch pointing at this commit while I remain on my current branch (which is master in this case)". So there's no need to have a command that moves the commits from master to the new branch - you just create a new branch there and when you reset master the new branch is left where master was
a bit late to the party but @Olie, just because git status when on the new branch doesn't show the commits ahead of master doesn't mean they are not actually there (assuming that's why you were worried). Try pushing the new branch to origin: you will see the commits are there
@FélixGagnon-Grenier, don't worry about "late" -- there are always people looking up old questions and every clarification helps. Thanks! :)
S
Stachu

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"

To show an easy-to-understand graph, please use git log --all --decorate --oneline --graph.
Hey @EliuX - I'm missing the relevancy here. Can you expand?
This is something useful to check if you got the wanted result in what you did
Thank u!! this is a very simple solution and it worked perfectly!!
Not sure what went wrong but I just lost some work doing this. My work was lost when I switched to the new branch - all changes were gone at this point.
A
Ariel

I stuck with the same issue. I have found easiest solution which I like to share.

1) Create new branch with your changes.

git checkout -b mybranch

2) (Optional) Push new branch code on remote server.

git push origin mybranch

3) Checkout back to master branch.

git checkout master

4) Reset master branch code with remote server and remove local commit.

git reset --hard origin/master

That's really the easiest way
You can leave out step 2. I assume that in the time since the top answer, git has changed and this prcedure was not allowed before.
This is the best answer in my opinion.
This answer needs to move to the top. Thank you.
Wanted to expand on why this works. You have a set of commits that were committed to your local master but not updated on the origin. Then you create a branch from your local update, which reflects all the new changes. When you switch back to the master and hard reset it, it resets back to the origin's master. Your new branch still has the changes it inherited from the local master prior to reset. The new branch doesn't get reset along with the local master. If you're doing this for the first time, you might consider backing up your repo and confirm your changes are in your backup.
A
Andriy

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

Cherry-pick is really the best "copy/move a single commit" command, esp. when history is baggage for your purposes.
This is so far the most convenient answer to the question. Thank you for the command!
can you update your last comment where 1 or n is the number of unpushed commits? This is still a really good solution for this question.
t
testing

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.


T
Tim Keating

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?


Ah, this is basically option B described by @Mark-Longair above
A
A Kok

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 a git pull on your master branch to ensure you have your teams latest code.


The merge from the local master branch to the target branch is a great tip. Deleting and re-pulling the master branch is unnecessary. Just git reset --hard origin/master to discard the unpushed change in your master branch.
u
user1429980

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.


J
John Conde

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}


S
Sebastian

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