简体   繁体   中英

Rebasing a commit from a branch to another branch

I have a question regarding git rebasing. There are tons of threads out there and I am not sure which one works with my usecase and I don't want to mess the remote branches since I am a beginner.

From what I've seen, I can use the commands:

  • git branch to create or change the branch
  • git rebase -i to rebase interactively
  • git rebase <branch_name>
  • git checkout to switch to the branch

Here is my case:

I have a branch branch_A that is on remote: branch_A

Then, branch_A diverged to a branch branch_B and a branch branch_C (multiple commits)

branch_A - branch_B

branch_A - branch_C

Then, I did 3 commits (D1, D2 and D3) on branch B that I call branch branch_D:

branch_A - branch_B - D1 - D2 - D3 (branch_D)

branch_A - branch_C

I pushed these to remote so this state is on remote.

Now I want to move all the 3 commits from B - D to C - D to get:

branch_A - branch_B

branch_A - branch_C - D1 - D2 - D3 - branch_D

Note: The changes are minor (no conflicts can occur) so I could just make a patch and apply it but I want to improve my level at git.

What I fear is that I accidentally delete A, B, C or D (although I think deleting branch_D is a possibility but I know I can push force). I know I can use gitk --all without pushing to prevent things from getting bad.

I tried several things with git rebase and git rebase -i but it didn't seem to work. Also I know I could git merge, but this is not what I want in this usecase.

A few key concepts:

  • Commits point to their parents.
  • Branches point to a single commit at a time. When we say something is "on a branch", we actually mean "reachable by following parents from that branch pointer".
  • Commits are immutable. When we talk about "moving" or "amending" commits, we actually mean "creating new, similar, commits".
  • Branches are independent - changing branch A has no immediate effect on branch B, or even on a branch called A on a server.

So, as I understand it, your commit graph looks like this:

      A        B       D
      |        v       v
      |  <-x <-x <-x <-x
      v /
... <-x  
        \
         <-x <-x
               ^
               C

What you want to create is this:

      A        B
      |        v
      |  <-x <-x
      v /
... <-x  
        \
         <-x <-x <-x <-x
               ^       ^
               C       D

Where the two new commits pointed at by D have been recreated with a parent of C rather than B. You don't need to touch branches A, B, and C; you just need to rebase branch D.

Until you're confident, you might want to create a backup of the current branch D, in case things go wrong:

git branch D_backup D

Then, the version of the git rebase command I find easiest to understand is "git rebase old_parent up_to_old_commit --onto new_parent", so:

git rebase B D --onto C

That should leave you with:

      A        B       D_backup
      |        v       v
      |  <-x <-x <-x <-x
      v /
... <-x  
        \
         <-x <-x <-x <-x
               ^       ^
               C       D

If it goes wrong, you can replace D with D_backup:

git branch -D D
git branch D D_backup

If it all looks fine, delete the backup, and overwrite the remote copy of branch D:

git branch -D D_backup
git push --force-with-lease origin D

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM