Jeff
Jeff

Reputation: 2443

Does git checkout -B perform a reset?

I have branch called shared that is shared amongst other developers. I work off of a feature branch. Whilst on my feature branch, I ran git checkout -B shared, and got the following message:

Switched to and reset branch 'shared'
Your branch and 'origin/shared' have diverged,
and have 6 and 126 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

I pulled and resolved the conflicts and suddenly realized that my shared branch had all of my changes from my feature branch. My questions are:

  1. How did this happen exactly?

  2. Looking at the docs it says that the branch is reset when running checkout with the -B flag:

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

    Last time I checked, running reset on a shared branch was dangerous. Or does 'reset' have a different meaning, in this context?

Upvotes: 2

Views: 582

Answers (3)

Shaun Luttin
Shaun Luttin

Reputation: 141742

Short Answer

Sometimes. git checkout -B <branch_name> performs a reset if branch_name already exists.

Details

Why did this happen, exactly?

As you indicated, git checkout -B <shared> resets shared to the HEAD commit and checks out shared. What does this do, exactly?

  • Point shared at your current HEAD commit. (This answers your first question).
  • Empty everything you recently added out of your index.
  • Checkout shared.

In other words, you reset shared to match feature. Here's an example that shows how you were before the checkout -B:

 > git log --oneline --decorate --all --graph

 * d0d0d0d (HEAD, feature) Some commit message.
 * e0e0e0e Some commit message.
 * f0f0f0f Some commit message.
 * g0g0g0g Some commit message. 
 * h0h0h0h Some commit message. 
 * i0i0i0i Some commit message. 
 |     * z0z0z0z (origin/shared) Some commit message.
 |     * y0y0y0y (origin/shared) Some commit message.
 |     * x0x0x0x (origin/shared) Some commit message.
 |     ---- 120 more commits ----
 |     * w0w0w0w (origin/shared) Some commit message.
 |     * v0v0v0v (origin/shared) Some commit message.
 |     * u0u0u0u (origin/shared) Some commit message.
 |   /   
 | /     
 * a0a0a0a (shared) Some commit message.
 * b0b0b0b Some commit message.
 * c0c0c0c Some commit message.

And here's how you were after the checkout -B:

 > git checkout -B shared
 > git log --oneline --decorate --all --graph

 * d0d0d0d (HEAD, feature, shared) Some commit message.
 * e0e0e0e Some commit message.
 * f0f0f0f Some commit message.
 * g0g0g0g Some commit message. 
 * h0h0h0h Some commit message. 
 * i0i0i0i Some commit message. 
 |     * z0z0z0z (origin/shared) Some commit message.
 |     * y0y0y0y (origin/shared) Some commit message.
 |     * x0x0x0x (origin/shared) Some commit message.
 |     ---- 120 more commits ----
 |     * w0w0w0w (origin/shared) Some commit message.
 |     * v0v0v0v (origin/shared) Some commit message.
 |     * u0u0u0u (origin/shared) Some commit message.
 |   /   
 | /     
 * a0a0a0a Some commit message.
 * b0b0b0b Some commit message.
 * c0c0c0c Some commit message.

shared will now have all the changes from feature, your shared will have 6 different commits thatorigin/shared`, and likewise it will have 126 different commits than yours.

Does 'reset' have a different meaning, in this context?

Reset has the same meaning as it always does. You basically did the following:

git checkout shared
git reset --mixed feature

A Good Fix

All I wanted to do was pull down shared and merge in feature. Is there a way to undo this?

@kdopen's comment suggests a good fix. Though both the fetch and the --hard option on reset are optional (see comments on the question for details). Here's my modified fix.

git checkout shared 
git reset origin/shared

That should land you in this position, from which you can merge in your feature branch as intended.

 * d0d0d0d (feature) Some commit message.
 * e0e0e0e Some commit message.
 * f0f0f0f Some commit message.
 * g0g0g0g Some commit message. 
 * h0h0h0h Some commit message. 
 * i0i0i0i Some commit message. 
 |     * z0z0z0z (HEAD, shared, origin/shared) Some commit message.
 |     * y0y0y0y (origin/shared) Some commit message.
 |     * x0x0x0x (origin/shared) Some commit message.
 |     ---- 120 more commits ----
 |     * w0w0w0w (origin/shared) Some commit message.
 |     * v0v0v0v (origin/shared) Some commit message.
 |     * u0u0u0u (origin/shared) Some commit message.
 |   /   
 | /     
 * a0a0a0a Some commit message.
 * b0b0b0b Some commit message.
 * c0c0c0c Some commit message.

Upvotes: 1

Martin G
Martin G

Reputation: 18129

git checkout -b and git checkout -B are used to checkout a (new) branch from a commit. -B is used to possibly re-use an existing branch by resetting it or otherwise creating it and -b is used to create a new one without the possibility of re-using an existing one.

git checkout -B shared

is the same thing as

git checkout -B shared HEAD

and it means

If a branch named shared exists, check it out and reset it to HEAD (in your case, HEAD was the tip of feature). If no branch named shared exists, create one based on HEAD.

What happened: You reset shared to feature and then pulled in origin/shared (and solved the conflicts)

Upvotes: 1

torek
torek

Reputation: 490078

The default starting position for a new branch (git checkout -b newbr) is HEAD.

This is also true for the reset action of "create-or-reset" git checkout -B oldbr. So since you were on feature, HEAD said feature which resolved to the ID of the tip-most commit on branch feature, which made your existing branch label shared point to that same commit.

Fortunately shared@{1} will have its previous position, so you can simply git reset shared@{1} (if you use csh or tcsh, you must quote the open brace, e.g., shared@\{1} or 'shared@{1}'; not sure about some other shells).

Upvotes: 1

Related Questions