2

Let's say that the central repo has master, branch_A and branch_B. In my local working space, I have only master and branch_A.

I want to get a local branch branch_B in my work-space in a clean way.

i.e. I want to get the same exact contents from central repo's branch_B and nothing else.

I thought that git checkout -b my_name/branch_B would do this. However, when I did this, I got a lot of conflicts, which I do not know why.

I do not want to resolve conflicts manually. All I want is to get the same exact contents from the central repo's branch_B and nothing else (i.e. discard any local changes if there is any)

leopoodle
  • 1,412
  • 3
  • 18
  • 27

3 Answers3

3

What you want is just git checkout branch_B even though branch_B does not exist. In fact, it's critical that it not exist, otherwise git checkout can't create it.


Before you just use that, though, take a moment to consider this: you're not really "creating a branch from a central repo" at all. You can't: you can only operate on your own repository.

This might seem like a distinction without a difference, but it's critical to making any sense out of numerous bits of Git weirdness. Everything you do, you do to, or in, your own repository.

(The one thing that's sort of an exception—but not really—is git push. Here, you take things you have already done to/in your own repository, and offer them to another Git, which has its own repository, and then request that it do things to its repository based on what you have offered. It's up to that Git to do those things, to its own repository.)

Centralized repositories

When dealing with a central repository, the way you get stuff from them is to use git fetch. The fetch command calls up their Git and requests, from them, a list of their branch-names and other such references, which gives your Git their branch tip commit IDs (SHA-1 hashes). Your Git then requests any commit objects, by hash ID, and any other objects (files, or technically "blobs", tree objects, earlier commits and their trees and blobs, and annotated-tag objects) needed to complete the fetch. Your Git then squirrels all those objects away in your repository, and as a last step, renames all their branch-names to new names that your Git guarantees will not conflict with any of your branch names.

The new names your Git synthesizes from their names are your remote-tracking branches (origin/master and so on). These are created and updated by git fetch. If you use --prune, or set up pruning as the default, your git fetch operations will remove from your repository any remote-tracking branch names you have that no longer have a corresponding regular branch in that other Git. (This is sometimes useful, but is not the default, probably for historical reasons plus the "only useful if there's a lot of branch creation and deletion in the other repo" aspect.)

The origin part of origin/master is just the name of the remote. A remote is just a name—usually origin, in fact, since that's the default created by git clone—under which your Git stores the URL used for git fetch. The name for these remote-tracking branches is constructed by putting the name of the remote in front of the remote's branch-name: hence master becomes origin/master, branch_A becomes origin/branch_A, and so on.

Why git checkout creates branches

The long form of the command you want is:

git checkout -b branch_B --track origin/branch_B

(assuming your other, central, repository is filed away under origin). The -b here means "create a branch", and the --track means: "I'm going to supply another name that I want you, my Git, to look up in my repository to find a commit hash ID. When I do that, I also want you to do the equivalent of git branch --set-upstream-to once the branch is made." Last, of course, origin/branch_B is the name of the (already-existing) remote-tracking branch.

This gets used a lot, so the Git folks decided to have git checkout be extra clever: if you ask Git to check out a branch by name, and it doesn't exist, git checkout looks to see if there's some remote-tracking branch with the same name, after stripping the remote off the remote-tracking branch name. (Whew!) That is, if you git checkout sneeze, your Git looks to see if there's an origin/sneeze or maybe an upstream/sneeze or whatever.

If there's exactly one such remote-tracking branch, then git checkout is instructed to create a local branch, using the remote-tracking branch's current hash ID as its starting point.

But the shortcut really has to be spelled exactly that way

Note that git checkout -b branch_B doesn't make a new branch_B starting from origin/branch_B. It just creates a new branch_B starting from the current commit. The new branch is also not set up to track any remote-tracking branch. This is because -b tells git checkout to create the branch immediately, so that it never triggers the "hey, wait, I don't have an existing branch_B ... maybe I should run some automatic special-case code instead?" code.

Of course, for the special case code to work, you must have origin/branch_B in your repository. It won't reach out and find it on the centralized repository. Only git fetch will do that—it's just git fetch and git push that actually call up another Git, using the URL stashed under the remote's name.

(In fact, git remote will also sometimes call up another Git, but that's for other SO questions.)

torek
  • 330,127
  • 43
  • 437
  • 552
0

You need to execute:

git checkout -b branch_B origin/branch_B

"origin" is the default name for your remote repository. To know the correct name execute:

git remote -v
0

First git fetch

After a git fetch your local repo should have fetched all the branches from the central repo, which usually is called origin.

This will have created a local remote-tracking branch called origin/branch_B:

$ git fetch
 * [new branch]      branch_B -> origin/branch_B

This remote-tracking branch origin/branch_B tracks in your repo what are the latest changes fetched from central repo.

You're not supposed to commit to it, so you need to create an actual branch to work on.


Then git checkout branch_B

Then simply git checkout branch_B should create a local branch_B that automatically tracks origin/branch_B:

$ git checkout branch_B
Branch branch_B set up to track remote branch branch_B from origin.
Switched to a new branch 'branch_B'

If you want to list both your local and your remote branches, you can use git branch -va.

Christoffer Hammarström
  • 24,236
  • 4
  • 44
  • 54