I am trying to get the content of a file from another branch.
I am doing the following:
git checkout branchB some_specific_file.cc
The current branch stays unaffected. I suspect the reason is that even though I have done a git pull
I have never checked out branchB
locally.
Is there a way for this command to work if I have just done a pull
in the repo but never actually checked out the other branch?
Is there something equilalent to:
git pull
git checkout branchB
git checkout branchA
git checkout branchB some_specific_file.cc
without actually having to switch to branches so the last command works?
git pull = git fetch + git merge Their Git lists their branch names, and which commit hash IDs go with those branch names. Your Git then makes sure you have those commits, and once you do, sets up your origin/* names to remember those hash IDs.
You could use git checkout from the branch you want to transfer the changes to: git checkout <branch name> . That will change all files to match the version in the desired branch. Then you can commit, change, discard whatever you want.
I think what you want is:
$ git fetch
$ git checkout origin/branchB -- some_specific_file.cc
The fundamental error you are making here is thinking that branches mean something. :-) Or rather, that a branch name has some sort of global meaning—but it doesn't!
The git pull
command is meant as a convenience operation: it first runs git fetch
, then it runs a second Git command. The default second command is normally git merge
, but (a) you can change this and (b) there are some corner cases. The reason this is supposedly (but not actually) convenient is that git fetch
only obtains new commits. It does not affect any of your branches (which are yours, they do not belong to some remote like origin
!).
Typically, after you have obtained new commits from some remote like origin
, you will want to incorporate (some of) those commits into (some of) your own branches. To do that, you need a second Git command, such as git merge
or git rebase
. There are many small issues here though, such as:
The git pull
convenience command casts all of these aside and assures you that, no matter what git fetch
did, you're 100% sure that an immediate git xxx
—you fill in the xxx
part before you fetch—is the right answer! If it's not—which actually turns out to be very often, in my experience—then git pull
is the wrong command.
Your sequence of these two commands above:
git pull
git checkout branchB
will, if you do not yet have a branchB
, create for yourself a new (local) branch name branchB
, pointing to the same commit as your existing remote-tracking name origin/branchB
. Then:
git checkout branchA
gets you back on your (presumably existing) branchA, about which we have more to say in a moment. The final command:
git checkout branchB -- some_specific_file.cc
then extracts that specific file from the commit identified by the name branchB
. (I added the --
here—it's a good idea to use it by reflex, in case a file name resembles a git checkout
option or branch name; some_specific_file.cc
won't, so it's safe either way.)
The git fetch
step has your Git call up another Git, typically at the URL you have stored under the name origin
. Their Git lists their branch names, and which commit hash IDs go with those branch names. Your Git then makes sure you have those commits, and once you do, sets up your origin/*
names to remember those hash IDs.
The origin/*
names are what I call remote-tracking names; Git calls them remote-tracking branch names. They remember, for you, in your own Git repository, where the remote's branch names were, the last time your Git talked with their Git.
Hence, since git pull
runs git fetch
, this has the side effect of updating your remote-tracking names. But there's a problem: git pull
, in its effort to be convenient, limits the set of names that git fetch
fetches.
Normally git fetch
fetches all their branch names, updating all of your corresponding remote-tracking names. When run from git pull
, though, Git looks at your current branch's so-called upstream setting. Typically the upstream of master
is origin/master
, the upstream of branchA
is origin/branchA
, and so on. These are your names for their branches. When git pull
runs git fetch
, it says: only update this one remote-tracking name.
What this means in the end is that git pull
while not on branchB
won't update your origin/branchB
, and that's (eventually) a big problem. You will need to reverse the order of the commands: check out branchB
first, then pull. (Or, better, avoid git pull
, but hold on a moment.)
The git checkout
command will switch you to some existing branch that you already have:
git checkout master
for instance will switch you to master
, which you probably already have. But if you don't have it yet, git checkout
will scan your origin/*
names—the remote-tracking (not-exactly-a-branch) names—to see if there's one that matches after taking away the origin/
part.
If so, your Git will create a new local branch name that has the origin/
version of itself as its "upstream".
git merge
operates always and only on the current branch
The last step of git pull
is normally to run git merge
. If you run:
git checkout branchB
git pull
this means that Git should:
branchB
, or create it if necessary from origin/branchB
;origin/branchB
(only);git merge
to update your current branch—branchB
—using its upstream, origin/branchB
, which git fetch
just updated.The merge step will then make your local branch branchB
get updated.
So in general, you have to git checkout branchB
before you git pull
so as to make sure that origin/branchB
is the (single) remote-tracking name that the fetch
updates, and then your own local branchB
is also updated.
But you don't need any of that for your task. If you just run git fetch
, which updates all your origin/*
names, and then use origin/branchB
to identify the commit that contains the version of some_specific_file.cc
that you want, you're good. Hence the final set of commands I suggest at the top.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With