Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I move pushed commits from one branch to another existing branch?

Tags:

git

git-branch

I have 3 branches: develop, feature-1 and feature-2. I was working on feature-1, then switched to work on feature-2. I then finished work on feature-2, committed and pushed to the repo, then created a merge request for that feature. I then saw that feature-2 contained some commits that were supposed to be in feature-1. Can I move them from feature-2 to feature-1 locally, then have the same moves reflected in the repo?

like image 337
GluePear Avatar asked May 17 '18 12:05

GluePear


People also ask

How do I move a pushed commit to another branch?

Undo and Commit to New Branch Use git log to check how many commits you want to roll back. Then undo the commits with git reset HEAD~N where “N” is the number of commits you want to undo. Then create a new branch and check it out in one go and add and commit your changes again.

Can I move a commit from one branch to another?

If we want to move a commit to an existing branch, we can follow a similar process using merge. In step (1) we make sure we are on the branch where we want the commit to end up. We then merge in the source branch in step (2). At this point, our target branch should have the work we want transferred.

Can a commit be taken from one branch and moved to a different branch in git?

technically you do not move the commit, you create a new one with the same content and git remembers this copy when merging.


2 Answers

git cherry-pick <commit-id> is your friend dear.

  1. Go on feature-2 branch
  2. Copy commit-id(s) you want to move from feature-2 to feature-1
  3. Switch to feature-1 branch
  4. Now cherry pick all the commits you have copied in step-2 above.

    git cherry-pick <commit-id>

    In case you have more than one commits to be moved to feature-1 then put all the commit-ids in sequence of their commit date/time.

    For example:

    git cherry-pick <commit-id-1> <commit-id-2> . . <commit-id-n>

like image 157
beingmanish Avatar answered Nov 04 '22 08:11

beingmanish


Your question says that the commits in question belong in feature-1 and not in feature-2 branch. The accepted answer does not accomplish this.

cherry-pick is an ok way to create a new commit on one branch that duplicates the changes made by a commit on another branch; but it doesn't change the other branch.

So for instance, if you started with

x <--(master)
|\
| A1 -- A2 <--(feature_1)
 \
  B1 -- A3 -- B2 <--(feature_2)

where A3 was meant for feature_1, after following a cherry-pick procedure you will have

x <--(master)
|\
| A1 -- A2 -- A3' <--(feature_1)
 \
  B1 -- A3 -- B2 <--(feature_2)

So feature_1 may look like you want it now, but feature_2 still has some changes it presumably shouldn't have. It's possible that this will cause some trouble when you merge both features into master. (By that I mean, there may be merge conflicts that don't make much sense. git does try to help out here, but it can't be perfect.)

In your question you note that the commits were already pushed, and in response to the cherry-pick answer, you ask if the changes will push cleanly; so I assume you've run into (at least some of) the problems with rewriting history on a branch you've pushed.

While it's true that the results of the cherry-pick will push cleanly, that's because the cherry-pick didn't make all the changes you've asked for (as noted above). It's the fix to feature-2 that really causes a problem with push.

One solution is to use cherry-pick to fix feature-1, then use revert to fix feature-2. In our example, using feature-2~1 as an expression that identifies the commit to be "moved" (you could generally use the commit ID, or an expression appropriate to your real situation):

git checkout feature-1
git cherry-pick feature-2~1
git checkout feautre-2
git revert feature-2~1

gives you

x <--(master)
|\
| A1 -- A2 -- A3' <--(feature_1)
 \
  B1 -- A3 -- B2 -- !A3 <--(feature_2)

This will still push cleanly (because no commit was removed from any branch's history) and both branches will have the right changes now. On the plus side, this makes it less likely that you'd have any merge issues; on the down side, certain rebase operations could now be problematic. There are steps you might take to mitigate that, but if you're worried about only making changes that push cleanly, then you won't be doing that sort of rebase anyway.

If there are many commits you want to "move", then you might want to replace the cherry-pick with an interactive rebase, like this:

git checkout feature-2
git branch temp
git rebase -i feature-1 temp

An editor will open, showing a "todo" list for rebase. Each entry on the list is the instruction for how to handle a commit. Delete the lines for commits you want to "leave behind". (There are other tweaks you could make to how the commits will be represented on feature-1; but that's a long rabbit hole since all you've asked so far is how to "move" the commits, so just these steps will keep them "as is".)

When you save and exit the editor, the rebase will commence, rewriting all of the selected commits. Finish up the update to feature-1 by

git checkout feature-1
git merge temp
git branch -d temp

You'll still need to go to feature-2 to revert the commits that shouldn't be there; you might want to do that in a single command with the -n flag, so that you can create just a single revert commit. (This will have the side-effect of reducing the risk I noted above, of certain rebase operations acting up after you do the revert; but again, I expect you won't be doing those types of rebase anyway given the constraints implied by this question.)

Now some people don't love using revert for this kind of thing, because the history shows what happened - including making the changes and later removing the changes, which may seem annoying since the change should never have been made.

The only way to avoid that is to "rewrite the history" of feature-2, and no matter how you do it, that will not push cleanly. You can get it to push, but in so doing you'll create work for all the other developers who have a copy of feature-2 - and if they do the wrong thing, it will undo your work. So you have to coordinate with everyone else who uses the repo if you want to do a history rewrite. See the git rebase docs under "recovering from upstream rebase" for more information about this.

like image 41
Mark Adelsberger Avatar answered Nov 04 '22 07:11

Mark Adelsberger