Search code examples
gitmergebranchrebasegit-workflow

How to move where a branch originates from


I feel like I’m missing something basic with Git but is there a way to move where a branch originates from? I’m running into a scenario very often where I create a feature branch off of master, work on it for a few days, then went I push it I need to make sure that any changes that were added to master need to be merged/rebased onto my branch. This seems to make my branch very messy. I’d imagine I could simply change where the branch originates from to where master currently is now as if I just made the branch in the first place (but obviously, I’d need to handle any conflicts that arise). Is there a way to do this or some other process to keep my branch clean?

What I’m hoping for is being able switch from:


a--b--d--f
    \
     c--e--g

to

a--b--d--f
          \
           c--e--g

Edit: Recently, to emulate this, I've been working off of temporary branches, when my work is complete I will create a new branch, and move all commits to that and recommit them all and push. This doesn't work very well if the pull-request reviews take a while. I've also recently tried doing a git pull --rebase upstream master then merging master into the branch. That added tons of other peoples commits to my branch. I'm thinking that the merge screwed things up, but I didn't realize before I pushed and checked the pull-request.


Solution

  • What you're describing is rebasing. You're just doing it in the wrong direction. Let's say master points to commit f and your-branch points to g.

    a---b---d---f  ← master
         \
          c---e---g  ← your-branch
    

    To take your branch and make it "start" at the commit f, you have to rebase your-branch on master. The corresponding command is:

    git rebase master your-branch
    

    Git will first check out the branch you specified in as your second argument (here your-branch). Thus, you can omit the second argument if you already have that branch checked out.

    The first argument will be used to determine the base commit, which is b in this example. Git will use the first common ancestor between the branch you provided and your currently checked out branch.

    Unless you specified --onto, Git will use the first argument again to determine the new base. In this case, that's the commit f. The result is:

    a---b---d---f  ← master
                 \
                  c'--e'--g' ← your-branch
    

    Just keep in mind that the commit hashes will change, since you essentially have new commits. I marked the new commits with a prime (').


    I've also recently tried doing a git pull --rebase upstream master then merging master into the branch.

    You don't want to merge master into your branch after rebasing on it. Rebasing does exactly what you described, and you don't need additional steps.