2

Can someone give a clear, simple way to swap the names on 2 branches with Git, with Github as remote repository?

Here's the scenario:

  1. I created a dev branch off master.
  2. After 1 commit on dev, I created branch exp (experiment).
  3. I checked out dev again and made 2 more commits.
  4. Then I realized I really wanted exp to be the branch that made those 2 commits, so I'd like to swap exp and dev

I'm fairly new at this and I've gone through some of the visual Git tutorials and searched this site and Google, but it's still not clear to me the best or intended way to fix this in Git (and particularly - with a Github remote repo)


My Bad attempts to fix this:

I've tried a few things and made a mess of it - renaming local branches with Git Extensions, but not able to get the remote Github repo to reflect that change. I tried making new branches, but can't always get those to reflect in both local and remote (regardless of where I make them).

I finally was able to get everything how I needed it with Git Extensions main pull function with "Prune remote branches", which appears to use fetch with --prune - this reflected remote deletions back to local, and also the push function with some force/delete options enabled.

I thought at first I might just be able to reset/move both branches (i.e. move exp up to dev, then reset exp back to the commit that dev was on (2 back), but when trying to reset in Git Extensions, it asks me to choose a soft, mixed, or hard reset - that made me stop and go the other route of trying to rename/create new branches, etc. Maybe this was the right track - if so, should I have done a soft or hard reset - or doesn't it matter after committing any open changes? I did a lot of searching on that, and even understanding working directory, index, and branch, it still wasn't clear in my case.


Question

There must be better ways to get this done - how can I easily swap two branches (or rename 2 branches so they effectively swap), in a way that all changes are reflected both locally and remotely (on Github)?

I would appreciate any insight on why your method is the right or easiest way to go. Thanks!


Note: I did find this question about renaming master (or any branch) - but there are a lot of steps there. I could do that twice, but I find it hard to believe that is the best way to do this.

ankostis
  • 8,579
  • 3
  • 47
  • 61
LightCC
  • 9,804
  • 5
  • 52
  • 92

4 Answers4

3

Create two new branches exp2, dev2 from exp and dev respectively.

$ git checkout exp
$ git branch exp2          # create new branch 'exp2' from 'exp'

$ git checkout dev
$ git checkout -b dev2     # create and checkout to `dev2` branch

Delete your local and remote dev and exp branches.

$ git branch -D dev        # delete local 'dev' branch
$ git push origin :dev     # delete remote 'dev' branch

$ git branch -D exp        # delete local 'exp' branch
$ git push origin :exp     # delete remote 'exp' branch

Create a new local branch exp from dev2 and push to remote.

# make sure you are in 'dev2' branch

$ git checkout -b exp
$ git push origin exp

Create a new local branch dev from exp2 and push to remote.

$ git checkout exp2        # checkout to 'exp2' so, current branch is 'exp2'
$ git checkout -b dev      # create new branch 'dev' 
$ git push origin dev      # push 'dev' branch to remote 

Now, if all things are ok then delete local exp2 and dev2 branch. (Optional)

$ git branch -D dev2      # delete local 'dev2' branch
$ git branch -D exp2      # delete local 'exp2' branch 
Sajib Khan
  • 22,878
  • 9
  • 63
  • 73
  • Hi Sajib - thanks. This goes beyond what I need for my example, but this shows how to completely swap two branches. This is helpful, if not the simplest answer. – LightCC Aug 08 '17 at 00:24
3

Assume the commit history you described as below:

A---B---…  master
     \
      C---D---E  dev
      |
     exp   

You can use below commands:

git checkout exp
git merge dev
git push origin exp
git checkout dev
git reset --hard head~2
git push -f origin dev

Then the commit history will be:

A---B---…  master
     \
      C    dev
       \
        D---E   exp

Of cause you can rename branch names, but this way is more efficient.

Note: if you are co-work with others and there has new changes on dev branch, you can backup the changes in a new branch such as temp by git pull origin dev and git checkout -b temp origin/dev at first. After swapping your local exp as dev, then you can cherry-pick or merge the changes by other developers from temp to dev.

Marina Liu
  • 36,876
  • 5
  • 61
  • 74
2

Renaming the two branches just to reposition a few commits sounds a bit like picking up a house and spinning it just to unscrew a lightbulb.

I think the easiest thing to do here would be to move the commits rather than trying to rename the branches. One simple way would be to cherry-pick the two commits from dev onto exp, and then to remove the two commits from dev

git checkout exp
git cherry-pick <SHA-1 of first dev commit>
git cherry-pick <SHA-2 of first dev commit>

And then remove the two commits from dev:

git checkout dev
git reset --hard HEAD~2

Note that if you have already pushed dev to GitHub and someone else may have pulled the branch, then you should instead revert the two commits:

git checkout dev
git revert A^..B

Here A is the first commit and B is the second commit. Note that git revert adds a new commit, which in this case will functionally undo the two commits on dev which you want to remove. So dev would end up with three commits, but it would be as if the two commits now on exp were never made on dev.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • Thanks - I didn't even consider the complication of someone else already have pulled. Can you explain why you use the --hard option in the reset? – LightCC Aug 07 '17 at 18:18
  • @LightCC Doing a hard reset moves the HEAD of the branch back twk commits and also resets the stage and working directory to that commit. Hence, it really is like nuking the two commits. – Tim Biegeleisen Aug 07 '17 at 23:19
  • Okay, so the commits are already "safe" because they are in the exp branch, but from the dev branch point of view, you are wanting to completely reset to exp~2, with no staged or unstaged changes. If instead, I wanted to leave those 2 commits worth of changes available to change, restage, and recommit (as a part of the new dev branch, separate from exp), then I could use --soft, right? – LightCC Aug 08 '17 at 00:20
  • @LightCC Yes, doing a soft reset, assuming your current working directory is empty and stage also empty, would be a way to recommit those two commits later, possibly with some new changes added. – Tim Biegeleisen Aug 08 '17 at 01:35
2

The process is much simpler, just use a temporary branch name while renaming, eg. todo-dev:

git branch --move exp todo-dev
git branch --move dev exp
git branch --move todo-dev dev
git push <remote> exp --set-upstream exp   # upstream was `dev` before  
git push <remote> dev --set-upstream dev   # upstream was `exp` before  

# Repeat the `push` commands for any other remote repos.

All the commands above are impervious to the checked-out branch, and do not affect the working-dir or the index (unlike the checkout, reset & cherry-pick commands).

The whole process is the same, regardless of the remote git-server (ie. GitHub, GitLab or just a local clone).

ankostis
  • 8,579
  • 3
  • 47
  • 61