80

git checkout -b foo switches on foo branch (even if it doesn't exist, it is created), but if the foo branch already exists it throws an error like this:

fatal: A branch named 'foo' already exists.

What's the command that does the following check?

  • if the branch already exists, just switch on it (git checkout foo)
  • if the branch doesn't exist, create it and switch on it (git checkout -b foo)
dreftymac
  • 27,818
  • 25
  • 108
  • 169
Ionică Bizău
  • 93,552
  • 74
  • 254
  • 426

5 Answers5

92

Update Q3 2019 (Git 2.23): there now actually is a git switch command!

git switch -c aBranch 

You would need a similar alias though:

switchoc = "!f() { git switch $1 2>/dev/null || git switch -c $1; }; f"

Note the name of the alias: switchoc (for "switch or create").
As jar pointed out in the comments:

Anyone trying this in 2021, note that you cannot shadow existing git commands with aliases.
Since git switch is a git command, this alias (named "switch") won't work. You must create your unique name for the alias, like "switchit" or something.


bgusach's alias mentioned below in the comment is safer (based on Jiří Pavelka 's answer):

switch = "!f() { git checkout $1 2>/dev/null || git checkout -b $1; }; f"

git switch abranch

Original answer (2014) You can try:

git checkout -B foo

From git checkout man page:

If -B is given, <new_branch> is created if it doesn’t exist; otherwise, it is reset. This is the transactional equivalent of

$ git branch -f <branch> [<start point>]
$ git checkout <branch>

As mentioned below, use it with caution as it does reset the branch, which is not always desirable.
If you did reset the branch by mistake with this command, you can easily revert to its previous state with:

git reset HEAD@{1}

VonC
  • 1,042,979
  • 435
  • 3,649
  • 4,283
  • Thanks, `git` guru! :-) Accepting in 4 minutes. – Ionică Bizău Nov 16 '14 at 20:04
  • 13
    Note that `-B` will _reset_ the branch, see my answer for a (lengthier...) alternative. – ssmith Feb 20 '16 at 17:48
  • @ssmith I realize that (and have upvoted your answer), but I would still prefer this (simpler) approach. – VonC Feb 20 '16 at 18:20
  • 1
    Don't use this. It will more often than not destroy your branch and give you nice headaches bringing it back... – bgusach May 31 '17 at 09:37
  • 3
    -1, because the answer is misleading. The behaviour that OP and most readers expect is "if the branch already exists, just switch on it (git checkout foo)". But the first line of code in this answer does a very different thing. Yes, it's explained below, but what people first read and try is this misleading code. – Nick Volynkin Mar 03 '19 at 06:41
  • Shouldn't it be `switch = "!f() { git switch $1 2>/dev/null || git switch -c $1; }; f"`? – Arpan Srivastava May 29 '20 at 19:11
  • @ArpanSrivastava Thank you. I have edited the answer accordingly. – VonC May 29 '20 at 19:41
  • Anyone trying this in 2021, note that you cannot shadow existing git commands with aliases. Since git switch is a git command this alias won't work. You must create your unique name for the alias, like "switchit" or something. – jar Feb 19 '21 at 14:41
  • @jar Very good point, thank you. I have edited the answer to make that clearer. – VonC Feb 19 '21 at 19:44
73

Agreed with ssmith. Had the same problem and -B does not solve it, coz of reset. His solution works, however my solution looks simpler:

git checkout foo || git checkout -b foo

That works for me :)

EDIT

Without error output iff foo not exists

git checkout foo 2>/dev/null || git checkout -b foo
George Pavelka
  • 1,641
  • 9
  • 8
  • 2
    Ah yes, much simpler and shorter. =) There is however the rather minor caveat that if "foo" exists as something other than a branch (ex: tags) it'll check it out rather than create the branch, but it's a pretty edge case. – ssmith Mar 03 '16 at 15:20
  • Another minor caveat, if the branch does not exist you get an error in the output. @ssmith solution is cleaner. +1 for simplicity anyway – Gabriele Petronella May 27 '16 at 19:05
  • @GabrielePetronella simply hide error output, see EDIT – George Pavelka May 28 '16 at 09:59
  • @JiříPavelka thanks, however in my use case I want the output, but just the one of the successful comment. – Gabriele Petronella May 28 '16 at 11:51
  • @GabrielePetronella that should be it. You can get success from first command or success/error from the second command. – George Pavelka May 28 '16 at 12:02
  • @JiříPavelka Oh right, you're redirecting only stderr. Yes thanks, that works :) – Gabriele Petronella May 28 '16 at 12:03
  • 1
    Nice. I made an alias for this... just in case it helps somebody: `switch = "!f() { git checkout $1 2>/dev/null || git checkout -b $1; }; f"` – bgusach May 31 '17 at 09:26
  • 1
    be careful: if `foo` matches a file in the repo, this will check out _that file_ and revert changes to it. @ssmith 's answer is a little safer. – Josh Nov 16 '18 at 20:23
24

Note the rather important fact that -B will reset an existing branch before checking it out, which I don't believe @Ionica wants according to his question.

I certainly didn't, so the best one-liner I could come up with is this:

git checkout $(git show-ref --verify --quiet refs/heads/<branch> || echo '-b') <branch>

This can be made into a handy alias like so:

[alias]
  # git cob <branch>
  cob = "!f() { git checkout $(git show-ref --verify --quiet refs/heads/\"$1\" || echo '-b') \"$1\"; }; f"
ssmith
  • 634
  • 7
  • 10
12

The command checkout -b creates a new branch and then checks out to that branch. So, if a branch already exists, it cannot create a new one.

Instead you need to do:

git checkout -B <branchname>

The above command does in a context sensitive way. If there's a branch, it switches, if not, it creates and checkout.

Praveen Kumar Purushothaman
  • 154,660
  • 22
  • 177
  • 226
2

Not very different from what George Pavelka suggested, but instead of relying on status of "git checkout ", this checks for the presence and then decides the command to use

git show-branch <branch> &>/dev/null && git checkout <branch> || git checkout -b <branch>
kishore
  • 66
  • 2