What happens when I push from a tracking branch in Git to a different remote branch?
Say I have a tracking branch called devo-1 that tracks the remote’s devo-1 branch. Suppose there’s another branch in the same remote, called devo-2. I now perform the following:
git checkout devo-1
git fetch origin
git pull origin devo-2
git push origin devo-2
- At step 2, this should update all origin/devo-* remote-tracking branches, correct?
- At step 3, this should get updates from only origin devo-2 (and not devo-1), correct?
- At step 4, this should push changes in devo-1 to only origin devo-2, correct?
4 Solutions collect form web for “What happens when I push from a tracking branch in Git to a different remote branch?”
Short version: 1: yes, 2: maybe, 3: no.
Git’s terminology is twisty and confusing. You don’t push to a “remote branch”, you push to a branch on a remote. Seems like a silly distinction but because the terminology is confusing, it’s important to make sure. (Just to be even more confusing, these “branches” all refer to labels attached to repositories, rather than the data structures one builds from the commit graphs contained in those repositories; but parts of those structures are also called “branches” at various times.)
To make things worse,
git pull, and
git push are not quite symmetric, either.
We start out in your own
devo-1 branch (because of
git checkout devo-1), although that does not matter until
git pull invokes
git merge below.
Then, assuming a standard setup (not a mirror or whatever):
git fetch origin
calls up the remote git on the internet-phone (or whatever), asks him “hey, what branch labels do you have”, copies over commits and such as needed, and sticks a copy of his (local) branch labels in your (local) “remote-branch” labels under your
origin/ name-space. That is,
origin/devo-2 are both updated—I assume both exist on
origin—along with anything else that can be, while your git has this chance.
(The answer to your first question is “yes”.)
The next command:
git pull origin devo-2
just runs a shell script, which in turn runs two commands:
git fetch(with some arguments), then
git rebase, depending on your pull configuration. I’m going to assume the former.
The first sub-part calls up the remote git on the internet-phone again. This time it only brings over new stuff in the supplied branch, i.e., their copy of
devo-2. It’s pretty likely there’s nothing new there yet (you just did a full fetch), but if there is anything new, it then drops the new SHA-1 into the special
FETCH_HEAD file, but does not1 update your “remote branch” copy in
The second sub-part runs
git merge to merge in their latest version. This is the moral equivalent2 of doing
git merge origin/devo-2. So now your
devo-1 is merged with the latest commit in their
devo-2, as recorded in
(Or, if you’re set up for rebase, it does that instead.)
(The answer to your second question is “maybe, depending on precisely what you meant”.)
Although you get any new commits and other SHA-1 goodies needed, they’re only written into
FETCH_HEAD, unless you have a new (1.8.4 or later) git. (See footnote 1.)
git push: you gave it two extra arguments, a remote and a refspec. The remote is
origin, so that’s who it will call up on the internet-phone or whatever as before. The refspec, though: that’s
devo-2, and that means
devo-2:devo-2 which (since I assume you have a local
devo-2 branch) means
This takes your local
devo-1) and tries to send new stuff to the remote (he gets a chance to reject them) and point his
devo-2 branch label to the new tip commit.
(The answer to your third question is “no”.)
In order to push what’s in your
devo-1 to their
devo-2, you need:
git push origin devo-1:devo-2
The refspec here means: “Send their git the SHA-1 you find by looking up my
devo-1, and ask them to write it to their
1Unless you have git 1.8.4 or newer, and then it does update
origin/devo-2. Fortunately, this doesn’t matter here: even if there was new stuff, the next step uses
FETCH_HEAD to refer to it, rather than using
2If you have git 1.8.4 or newer, it’s the real equivalent. Otherwise it depends on whether the second
fetch actually brought new stuff in.
At step 2, this should update all origin/devo-* remote-tracking branches, correct?
Correct. (Well, any remote tracking branches. Not just those that start with “devo”)
At step 3, this should get updates from only origin devo-2 (and not devo-1), correct?
Correct. (Well, the remote devo-2 branch will be merged/rebased with your HEAD).
At step 4, this should push changes in devo-1 to only origin devo-2, correct?
git push origin devo-1:devo-2 is what you’re looking for.
git push origin devo-2 is basically saying “push my local devo-2 branch to the remote devo-2 branch”, or
git push origin devo-2:devo-2.
Step 2 – yes git-fetch will update all remote branches (unless you provide a refspec argument to limit what it fetches).
Step 3 – no, git-pull is essentially the same as git-fetch + git-merge, and the merge operation will operate on the current branch. So in this example the current branch is devo-1 and the command would then merge devo-2 into devo-1.
Step 4, no this will push your local devo-2 changes to origin/devo-2.
git fetchwill not only update remote tracking branches, but all remote branches of that remote. Tracking usually means that a local branch belongs to a certain remote branch and consider that as the default, and supply additional status information.
git pull origin devo-2will fetch again for
devo-2and then merge the remote branch (
origin/devo-2) into the current branch. So as you have checked out the local
devo-1branch before, you will essentially merge the remote’s
devo-2into that branch.
git push origin devo-2will be equivalent to
git push origin devo-2:devo-2which means that this will push your local
devo-2to the remote’s
devo-2. So no, your local and currently checked out branch
devo-1will not be used for anything.