Git fetch not working as expected “:gone]” is not being added to branch description2019 Community Moderator ElectionCheck if a git branch is ahead of another using a scriptgit branch ahead and behind for local branch?How to remove local (untracked) files from the current Git working tree?How to clone all remote branches in Git?What is the difference between 'git pull' and 'git fetch'?Make an existing Git branch track a remote branch?How do you create a remote Git branch?Move the most recent commit(s) to a new branch with GitHow do I check out a remote Git branch?How do I delete a Git branch both locally and remotely?How do I rename a local Git branch?Git fetch remote branch
When was drinking water recognized as crucial in marathon running?
Where is this quote about overcoming the impossible said in "Interstellar"?
I can't die. Who am I?
How to mitigate "bandwagon attacking" from players?
Why won't the strings command stop?
How to fix my table, centering of columns
When to use mean vs median
Wardrobe above a wall with fuse boxes
3.5% Interest Student Loan or use all of my savings on Tuition?
1970s scifi/horror novel where protagonist is used by a crablike creature to feed its larvae, goes mad, and is defeated by retraumatising him
A bug in Excel? Conditional formatting for marking duplicates also highlights unique value
Book about a time-travel war fought by computers
Is there a math equivalent to the conditional ternary operator?
“I had a flat in the centre of town, but I didn’t like living there, so …”
Can I solder 12/2 Romex to extend wire 5 ft?
Is there a frame of reference in which I was born before I was conceived?
Has Wakanda ever accepted refugees?
Sometimes a banana is just a banana
PTIJ: Why can't I sing about soda on certain days?
PTIJ: Aharon, King of Egypt
Did Amazon pay $0 in taxes last year?
Meaning of word ягоза
Is there a limit on the maximum number of future jobs queued in an org?
School performs periodic password audits. Is my password compromised?
Git fetch not working as expected “:gone]” is not being added to branch description
2019 Community Moderator ElectionCheck if a git branch is ahead of another using a scriptgit branch ahead and behind for local branch?How to remove local (untracked) files from the current Git working tree?How to clone all remote branches in Git?What is the difference between 'git pull' and 'git fetch'?Make an existing Git branch track a remote branch?How do you create a remote Git branch?Move the most recent commit(s) to a new branch with GitHow do I check out a remote Git branch?How do I delete a Git branch both locally and remotely?How do I rename a local Git branch?Git fetch remote branch
If we execute git fetch -p or git fetch --prune it will prune branches if deleted on remote.
After executing this command if we do git branch -vv it suppose to show : gone] for the local branches which are deleted from remote.
In my case sometimes it is working as expected but not always. Sometimes it is not adding : gone] to the branches deleted on remote.
My goal here is to delete branche if local branch is deleted on remote.
I am wondering why this is happening ?
git github
add a comment |
If we execute git fetch -p or git fetch --prune it will prune branches if deleted on remote.
After executing this command if we do git branch -vv it suppose to show : gone] for the local branches which are deleted from remote.
In my case sometimes it is working as expected but not always. Sometimes it is not adding : gone] to the branches deleted on remote.
My goal here is to delete branche if local branch is deleted on remote.
I am wondering why this is happening ?
git github
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').
– RomainValeri
15 hours ago
add a comment |
If we execute git fetch -p or git fetch --prune it will prune branches if deleted on remote.
After executing this command if we do git branch -vv it suppose to show : gone] for the local branches which are deleted from remote.
In my case sometimes it is working as expected but not always. Sometimes it is not adding : gone] to the branches deleted on remote.
My goal here is to delete branche if local branch is deleted on remote.
I am wondering why this is happening ?
git github
If we execute git fetch -p or git fetch --prune it will prune branches if deleted on remote.
After executing this command if we do git branch -vv it suppose to show : gone] for the local branches which are deleted from remote.
In my case sometimes it is working as expected but not always. Sometimes it is not adding : gone] to the branches deleted on remote.
My goal here is to delete branche if local branch is deleted on remote.
I am wondering why this is happening ?
git github
git github
edited 16 hours ago
Sanjay Yadav
asked 16 hours ago
Sanjay YadavSanjay Yadav
8929
8929
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').
– RomainValeri
15 hours ago
add a comment |
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').
– RomainValeri
15 hours ago
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (
git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').– RomainValeri
15 hours ago
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (
git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').– RomainValeri
15 hours ago
add a comment |
1 Answer
1
active
oldest
votes
It's not necessarily wise to delete your branch named X just because someone else deleted his branch named X. If you're working on a new feature and you called it feat, and Bob gave up on his new feature that he was calling feat and Bob deletes Bob's feat, that doesn't mean you should delete your feat!
That aside, let's look at a special feature of branches. This special feature is only available for (local) branches, not for things like origin/master, which parts of Git call remote-tracking branches and which are listed under git branch -r output.1 They actually have several special features—for instance, you can get "on" a branch using git checkout, as in after git checkout master, the git status command will say on branch master. But that's not the special feature I mean here.
The special feature we care about here is that they can have an upstream setting. That is, your master can have one—and only one—upstream, and your develop, if you have a develop, can have one upstream, and your feat, if you have one, can have one upstream, and so on. Your choice here is to have an upstream, or not have an upstream. You make this choice one branch at a time, for each branch.
To take away the upstream setting of a branch, use git branch --unset-upstream name. The branch named name now has no upstream. If you leave out the name part, it applies to the current branch, i.e., the one to which your HEAD is attached. This is not the only way to unset it, but it's usually the best way.
To set or change the upstream setting of a branch, use git branch --set-upstream-to=upstream name. The branch named name now has an upstream; the upstream is has is the argument you gave as upstream. As with --unset-upstream, leaving out name means the current branch (you're not allowed to leave out upstream). Likewise, this is not the only way to set it, but usually it's the best way, because the git branch command will verify whether the upstream argument is sensible before it lets you set it.
Sometimes branches have an upstream setting right from the get-go, and sometimes they don't. We'll look at when and why in a moment.
1I've gotten to the point where I try to avoid the word branch for the remote-tracking things. I now just call remote-tracking names, because they're so different from local branch names. Note that git fetch -p, or git remote prune origin, or setting fetch.prune to true, affects only these remote-tracking names.
What exactly is an upstream?
An upstream is just another branch name—and here, by branch name, I mean either a local branch like master or develop, or a remote-tracking name like origin/master. So you can have the upstream of develop set to master if you like, or to origin/master, or to origin/develop. The git branch --set-upstream-to operation will let you set anything that exists and, to Git's mind, makes sense here.
Git has a weird flaw of sorts here. Part of this is historical. Back in the ancient past, Git did not have remotes—there was no origin—so Git did not have remote-tracking names either without origin, there could be no origin/master. But part is due to the simple fact you may or may not have an origin/xyz, and origin/xyz could even go away while you're hard at work on your xyz branch (because Bob thought you were done and went and deleted xyz over on origin).
The flaw is, to put it a bit too simply, that the upstream you've set—back when it existed and git branch --set-upstream-to therefore let you set it—might be gone now. And that's the case when you see : gone in your git branch -vv output. At some point in the past, you told your Git that your branch xyz should have origin/xyz as its upstream, and origin/xyz existed at the time. So git branch verified that all was good and made the setting. But now the name is gone, so the setting is no longer valid and git branch -vv makes note of that.
In fact, the upstream setting of a branch is built out of two parts, and you can configure either or both parts with git config, or even bring your configuration in your chosen editor (git config --edit) and mess with them directly:
[branch "master"]
remote = origin
merge = refs/heads/master
This setting, in this particular repository, says that the upstream of master is origin/master. You might think you can just take the origin part from the remote = line and the master part from the merge = line, but this is a sort of trap: there's a secret complicated mapping. To find the upstream setting of some branch, use git rev-parse with the @upstream suffix:
$ git rev-parse --symbolic-full-name master@upstream
refs/remotes/origin/master
This works for branches whose upstream is set to be another local branch too.
Anyway, because it is two parts like this and you can mess with it outside the normal git branch --set-upstream-to mechanism, you can break the upstream setting. If you do break it—if you set it to something nonsensical—git branch -vv will list the upstream as "gone", using the same technique as when normal, everyday Git operations break it because it really did go away. Git does not care why it's broken, only that it is or is not broken right now: if it is broken right now, Git says "gone" and otherwise pretends it's unset.
Note that this also means that if Bob accidentally removed xyz from origin and Bob fixes his mistake and puts xyz back, your Git can go from "gone" to "not gone, everything is fine" after another git fetch. That's yet another reason you should not have your Git remove your local branch just because someone messed with some other Git somewhere else.
What good is an upstream?
The upstream setting only offers a few minor features. Sometimes, some people really like these features, but they're never required. So in one sense, an upstream is no good at all. You don't have to use them, ever, provided you avoid git pull.
The features, though, are:
Easier push: the standard
push.defaultsetting requires that your branch have an upstream if you want to rungit pushwithout extra arguments.Easier merge and rebase: the
git mergeandgit rebasecommands can use it. Thegit pullwrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runsgit fetchfor you, and then immediately—before you have a chance to decide whether it's a good idea based on whatgit fetchdid—runsgit mergeorgit rebasefor you.More-useful
git status: the first line ofgit statustells you whether you're in detached HEAD mode, and if not, which branch you're on. Having an upstream means that there's a second line, right after the one about the branch you're on, when you're on a branch. The second line compares the branch to its upstream and tells you whether it is "up to date" with its upstream.
So that's what an upstream is good for: it makes some things easier and/or more useful. But you are limited to one upstream at a time. You may, sometimes, want to get the equivalent of the git status second-line output for some arbitrary pair of names. There is a way to do that using git rev-list --count, but we'll leave that for other answers.
Why do some branches already have an upstream set, and others don't?
There are lots of ways to create branches in Git. Each one does something a little bit different from its other alternatives—which is why each of these methods exists, but also gives you this profusion of confusion.
The two main commands for creating new branches are git branch and git checkout. When you use git branch to create a new branch, you are in full control at all times:
git branch --track newbranch origin/upstreamname
or:
git branch --no-track newbranch origin/upstreamname
Despite the upstream being called upstream, the argument controlling it is spelled --track—another historical accident or mistake, really.
If you don't use --track or --no-track here, git branch uses whatever you've chosen as a default when you configured branch.autoSetupMerge. See below for what that means.
When you use git checkout, you can use --track or --no-track, but if you don't use either option, it gets more complicated. The branch.autoSetupMerge setting still matters but ... well:
git checkout -b newbranchcreatesnewbranch, but creates it fromHEAD, so it doesn't set an upstream. That is, the new namenewbranchnow identifies the same commit thatHEADidentified just before this.git checkout -b newbranch origin/namecreatesnewbranchand creates it usingorigin/name. That is, the new namenewbranchnow identifies the same commit asorigin/name. This obeys yourbranch.autoSetupMergeconfiguration.git checkout -b newbranch existing-branchcreatesnewbranch, usingexisting-branchas its starting point. That is, the new name and the existing name now identify the same commit. This also obeys yourbranch.autoSetupMergeconfiguration, but see below for why I separated this out.git checkout nameeither uses an existingname, or creates a new branch namednameusingorigin/name. If it creates a new branch, it obeysbranch.autoSetupMerge.Note that this will never create a new branch using a local branch name, i.e., it can't make a local branch that has another local branch as its upstream. If that were going to be the case, the two *
name*s would be the same, so the branch by definition already exists, so it just checks out the local branch without creating anything.git checkout --track origin/namecreates a new branch namednameand does set its upstream.git checkout --no-track origin/namecreates a new branch namednameand makes sure it has no upstream.
So, as you can see, it's complicated! The exact method of creating the branch determines in part whether it has an upstream, with the rest of the determination being based on your branch.autoSetupMerge configuration. This setting has three possible values:
true: set the upstream when the starting-point is a remote-tracking name.false: don't set the upstream.always: set the upstream when the starting-point is either a remote-tracking name or a (local) branch name.
The default, if you did not set branch.autoSetupMerge at all, is to pretend you set it to true. So by default, all of these branch-creating options act like you said --track if you give them an origin/* name, or any other remote-tracking name, as their starting-point. That's true even if the starting point is merely implied, as in the:
git checkout develop
case where you don't have a local develop but do have a remote-tracking origin/develop: this creates your new local develop from your remote-tracking origin/develop, and if branch.autoSetupMerge is true—including if you haven't set it at all—now your develop "tracks"—has as its upstream—your origin/develop.
Summary
Some of your branches have upstreams set. Which branches have upstreams, and what those upstreams are, is up to you, controlled by your configuration and/or by your command-line options and/or by additional git branch --set-upstream-to or git branch --unset-upstream commands.
Those branches that do have upstreams set will get some useful features. If the upstream that is set "goes away" by whatever process, git branch -vv will list your local branches and say that their upstream is "gone". Other Git commands will just pretend you unset their upstream. If the upstream comes back again, the upstream will resume its usefulness.
Deleting a local branch only because its upstream is gone is a mistake. Deleting it because you are done with it is fine. You don't need to have a local branch named develop, or even one named master, if you're done with them, even if they still exist as upstream origin/develop or origin/master names. You can just use origin/master to refer to your Git's memory of the master on origin—you don't need to have your own master at all.
Sometimes, you are done with a branch because of some underlying reason that also means that the upstream is going to be gone, or is already gone. In that case, deleting your local branch is fine—you're deleting it because you're done with it. The fact that it will be deleted on origin, or already has been deleted on origin, is irrelevant here!
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55020899%2fgit-fetch-not-working-as-expected-gone-is-not-being-added-to-branch-descript%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
It's not necessarily wise to delete your branch named X just because someone else deleted his branch named X. If you're working on a new feature and you called it feat, and Bob gave up on his new feature that he was calling feat and Bob deletes Bob's feat, that doesn't mean you should delete your feat!
That aside, let's look at a special feature of branches. This special feature is only available for (local) branches, not for things like origin/master, which parts of Git call remote-tracking branches and which are listed under git branch -r output.1 They actually have several special features—for instance, you can get "on" a branch using git checkout, as in after git checkout master, the git status command will say on branch master. But that's not the special feature I mean here.
The special feature we care about here is that they can have an upstream setting. That is, your master can have one—and only one—upstream, and your develop, if you have a develop, can have one upstream, and your feat, if you have one, can have one upstream, and so on. Your choice here is to have an upstream, or not have an upstream. You make this choice one branch at a time, for each branch.
To take away the upstream setting of a branch, use git branch --unset-upstream name. The branch named name now has no upstream. If you leave out the name part, it applies to the current branch, i.e., the one to which your HEAD is attached. This is not the only way to unset it, but it's usually the best way.
To set or change the upstream setting of a branch, use git branch --set-upstream-to=upstream name. The branch named name now has an upstream; the upstream is has is the argument you gave as upstream. As with --unset-upstream, leaving out name means the current branch (you're not allowed to leave out upstream). Likewise, this is not the only way to set it, but usually it's the best way, because the git branch command will verify whether the upstream argument is sensible before it lets you set it.
Sometimes branches have an upstream setting right from the get-go, and sometimes they don't. We'll look at when and why in a moment.
1I've gotten to the point where I try to avoid the word branch for the remote-tracking things. I now just call remote-tracking names, because they're so different from local branch names. Note that git fetch -p, or git remote prune origin, or setting fetch.prune to true, affects only these remote-tracking names.
What exactly is an upstream?
An upstream is just another branch name—and here, by branch name, I mean either a local branch like master or develop, or a remote-tracking name like origin/master. So you can have the upstream of develop set to master if you like, or to origin/master, or to origin/develop. The git branch --set-upstream-to operation will let you set anything that exists and, to Git's mind, makes sense here.
Git has a weird flaw of sorts here. Part of this is historical. Back in the ancient past, Git did not have remotes—there was no origin—so Git did not have remote-tracking names either without origin, there could be no origin/master. But part is due to the simple fact you may or may not have an origin/xyz, and origin/xyz could even go away while you're hard at work on your xyz branch (because Bob thought you were done and went and deleted xyz over on origin).
The flaw is, to put it a bit too simply, that the upstream you've set—back when it existed and git branch --set-upstream-to therefore let you set it—might be gone now. And that's the case when you see : gone in your git branch -vv output. At some point in the past, you told your Git that your branch xyz should have origin/xyz as its upstream, and origin/xyz existed at the time. So git branch verified that all was good and made the setting. But now the name is gone, so the setting is no longer valid and git branch -vv makes note of that.
In fact, the upstream setting of a branch is built out of two parts, and you can configure either or both parts with git config, or even bring your configuration in your chosen editor (git config --edit) and mess with them directly:
[branch "master"]
remote = origin
merge = refs/heads/master
This setting, in this particular repository, says that the upstream of master is origin/master. You might think you can just take the origin part from the remote = line and the master part from the merge = line, but this is a sort of trap: there's a secret complicated mapping. To find the upstream setting of some branch, use git rev-parse with the @upstream suffix:
$ git rev-parse --symbolic-full-name master@upstream
refs/remotes/origin/master
This works for branches whose upstream is set to be another local branch too.
Anyway, because it is two parts like this and you can mess with it outside the normal git branch --set-upstream-to mechanism, you can break the upstream setting. If you do break it—if you set it to something nonsensical—git branch -vv will list the upstream as "gone", using the same technique as when normal, everyday Git operations break it because it really did go away. Git does not care why it's broken, only that it is or is not broken right now: if it is broken right now, Git says "gone" and otherwise pretends it's unset.
Note that this also means that if Bob accidentally removed xyz from origin and Bob fixes his mistake and puts xyz back, your Git can go from "gone" to "not gone, everything is fine" after another git fetch. That's yet another reason you should not have your Git remove your local branch just because someone messed with some other Git somewhere else.
What good is an upstream?
The upstream setting only offers a few minor features. Sometimes, some people really like these features, but they're never required. So in one sense, an upstream is no good at all. You don't have to use them, ever, provided you avoid git pull.
The features, though, are:
Easier push: the standard
push.defaultsetting requires that your branch have an upstream if you want to rungit pushwithout extra arguments.Easier merge and rebase: the
git mergeandgit rebasecommands can use it. Thegit pullwrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runsgit fetchfor you, and then immediately—before you have a chance to decide whether it's a good idea based on whatgit fetchdid—runsgit mergeorgit rebasefor you.More-useful
git status: the first line ofgit statustells you whether you're in detached HEAD mode, and if not, which branch you're on. Having an upstream means that there's a second line, right after the one about the branch you're on, when you're on a branch. The second line compares the branch to its upstream and tells you whether it is "up to date" with its upstream.
So that's what an upstream is good for: it makes some things easier and/or more useful. But you are limited to one upstream at a time. You may, sometimes, want to get the equivalent of the git status second-line output for some arbitrary pair of names. There is a way to do that using git rev-list --count, but we'll leave that for other answers.
Why do some branches already have an upstream set, and others don't?
There are lots of ways to create branches in Git. Each one does something a little bit different from its other alternatives—which is why each of these methods exists, but also gives you this profusion of confusion.
The two main commands for creating new branches are git branch and git checkout. When you use git branch to create a new branch, you are in full control at all times:
git branch --track newbranch origin/upstreamname
or:
git branch --no-track newbranch origin/upstreamname
Despite the upstream being called upstream, the argument controlling it is spelled --track—another historical accident or mistake, really.
If you don't use --track or --no-track here, git branch uses whatever you've chosen as a default when you configured branch.autoSetupMerge. See below for what that means.
When you use git checkout, you can use --track or --no-track, but if you don't use either option, it gets more complicated. The branch.autoSetupMerge setting still matters but ... well:
git checkout -b newbranchcreatesnewbranch, but creates it fromHEAD, so it doesn't set an upstream. That is, the new namenewbranchnow identifies the same commit thatHEADidentified just before this.git checkout -b newbranch origin/namecreatesnewbranchand creates it usingorigin/name. That is, the new namenewbranchnow identifies the same commit asorigin/name. This obeys yourbranch.autoSetupMergeconfiguration.git checkout -b newbranch existing-branchcreatesnewbranch, usingexisting-branchas its starting point. That is, the new name and the existing name now identify the same commit. This also obeys yourbranch.autoSetupMergeconfiguration, but see below for why I separated this out.git checkout nameeither uses an existingname, or creates a new branch namednameusingorigin/name. If it creates a new branch, it obeysbranch.autoSetupMerge.Note that this will never create a new branch using a local branch name, i.e., it can't make a local branch that has another local branch as its upstream. If that were going to be the case, the two *
name*s would be the same, so the branch by definition already exists, so it just checks out the local branch without creating anything.git checkout --track origin/namecreates a new branch namednameand does set its upstream.git checkout --no-track origin/namecreates a new branch namednameand makes sure it has no upstream.
So, as you can see, it's complicated! The exact method of creating the branch determines in part whether it has an upstream, with the rest of the determination being based on your branch.autoSetupMerge configuration. This setting has three possible values:
true: set the upstream when the starting-point is a remote-tracking name.false: don't set the upstream.always: set the upstream when the starting-point is either a remote-tracking name or a (local) branch name.
The default, if you did not set branch.autoSetupMerge at all, is to pretend you set it to true. So by default, all of these branch-creating options act like you said --track if you give them an origin/* name, or any other remote-tracking name, as their starting-point. That's true even if the starting point is merely implied, as in the:
git checkout develop
case where you don't have a local develop but do have a remote-tracking origin/develop: this creates your new local develop from your remote-tracking origin/develop, and if branch.autoSetupMerge is true—including if you haven't set it at all—now your develop "tracks"—has as its upstream—your origin/develop.
Summary
Some of your branches have upstreams set. Which branches have upstreams, and what those upstreams are, is up to you, controlled by your configuration and/or by your command-line options and/or by additional git branch --set-upstream-to or git branch --unset-upstream commands.
Those branches that do have upstreams set will get some useful features. If the upstream that is set "goes away" by whatever process, git branch -vv will list your local branches and say that their upstream is "gone". Other Git commands will just pretend you unset their upstream. If the upstream comes back again, the upstream will resume its usefulness.
Deleting a local branch only because its upstream is gone is a mistake. Deleting it because you are done with it is fine. You don't need to have a local branch named develop, or even one named master, if you're done with them, even if they still exist as upstream origin/develop or origin/master names. You can just use origin/master to refer to your Git's memory of the master on origin—you don't need to have your own master at all.
Sometimes, you are done with a branch because of some underlying reason that also means that the upstream is going to be gone, or is already gone. In that case, deleting your local branch is fine—you're deleting it because you're done with it. The fact that it will be deleted on origin, or already has been deleted on origin, is irrelevant here!
add a comment |
It's not necessarily wise to delete your branch named X just because someone else deleted his branch named X. If you're working on a new feature and you called it feat, and Bob gave up on his new feature that he was calling feat and Bob deletes Bob's feat, that doesn't mean you should delete your feat!
That aside, let's look at a special feature of branches. This special feature is only available for (local) branches, not for things like origin/master, which parts of Git call remote-tracking branches and which are listed under git branch -r output.1 They actually have several special features—for instance, you can get "on" a branch using git checkout, as in after git checkout master, the git status command will say on branch master. But that's not the special feature I mean here.
The special feature we care about here is that they can have an upstream setting. That is, your master can have one—and only one—upstream, and your develop, if you have a develop, can have one upstream, and your feat, if you have one, can have one upstream, and so on. Your choice here is to have an upstream, or not have an upstream. You make this choice one branch at a time, for each branch.
To take away the upstream setting of a branch, use git branch --unset-upstream name. The branch named name now has no upstream. If you leave out the name part, it applies to the current branch, i.e., the one to which your HEAD is attached. This is not the only way to unset it, but it's usually the best way.
To set or change the upstream setting of a branch, use git branch --set-upstream-to=upstream name. The branch named name now has an upstream; the upstream is has is the argument you gave as upstream. As with --unset-upstream, leaving out name means the current branch (you're not allowed to leave out upstream). Likewise, this is not the only way to set it, but usually it's the best way, because the git branch command will verify whether the upstream argument is sensible before it lets you set it.
Sometimes branches have an upstream setting right from the get-go, and sometimes they don't. We'll look at when and why in a moment.
1I've gotten to the point where I try to avoid the word branch for the remote-tracking things. I now just call remote-tracking names, because they're so different from local branch names. Note that git fetch -p, or git remote prune origin, or setting fetch.prune to true, affects only these remote-tracking names.
What exactly is an upstream?
An upstream is just another branch name—and here, by branch name, I mean either a local branch like master or develop, or a remote-tracking name like origin/master. So you can have the upstream of develop set to master if you like, or to origin/master, or to origin/develop. The git branch --set-upstream-to operation will let you set anything that exists and, to Git's mind, makes sense here.
Git has a weird flaw of sorts here. Part of this is historical. Back in the ancient past, Git did not have remotes—there was no origin—so Git did not have remote-tracking names either without origin, there could be no origin/master. But part is due to the simple fact you may or may not have an origin/xyz, and origin/xyz could even go away while you're hard at work on your xyz branch (because Bob thought you were done and went and deleted xyz over on origin).
The flaw is, to put it a bit too simply, that the upstream you've set—back when it existed and git branch --set-upstream-to therefore let you set it—might be gone now. And that's the case when you see : gone in your git branch -vv output. At some point in the past, you told your Git that your branch xyz should have origin/xyz as its upstream, and origin/xyz existed at the time. So git branch verified that all was good and made the setting. But now the name is gone, so the setting is no longer valid and git branch -vv makes note of that.
In fact, the upstream setting of a branch is built out of two parts, and you can configure either or both parts with git config, or even bring your configuration in your chosen editor (git config --edit) and mess with them directly:
[branch "master"]
remote = origin
merge = refs/heads/master
This setting, in this particular repository, says that the upstream of master is origin/master. You might think you can just take the origin part from the remote = line and the master part from the merge = line, but this is a sort of trap: there's a secret complicated mapping. To find the upstream setting of some branch, use git rev-parse with the @upstream suffix:
$ git rev-parse --symbolic-full-name master@upstream
refs/remotes/origin/master
This works for branches whose upstream is set to be another local branch too.
Anyway, because it is two parts like this and you can mess with it outside the normal git branch --set-upstream-to mechanism, you can break the upstream setting. If you do break it—if you set it to something nonsensical—git branch -vv will list the upstream as "gone", using the same technique as when normal, everyday Git operations break it because it really did go away. Git does not care why it's broken, only that it is or is not broken right now: if it is broken right now, Git says "gone" and otherwise pretends it's unset.
Note that this also means that if Bob accidentally removed xyz from origin and Bob fixes his mistake and puts xyz back, your Git can go from "gone" to "not gone, everything is fine" after another git fetch. That's yet another reason you should not have your Git remove your local branch just because someone messed with some other Git somewhere else.
What good is an upstream?
The upstream setting only offers a few minor features. Sometimes, some people really like these features, but they're never required. So in one sense, an upstream is no good at all. You don't have to use them, ever, provided you avoid git pull.
The features, though, are:
Easier push: the standard
push.defaultsetting requires that your branch have an upstream if you want to rungit pushwithout extra arguments.Easier merge and rebase: the
git mergeandgit rebasecommands can use it. Thegit pullwrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runsgit fetchfor you, and then immediately—before you have a chance to decide whether it's a good idea based on whatgit fetchdid—runsgit mergeorgit rebasefor you.More-useful
git status: the first line ofgit statustells you whether you're in detached HEAD mode, and if not, which branch you're on. Having an upstream means that there's a second line, right after the one about the branch you're on, when you're on a branch. The second line compares the branch to its upstream and tells you whether it is "up to date" with its upstream.
So that's what an upstream is good for: it makes some things easier and/or more useful. But you are limited to one upstream at a time. You may, sometimes, want to get the equivalent of the git status second-line output for some arbitrary pair of names. There is a way to do that using git rev-list --count, but we'll leave that for other answers.
Why do some branches already have an upstream set, and others don't?
There are lots of ways to create branches in Git. Each one does something a little bit different from its other alternatives—which is why each of these methods exists, but also gives you this profusion of confusion.
The two main commands for creating new branches are git branch and git checkout. When you use git branch to create a new branch, you are in full control at all times:
git branch --track newbranch origin/upstreamname
or:
git branch --no-track newbranch origin/upstreamname
Despite the upstream being called upstream, the argument controlling it is spelled --track—another historical accident or mistake, really.
If you don't use --track or --no-track here, git branch uses whatever you've chosen as a default when you configured branch.autoSetupMerge. See below for what that means.
When you use git checkout, you can use --track or --no-track, but if you don't use either option, it gets more complicated. The branch.autoSetupMerge setting still matters but ... well:
git checkout -b newbranchcreatesnewbranch, but creates it fromHEAD, so it doesn't set an upstream. That is, the new namenewbranchnow identifies the same commit thatHEADidentified just before this.git checkout -b newbranch origin/namecreatesnewbranchand creates it usingorigin/name. That is, the new namenewbranchnow identifies the same commit asorigin/name. This obeys yourbranch.autoSetupMergeconfiguration.git checkout -b newbranch existing-branchcreatesnewbranch, usingexisting-branchas its starting point. That is, the new name and the existing name now identify the same commit. This also obeys yourbranch.autoSetupMergeconfiguration, but see below for why I separated this out.git checkout nameeither uses an existingname, or creates a new branch namednameusingorigin/name. If it creates a new branch, it obeysbranch.autoSetupMerge.Note that this will never create a new branch using a local branch name, i.e., it can't make a local branch that has another local branch as its upstream. If that were going to be the case, the two *
name*s would be the same, so the branch by definition already exists, so it just checks out the local branch without creating anything.git checkout --track origin/namecreates a new branch namednameand does set its upstream.git checkout --no-track origin/namecreates a new branch namednameand makes sure it has no upstream.
So, as you can see, it's complicated! The exact method of creating the branch determines in part whether it has an upstream, with the rest of the determination being based on your branch.autoSetupMerge configuration. This setting has three possible values:
true: set the upstream when the starting-point is a remote-tracking name.false: don't set the upstream.always: set the upstream when the starting-point is either a remote-tracking name or a (local) branch name.
The default, if you did not set branch.autoSetupMerge at all, is to pretend you set it to true. So by default, all of these branch-creating options act like you said --track if you give them an origin/* name, or any other remote-tracking name, as their starting-point. That's true even if the starting point is merely implied, as in the:
git checkout develop
case where you don't have a local develop but do have a remote-tracking origin/develop: this creates your new local develop from your remote-tracking origin/develop, and if branch.autoSetupMerge is true—including if you haven't set it at all—now your develop "tracks"—has as its upstream—your origin/develop.
Summary
Some of your branches have upstreams set. Which branches have upstreams, and what those upstreams are, is up to you, controlled by your configuration and/or by your command-line options and/or by additional git branch --set-upstream-to or git branch --unset-upstream commands.
Those branches that do have upstreams set will get some useful features. If the upstream that is set "goes away" by whatever process, git branch -vv will list your local branches and say that their upstream is "gone". Other Git commands will just pretend you unset their upstream. If the upstream comes back again, the upstream will resume its usefulness.
Deleting a local branch only because its upstream is gone is a mistake. Deleting it because you are done with it is fine. You don't need to have a local branch named develop, or even one named master, if you're done with them, even if they still exist as upstream origin/develop or origin/master names. You can just use origin/master to refer to your Git's memory of the master on origin—you don't need to have your own master at all.
Sometimes, you are done with a branch because of some underlying reason that also means that the upstream is going to be gone, or is already gone. In that case, deleting your local branch is fine—you're deleting it because you're done with it. The fact that it will be deleted on origin, or already has been deleted on origin, is irrelevant here!
add a comment |
It's not necessarily wise to delete your branch named X just because someone else deleted his branch named X. If you're working on a new feature and you called it feat, and Bob gave up on his new feature that he was calling feat and Bob deletes Bob's feat, that doesn't mean you should delete your feat!
That aside, let's look at a special feature of branches. This special feature is only available for (local) branches, not for things like origin/master, which parts of Git call remote-tracking branches and which are listed under git branch -r output.1 They actually have several special features—for instance, you can get "on" a branch using git checkout, as in after git checkout master, the git status command will say on branch master. But that's not the special feature I mean here.
The special feature we care about here is that they can have an upstream setting. That is, your master can have one—and only one—upstream, and your develop, if you have a develop, can have one upstream, and your feat, if you have one, can have one upstream, and so on. Your choice here is to have an upstream, or not have an upstream. You make this choice one branch at a time, for each branch.
To take away the upstream setting of a branch, use git branch --unset-upstream name. The branch named name now has no upstream. If you leave out the name part, it applies to the current branch, i.e., the one to which your HEAD is attached. This is not the only way to unset it, but it's usually the best way.
To set or change the upstream setting of a branch, use git branch --set-upstream-to=upstream name. The branch named name now has an upstream; the upstream is has is the argument you gave as upstream. As with --unset-upstream, leaving out name means the current branch (you're not allowed to leave out upstream). Likewise, this is not the only way to set it, but usually it's the best way, because the git branch command will verify whether the upstream argument is sensible before it lets you set it.
Sometimes branches have an upstream setting right from the get-go, and sometimes they don't. We'll look at when and why in a moment.
1I've gotten to the point where I try to avoid the word branch for the remote-tracking things. I now just call remote-tracking names, because they're so different from local branch names. Note that git fetch -p, or git remote prune origin, or setting fetch.prune to true, affects only these remote-tracking names.
What exactly is an upstream?
An upstream is just another branch name—and here, by branch name, I mean either a local branch like master or develop, or a remote-tracking name like origin/master. So you can have the upstream of develop set to master if you like, or to origin/master, or to origin/develop. The git branch --set-upstream-to operation will let you set anything that exists and, to Git's mind, makes sense here.
Git has a weird flaw of sorts here. Part of this is historical. Back in the ancient past, Git did not have remotes—there was no origin—so Git did not have remote-tracking names either without origin, there could be no origin/master. But part is due to the simple fact you may or may not have an origin/xyz, and origin/xyz could even go away while you're hard at work on your xyz branch (because Bob thought you were done and went and deleted xyz over on origin).
The flaw is, to put it a bit too simply, that the upstream you've set—back when it existed and git branch --set-upstream-to therefore let you set it—might be gone now. And that's the case when you see : gone in your git branch -vv output. At some point in the past, you told your Git that your branch xyz should have origin/xyz as its upstream, and origin/xyz existed at the time. So git branch verified that all was good and made the setting. But now the name is gone, so the setting is no longer valid and git branch -vv makes note of that.
In fact, the upstream setting of a branch is built out of two parts, and you can configure either or both parts with git config, or even bring your configuration in your chosen editor (git config --edit) and mess with them directly:
[branch "master"]
remote = origin
merge = refs/heads/master
This setting, in this particular repository, says that the upstream of master is origin/master. You might think you can just take the origin part from the remote = line and the master part from the merge = line, but this is a sort of trap: there's a secret complicated mapping. To find the upstream setting of some branch, use git rev-parse with the @upstream suffix:
$ git rev-parse --symbolic-full-name master@upstream
refs/remotes/origin/master
This works for branches whose upstream is set to be another local branch too.
Anyway, because it is two parts like this and you can mess with it outside the normal git branch --set-upstream-to mechanism, you can break the upstream setting. If you do break it—if you set it to something nonsensical—git branch -vv will list the upstream as "gone", using the same technique as when normal, everyday Git operations break it because it really did go away. Git does not care why it's broken, only that it is or is not broken right now: if it is broken right now, Git says "gone" and otherwise pretends it's unset.
Note that this also means that if Bob accidentally removed xyz from origin and Bob fixes his mistake and puts xyz back, your Git can go from "gone" to "not gone, everything is fine" after another git fetch. That's yet another reason you should not have your Git remove your local branch just because someone messed with some other Git somewhere else.
What good is an upstream?
The upstream setting only offers a few minor features. Sometimes, some people really like these features, but they're never required. So in one sense, an upstream is no good at all. You don't have to use them, ever, provided you avoid git pull.
The features, though, are:
Easier push: the standard
push.defaultsetting requires that your branch have an upstream if you want to rungit pushwithout extra arguments.Easier merge and rebase: the
git mergeandgit rebasecommands can use it. Thegit pullwrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runsgit fetchfor you, and then immediately—before you have a chance to decide whether it's a good idea based on whatgit fetchdid—runsgit mergeorgit rebasefor you.More-useful
git status: the first line ofgit statustells you whether you're in detached HEAD mode, and if not, which branch you're on. Having an upstream means that there's a second line, right after the one about the branch you're on, when you're on a branch. The second line compares the branch to its upstream and tells you whether it is "up to date" with its upstream.
So that's what an upstream is good for: it makes some things easier and/or more useful. But you are limited to one upstream at a time. You may, sometimes, want to get the equivalent of the git status second-line output for some arbitrary pair of names. There is a way to do that using git rev-list --count, but we'll leave that for other answers.
Why do some branches already have an upstream set, and others don't?
There are lots of ways to create branches in Git. Each one does something a little bit different from its other alternatives—which is why each of these methods exists, but also gives you this profusion of confusion.
The two main commands for creating new branches are git branch and git checkout. When you use git branch to create a new branch, you are in full control at all times:
git branch --track newbranch origin/upstreamname
or:
git branch --no-track newbranch origin/upstreamname
Despite the upstream being called upstream, the argument controlling it is spelled --track—another historical accident or mistake, really.
If you don't use --track or --no-track here, git branch uses whatever you've chosen as a default when you configured branch.autoSetupMerge. See below for what that means.
When you use git checkout, you can use --track or --no-track, but if you don't use either option, it gets more complicated. The branch.autoSetupMerge setting still matters but ... well:
git checkout -b newbranchcreatesnewbranch, but creates it fromHEAD, so it doesn't set an upstream. That is, the new namenewbranchnow identifies the same commit thatHEADidentified just before this.git checkout -b newbranch origin/namecreatesnewbranchand creates it usingorigin/name. That is, the new namenewbranchnow identifies the same commit asorigin/name. This obeys yourbranch.autoSetupMergeconfiguration.git checkout -b newbranch existing-branchcreatesnewbranch, usingexisting-branchas its starting point. That is, the new name and the existing name now identify the same commit. This also obeys yourbranch.autoSetupMergeconfiguration, but see below for why I separated this out.git checkout nameeither uses an existingname, or creates a new branch namednameusingorigin/name. If it creates a new branch, it obeysbranch.autoSetupMerge.Note that this will never create a new branch using a local branch name, i.e., it can't make a local branch that has another local branch as its upstream. If that were going to be the case, the two *
name*s would be the same, so the branch by definition already exists, so it just checks out the local branch without creating anything.git checkout --track origin/namecreates a new branch namednameand does set its upstream.git checkout --no-track origin/namecreates a new branch namednameand makes sure it has no upstream.
So, as you can see, it's complicated! The exact method of creating the branch determines in part whether it has an upstream, with the rest of the determination being based on your branch.autoSetupMerge configuration. This setting has three possible values:
true: set the upstream when the starting-point is a remote-tracking name.false: don't set the upstream.always: set the upstream when the starting-point is either a remote-tracking name or a (local) branch name.
The default, if you did not set branch.autoSetupMerge at all, is to pretend you set it to true. So by default, all of these branch-creating options act like you said --track if you give them an origin/* name, or any other remote-tracking name, as their starting-point. That's true even if the starting point is merely implied, as in the:
git checkout develop
case where you don't have a local develop but do have a remote-tracking origin/develop: this creates your new local develop from your remote-tracking origin/develop, and if branch.autoSetupMerge is true—including if you haven't set it at all—now your develop "tracks"—has as its upstream—your origin/develop.
Summary
Some of your branches have upstreams set. Which branches have upstreams, and what those upstreams are, is up to you, controlled by your configuration and/or by your command-line options and/or by additional git branch --set-upstream-to or git branch --unset-upstream commands.
Those branches that do have upstreams set will get some useful features. If the upstream that is set "goes away" by whatever process, git branch -vv will list your local branches and say that their upstream is "gone". Other Git commands will just pretend you unset their upstream. If the upstream comes back again, the upstream will resume its usefulness.
Deleting a local branch only because its upstream is gone is a mistake. Deleting it because you are done with it is fine. You don't need to have a local branch named develop, or even one named master, if you're done with them, even if they still exist as upstream origin/develop or origin/master names. You can just use origin/master to refer to your Git's memory of the master on origin—you don't need to have your own master at all.
Sometimes, you are done with a branch because of some underlying reason that also means that the upstream is going to be gone, or is already gone. In that case, deleting your local branch is fine—you're deleting it because you're done with it. The fact that it will be deleted on origin, or already has been deleted on origin, is irrelevant here!
It's not necessarily wise to delete your branch named X just because someone else deleted his branch named X. If you're working on a new feature and you called it feat, and Bob gave up on his new feature that he was calling feat and Bob deletes Bob's feat, that doesn't mean you should delete your feat!
That aside, let's look at a special feature of branches. This special feature is only available for (local) branches, not for things like origin/master, which parts of Git call remote-tracking branches and which are listed under git branch -r output.1 They actually have several special features—for instance, you can get "on" a branch using git checkout, as in after git checkout master, the git status command will say on branch master. But that's not the special feature I mean here.
The special feature we care about here is that they can have an upstream setting. That is, your master can have one—and only one—upstream, and your develop, if you have a develop, can have one upstream, and your feat, if you have one, can have one upstream, and so on. Your choice here is to have an upstream, or not have an upstream. You make this choice one branch at a time, for each branch.
To take away the upstream setting of a branch, use git branch --unset-upstream name. The branch named name now has no upstream. If you leave out the name part, it applies to the current branch, i.e., the one to which your HEAD is attached. This is not the only way to unset it, but it's usually the best way.
To set or change the upstream setting of a branch, use git branch --set-upstream-to=upstream name. The branch named name now has an upstream; the upstream is has is the argument you gave as upstream. As with --unset-upstream, leaving out name means the current branch (you're not allowed to leave out upstream). Likewise, this is not the only way to set it, but usually it's the best way, because the git branch command will verify whether the upstream argument is sensible before it lets you set it.
Sometimes branches have an upstream setting right from the get-go, and sometimes they don't. We'll look at when and why in a moment.
1I've gotten to the point where I try to avoid the word branch for the remote-tracking things. I now just call remote-tracking names, because they're so different from local branch names. Note that git fetch -p, or git remote prune origin, or setting fetch.prune to true, affects only these remote-tracking names.
What exactly is an upstream?
An upstream is just another branch name—and here, by branch name, I mean either a local branch like master or develop, or a remote-tracking name like origin/master. So you can have the upstream of develop set to master if you like, or to origin/master, or to origin/develop. The git branch --set-upstream-to operation will let you set anything that exists and, to Git's mind, makes sense here.
Git has a weird flaw of sorts here. Part of this is historical. Back in the ancient past, Git did not have remotes—there was no origin—so Git did not have remote-tracking names either without origin, there could be no origin/master. But part is due to the simple fact you may or may not have an origin/xyz, and origin/xyz could even go away while you're hard at work on your xyz branch (because Bob thought you were done and went and deleted xyz over on origin).
The flaw is, to put it a bit too simply, that the upstream you've set—back when it existed and git branch --set-upstream-to therefore let you set it—might be gone now. And that's the case when you see : gone in your git branch -vv output. At some point in the past, you told your Git that your branch xyz should have origin/xyz as its upstream, and origin/xyz existed at the time. So git branch verified that all was good and made the setting. But now the name is gone, so the setting is no longer valid and git branch -vv makes note of that.
In fact, the upstream setting of a branch is built out of two parts, and you can configure either or both parts with git config, or even bring your configuration in your chosen editor (git config --edit) and mess with them directly:
[branch "master"]
remote = origin
merge = refs/heads/master
This setting, in this particular repository, says that the upstream of master is origin/master. You might think you can just take the origin part from the remote = line and the master part from the merge = line, but this is a sort of trap: there's a secret complicated mapping. To find the upstream setting of some branch, use git rev-parse with the @upstream suffix:
$ git rev-parse --symbolic-full-name master@upstream
refs/remotes/origin/master
This works for branches whose upstream is set to be another local branch too.
Anyway, because it is two parts like this and you can mess with it outside the normal git branch --set-upstream-to mechanism, you can break the upstream setting. If you do break it—if you set it to something nonsensical—git branch -vv will list the upstream as "gone", using the same technique as when normal, everyday Git operations break it because it really did go away. Git does not care why it's broken, only that it is or is not broken right now: if it is broken right now, Git says "gone" and otherwise pretends it's unset.
Note that this also means that if Bob accidentally removed xyz from origin and Bob fixes his mistake and puts xyz back, your Git can go from "gone" to "not gone, everything is fine" after another git fetch. That's yet another reason you should not have your Git remove your local branch just because someone messed with some other Git somewhere else.
What good is an upstream?
The upstream setting only offers a few minor features. Sometimes, some people really like these features, but they're never required. So in one sense, an upstream is no good at all. You don't have to use them, ever, provided you avoid git pull.
The features, though, are:
Easier push: the standard
push.defaultsetting requires that your branch have an upstream if you want to rungit pushwithout extra arguments.Easier merge and rebase: the
git mergeandgit rebasecommands can use it. Thegit pullwrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runsgit fetchfor you, and then immediately—before you have a chance to decide whether it's a good idea based on whatgit fetchdid—runsgit mergeorgit rebasefor you.More-useful
git status: the first line ofgit statustells you whether you're in detached HEAD mode, and if not, which branch you're on. Having an upstream means that there's a second line, right after the one about the branch you're on, when you're on a branch. The second line compares the branch to its upstream and tells you whether it is "up to date" with its upstream.
So that's what an upstream is good for: it makes some things easier and/or more useful. But you are limited to one upstream at a time. You may, sometimes, want to get the equivalent of the git status second-line output for some arbitrary pair of names. There is a way to do that using git rev-list --count, but we'll leave that for other answers.
Why do some branches already have an upstream set, and others don't?
There are lots of ways to create branches in Git. Each one does something a little bit different from its other alternatives—which is why each of these methods exists, but also gives you this profusion of confusion.
The two main commands for creating new branches are git branch and git checkout. When you use git branch to create a new branch, you are in full control at all times:
git branch --track newbranch origin/upstreamname
or:
git branch --no-track newbranch origin/upstreamname
Despite the upstream being called upstream, the argument controlling it is spelled --track—another historical accident or mistake, really.
If you don't use --track or --no-track here, git branch uses whatever you've chosen as a default when you configured branch.autoSetupMerge. See below for what that means.
When you use git checkout, you can use --track or --no-track, but if you don't use either option, it gets more complicated. The branch.autoSetupMerge setting still matters but ... well:
git checkout -b newbranchcreatesnewbranch, but creates it fromHEAD, so it doesn't set an upstream. That is, the new namenewbranchnow identifies the same commit thatHEADidentified just before this.git checkout -b newbranch origin/namecreatesnewbranchand creates it usingorigin/name. That is, the new namenewbranchnow identifies the same commit asorigin/name. This obeys yourbranch.autoSetupMergeconfiguration.git checkout -b newbranch existing-branchcreatesnewbranch, usingexisting-branchas its starting point. That is, the new name and the existing name now identify the same commit. This also obeys yourbranch.autoSetupMergeconfiguration, but see below for why I separated this out.git checkout nameeither uses an existingname, or creates a new branch namednameusingorigin/name. If it creates a new branch, it obeysbranch.autoSetupMerge.Note that this will never create a new branch using a local branch name, i.e., it can't make a local branch that has another local branch as its upstream. If that were going to be the case, the two *
name*s would be the same, so the branch by definition already exists, so it just checks out the local branch without creating anything.git checkout --track origin/namecreates a new branch namednameand does set its upstream.git checkout --no-track origin/namecreates a new branch namednameand makes sure it has no upstream.
So, as you can see, it's complicated! The exact method of creating the branch determines in part whether it has an upstream, with the rest of the determination being based on your branch.autoSetupMerge configuration. This setting has three possible values:
true: set the upstream when the starting-point is a remote-tracking name.false: don't set the upstream.always: set the upstream when the starting-point is either a remote-tracking name or a (local) branch name.
The default, if you did not set branch.autoSetupMerge at all, is to pretend you set it to true. So by default, all of these branch-creating options act like you said --track if you give them an origin/* name, or any other remote-tracking name, as their starting-point. That's true even if the starting point is merely implied, as in the:
git checkout develop
case where you don't have a local develop but do have a remote-tracking origin/develop: this creates your new local develop from your remote-tracking origin/develop, and if branch.autoSetupMerge is true—including if you haven't set it at all—now your develop "tracks"—has as its upstream—your origin/develop.
Summary
Some of your branches have upstreams set. Which branches have upstreams, and what those upstreams are, is up to you, controlled by your configuration and/or by your command-line options and/or by additional git branch --set-upstream-to or git branch --unset-upstream commands.
Those branches that do have upstreams set will get some useful features. If the upstream that is set "goes away" by whatever process, git branch -vv will list your local branches and say that their upstream is "gone". Other Git commands will just pretend you unset their upstream. If the upstream comes back again, the upstream will resume its usefulness.
Deleting a local branch only because its upstream is gone is a mistake. Deleting it because you are done with it is fine. You don't need to have a local branch named develop, or even one named master, if you're done with them, even if they still exist as upstream origin/develop or origin/master names. You can just use origin/master to refer to your Git's memory of the master on origin—you don't need to have your own master at all.
Sometimes, you are done with a branch because of some underlying reason that also means that the upstream is going to be gone, or is already gone. In that case, deleting your local branch is fine—you're deleting it because you're done with it. The fact that it will be deleted on origin, or already has been deleted on origin, is irrelevant here!
answered 8 hours ago
torektorek
194k18242322
194k18242322
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55020899%2fgit-fetch-not-working-as-expected-gone-is-not-being-added-to-branch-descript%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
I am also interested in this question. I have an unsatisfactory alias (to output local branches which lack a remote counterpart) that I'd love to replace one of these days (
git config --global alias.brloc '!git branch -vv | grep -v origin; git branch -vv | grep gone').– RomainValeri
15 hours ago