55

The title is not very clear. What I actually need to do often is the following:

Let's say I have a development going on with several commits c1,c2,... and 3 branches A,B,C

c1--c2--c3--(B)--c4--(A,C)

Branch A and C are at the same commit.

Now I want branch A to go back where B is, so that it looks like this:

c1--c2--c3--(A,B)--c4--(C)

Important is that this has to happen locally and on GitHub.

Michiel van Oosterhout
  • 22,839
  • 15
  • 90
  • 132
user89021
  • 14,784
  • 16
  • 53
  • 65

4 Answers4

76

Use the reset subcommand:

git checkout A
git reset --hard B
git push --force github

As a sidenote, you should be careful when using git reset while a branch has been pushed elsewhere already. This may cause trouble to those who have already checked out your changes.

Bram Schoenmakers
  • 1,599
  • 14
  • 19
  • 4
    If there are any commits on branch A, they will be lost by `git reset --hard B`. If there are commits on branch A, then you should use `git rebase` to relocate the branch. – Tim Henigan May 27 '10 at 17:08
  • What trouble exactly might it cause? – Bjarke Freund-Hansen Mar 02 '11 at 13:12
  • You may throw away a branch head you pushed to the server and is pulled by others in the meantime. The server cannot build on top of this removed head (so the push needs to be forced). And likewise, peer developers also need to force a pull which may be undesired. – Bram Schoenmakers Mar 03 '11 at 21:54
  • push --force causes the HEAD to detach from the commits tail (i.e. previous commits). doesn't it? I think it's worth adding how to fix that too – dragonmnl Feb 06 '17 at 20:47
27

If there are no commits on branch A, then the git reset --hard B solution given by Bram Schoenmakers will work.

However if there are commits are branch A which must be preserved, then the following should do the trick:

  1. Make a backup copy of your repo (just in case)
  2. git checkout A
  3. git rebase -i --onto B SHA1-A^

...where SHA1-A^ is the commit id of the parent of your branch A

See the git rebase man page for details.

NOTE: This will rewrite history (as rebase always does). Special consideration should be made if your A branch was ever pushed to a public repo.

Community
  • 1
  • 1
Tim Henigan
  • 60,452
  • 11
  • 85
  • 78
9

I usually use this sequence and find it the simplest way:

git checkout B
git branch -f A B
Vladyslav Savchenko
  • 1,282
  • 13
  • 10
  • is this force creating an identically named branch, just at an earlier commit? – Skibisky Oct 17 '18 at 09:21
  • This essentially moves branch A to the revision branch B is pointing to. If the result is rejected during push (_Updates were rejected because the tip of your current branch is behind its remote counterpart._), `git push --force` should do the trick (like in the [answer of Bram](https://stackoverflow.com/a/2923142/1811525)). – CodeFox Sep 16 '19 at 12:30
2

Delete the branch both locally and remotely, recreate the branch, push the branch back up to the server.

git branch -d A
git push origin :heads/A
git branch B A
git push origin A:A

Alternately you can use the following command to undo that last commit.

git revert c4

Which will make your timeline look like:

c1--c2--c3--(B)
             \
              c4--(C)
               \
                (^c4)--(A)

where (^c4) is a commit that undoes c4

I don't recommend using rebase or revert on a branch that has been pushed to a remote repo, they can cause tons of trouble for you or anyone else using that repo.

kubi
  • 48,104
  • 19
  • 94
  • 118
  • 1
    Deleting and recreating the remote branch will also cause tons of trouble for anyone using the repo, though. (As I have learned from painful experience.) – ebneter May 27 '10 at 21:35
  • What is the issue? I do this all the time and it never causes any trouble, but now I'm wondering if I've just been getting lucky. – kubi May 28 '10 at 14:50