436

I have worked on a local branch and also pushed the changes to remote.

I want to revert the changes on that branch and do something else on it, but I don't want to lose the work completely. I was thinking of something like create a new branch locally and copy the old branch there, then I can revert the changes and continue working on the old branch.

Is there a better way than this maybe?

Scott Anderson
  • 631
  • 5
  • 26
serengeti12
  • 5,205
  • 4
  • 23
  • 27
  • 27
    4 years later, with Git 2.15 (Q4 2017), you will have `git branch -c A B`. See [my answer below](https://stackoverflow.com/a/46750209/6309) – VonC Oct 14 '17 at 23:13

6 Answers6

668
git checkout old_branch
git branch new_branch

This will give you a new branch "new_branch" with the same state as "old_branch".

This command can be combined to the following:

git checkout -b new_branch old_branch
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 195
    Or even shorter `git checkout -b new_branch` (when you're already on `old_branch`). – Koraktor Feb 21 '13 at 09:55
  • 9
    This just creating the new branch but cannot able to copy the contents from one branch to another branch. When i try this commands it just showing "The branch named **** already exist". – anoop Sep 27 '13 at 14:45
  • 16
    I think if one creates a new branch like this one doesn't instantly have a copy of the old branch but simply a new pointer at the head of the old branch. But when you now do something like rebasing the new branch you should see that the old branch is still in its original state while the new branch is modified. So I think that does what the OP wants. – uli_1973 Sep 30 '13 at 07:54
  • 2
    git checkout old_branch and than git branch new_branch ....Its better to use above command on production, as below command will create new branch and take you to the new branch (change branch as new branch ).... git checkout -b new_branch old_branch – Kiran Jan 22 '18 at 10:00
  • To overwrite a branch, see https://stackoverflow.com/questions/26961371/switch-on-another-branch-create-if-not-exists-without-checking-if-already-exi – MCCCS Feb 25 '19 at 08:39
  • After copying the branch to a new branch, better to use `git status` to see the new files and commit them and update the git with `git commit -m "copy success"` and `git add . ` – Corina Roca Feb 05 '21 at 11:43
110

See second part (since Git 2.23, Q3 2019): git switch -c newBranch oldBranch


With Git 2.15 (Q4 2017), "git branch" learned "-c/-C" to create a new branch by copying an existing one.

See commit c8b2cec (18 Jun 2017) by Ævar Arnfjörð Bjarmason (avar).
See commit 52d59cc, commit 5463caa (18 Jun 2017) by Sahil Dua (sahildua2305).
(Merged by Junio C Hamano -- gitster -- in commit 3b48045, 03 Oct 2017)

branch: add a --copy (-c) option to go with --move (-m)

Add the ability to --copy a branch and its reflog and configuration, this uses the same underlying machinery as the --move (-m) option except the reflog and configuration is copied instead of being moved.

This is useful for e.g. copying a topic branch to a new version, e.g. work to work-2 after submitting the work topic to the list, while preserving all the tracking info and other configuration that goes with the branch, and unlike --move keeping the other already-submitted branch around for reference.

Note: when copying a branch, you remain on your current branch.
As Junio C Hamano explains, the initial implementation of this new feature was modifying HEAD, which was not good:

When creating a new branch B by copying the branch A that happens to be the current branch, it also updates HEAD to point at the new branch.
It probably was made this way because "git branch -c A B" piggybacked its implementation on "git branch -m A B",

This does not match the usual expectation.
If I were sitting on a blue chair, and somebody comes and repaints it to red, I would accept ending up sitting on a chair that is now red (I am also OK to stand, instead, as there no longer is my favourite blue chair).

But if somebody creates a new red chair, modelling it after the blue chair I am sitting on, I do not expect to be booted off of the blue chair and ending up on sitting on the new red one.


Second part: with git 2.23 (Q3 2019), no need to use git branch or the old confusing git checkout: you have git switch.

git switch -c newBranch oldBranch

With Git 2.40 (Q1 2023), 'git branch -c'(man) is more robust and detects a no-op case.

See commit cfbd173 (17 Nov 2022) by Rubén Justo (rjusto).
(Merged by Junio C Hamano -- gitster -- in commit 963f8d3, 19 Dec 2022)

branch: force-copy a branch to itself via @{-1} is a no-op

Signed-off-by: Rubén Justo
Signed-off-by: Taylor Blau

Since 52d59cc ("branch: add a --copy (-c) option to go with --move (-m)", 2017-06-18, Git v2.15.0-rc0 -- merge listed in batch #12) we can copy a branch to make a new branch with the '-c' (copy) option or to overwrite an existing branch using the '-C' (force copy) option.
A no-op possibility is considered when we are asked to copy a branch to itself, to follow the same no-op introduced for the rename (-M) operation in 3f59481 (branch: allow a no-op , 2011-11-25, Git v1.7.9-rc0 -- merge) (branch: allow a no-op "branch -M <current-branch> HEAD", 2011-11-25).
To check for this, in 52d59cc we compared the branch names provided by the user, source (HEAD if omitted) and destination, and a match is considered as this no-op.

Since ae5a6c3 (checkout: implement , 2009-01-17, Git v1.6.2-rc0 -- merge) (checkout: implement "@{-N}" shortcut name for N-th last branch, 2009-01-17) a branch can be specified using shortcuts like @{-1}.
This allows this usage:

$ git checkout -b test
$ git checkout -
$ git branch -C test test  # no-op
$ git branch -C test @{-1} # oops
$ git branch -C @{-1} test # oops

As we are using the branch name provided by the user to do the comparison, if one of the branches is provided using a shortcut we are not going to have a match and a call to git_config_copy_section() will happen.
This will make a duplicate of the configuration for that branch, and with this progression the second call will produce four copies of the configuration, and so on.

Let's use the interpreted branch name instead for this comparison.

The rename operation is not affected.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • The quoted explanation underneath from Junio C Hamano: 'it also updates HEAD to point at the new branch', seems to contradict your statement: 'Note: when copying a branch, you remain on your current branch.' Having tried it on git 2.17.1 I was left on my existing as you say. Therefore that explanation seems incorrect. – Chris R Dec 10 '20 at 14:11
  • 1
    @ChrisR I have added the link to the original Git mailing list thread from which this statement is originating. It was about the *initial* implement of `git branch -c`, which was being fixed, as a result of Junio's comment. – VonC Dec 10 '20 at 14:29
  • Thanks. Good edit too, much clearer now for anyone finding their way to this without having to try it and to see like I did. – Chris R Dec 11 '20 at 09:05
72
git branch copyOfMyBranch MyBranch

This avoids the potentially time-consuming and unnecessary act of checking out a branch. Recall that a checkout modifies the "working tree", which could take a long time if it is large or contains large files (images or videos, for example).

Josh
  • 5,631
  • 1
  • 28
  • 54
Lyle Z
  • 1,269
  • 10
  • 7
  • 2
    Of course, if you have binary files in git, especially large ones, it is likely worthwhile to analyse your strategy for said files. Naturally, unusual cases will exist and having binary files in git would be perfectly acceptable. – reverend Aug 07 '15 at 13:12
0

Given you requested better way options:

One potential flaw with copying branches is that you have to take care about git's fast-forward behaviour if you want to merge into the same parent, or re-introduce changes back into the original branch from the copy.

For instance if you have reverted some commits in the 'original' branch, but now you would like to re-introduce the changes you reverted to the original, you cannot simply merge the copied branch to the parent because git sees those commits already exist (even thought they are reverted later).

Maybe cherry-pick [commit-range] would work in this context & doesn't care about existing hashes shrugs

In my opinion though it would be better to do this.

  1. Create a new branch from current branch HEAD git branch [archive-branch-name]
  2. Find the commit you want to roll back to with git log
  3. Run git reset --head [commit-hash-from-#2]
  4. git push -f origin

Note that you start on the 'original' branch and do not change branches during the steps.

Or even more simply you could just do away with branching altogether and just revert the commits you want to revert, and revert the revert later if you need to

Scott Anderson
  • 631
  • 5
  • 26
0

I want to revert the changes on that branch and do something else on it, but I don't want to lose the work completely.

My intepretation is that you for branch b want to:

  • Make a copy copy-b (say) for future reference
  • Keep working on b, knowing that you have copy-b for future reference

What seems to be implied here is that copy-b will be left alone; it’s only for reference.

So what do you need a branch for? A branch needs to be able to move while a “for reference” ref does not. Do you need the reflog? Well that will expire in 90 days by default, so long-term that doesn’t matter. Maybe you want the branch description or some other config?

If you only want to copy whatever the ref points at then you just need a lightweight tag:

git checkout b
git tag archive/b

Or using git switch:

git switch b
git tag archive/b

And if you have multiple versions:

git tag archive/b-v1

This scheme can be used if one is sending out a “patch series” via email which is reviewed through several rounds.

Some apparent benefits of this scheme:

  1. Might be slightly easier to include or exclude such “for reference” refs with git-clone(1) (using --tags or --no-tags)
  2. You won’t accidentally check them out and start working on them (well, you’ll get a “detached head” warning/note if you do)
  3. Branches are not by default packed using git-pack-refs(1) while tags are (I guess you would have to be a really dedicated archiver in order for this to matter, though…)
Guildenstern
  • 2,179
  • 1
  • 17
  • 39
-1

Checkout to the branch that you want to copy. Then once you are on that branch run: git checkout -b new_branch_name

Josh
  • 24
  • 4
  • 1
    The idea is to phase out the use of the old obsolete and confusing `git checkout` command (which operates both on files and on branches), and instead consider `git switch` for branches only, like the `git switch -c newBranch oldBranch` I mention in [my answer](https://stackoverflow.com/a/46750209/6309) (and `git restore`, to restore files) – VonC Jun 13 '22 at 14:58