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

GPL code private and stolen

When was drinking water recognized as crucial in marathon running?

What is better: yes / no radio, or simple checkbox?

“I had a flat in the centre of town, but I didn’t like living there, so …”

Can a Trickery Domain cleric cast a spell through the Invoke Duplicity clone while inside a Forcecage?

Why are special aircraft used for the carriers in the United States Navy?

Practical reasons to have both a large police force and bounty hunting network?

What can I do if someone tampers with my SSH public key?

Why won't the strings command stop?

How to disable or uninstall iTunes under High Sierra without disabling SIP

If nine coins are tossed, what is the probability that the number of heads is even?

A bug in Excel? Conditional formatting for marking duplicates also highlights unique value

Meaning of '4:1 (3:0)' as score in football (World Cup match)

Misplaced tyre lever - alternatives?

Caulking a corner instead of taping with joint compound?

Script that counts quarters, dimes, nickels, and pennies

Quitting employee has privileged access to critical information

An Undercover Army

Called into a meeting and told we are being made redundant (laid off) and "not to share outside". Can I tell my partner?

Create chunks from an array

Should we avoid writing fiction about historical events without extensive research?

Why would the IRS ask for birth certificates or even audit a small tax return?

Is there any relevance to Thor getting his hair cut other than comedic value?

How do I deal with being envious of my own players?



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










2















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 ?










share|improve this question
























  • 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
    19 hours ago
















2















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 ?










share|improve this question
























  • 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
    19 hours ago














2












2








2








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 ?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 20 hours ago







Sanjay Yadav

















asked 20 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
    19 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
    19 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
19 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
19 hours ago













1 Answer
1






active

oldest

votes


















0














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.default setting requires that your branch have an upstream if you want to run git push without extra arguments.


  • Easier merge and rebase: the git merge and git rebase commands can use it. The git pull wrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runs git fetch for you, and then immediately—before you have a chance to decide whether it's a good idea based on what git fetch did—runs git merge or git rebase for you.


  • More-useful git status: the first line of git status tells 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 newbranch creates newbranch, but creates it from HEAD, so it doesn't set an upstream. That is, the new name newbranch now identifies the same commit that HEAD identified just before this.



  • git checkout -b newbranch origin/name creates newbranch and creates it using origin/name. That is, the new name newbranch now identifies the same commit as origin/name. This obeys your branch.autoSetupMerge configuration.



    git checkout -b newbranch existing-branch creates newbranch, using existing-branch as its starting point. That is, the new name and the existing name now identify the same commit. This also obeys your branch.autoSetupMerge configuration, but see below for why I separated this out.




  • git checkout name either uses an existing name, or creates a new branch named name using origin/name. If it creates a new branch, it obeys branch.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/name creates a new branch named name and does set its upstream.


  • git checkout --no-track origin/name creates a new branch named name and 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!






share|improve this answer






















    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
    );



    );













    draft saved

    draft discarded


















    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









    0














    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.default setting requires that your branch have an upstream if you want to run git push without extra arguments.


    • Easier merge and rebase: the git merge and git rebase commands can use it. The git pull wrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runs git fetch for you, and then immediately—before you have a chance to decide whether it's a good idea based on what git fetch did—runs git merge or git rebase for you.


    • More-useful git status: the first line of git status tells 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 newbranch creates newbranch, but creates it from HEAD, so it doesn't set an upstream. That is, the new name newbranch now identifies the same commit that HEAD identified just before this.



    • git checkout -b newbranch origin/name creates newbranch and creates it using origin/name. That is, the new name newbranch now identifies the same commit as origin/name. This obeys your branch.autoSetupMerge configuration.



      git checkout -b newbranch existing-branch creates newbranch, using existing-branch as its starting point. That is, the new name and the existing name now identify the same commit. This also obeys your branch.autoSetupMerge configuration, but see below for why I separated this out.




    • git checkout name either uses an existing name, or creates a new branch named name using origin/name. If it creates a new branch, it obeys branch.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/name creates a new branch named name and does set its upstream.


    • git checkout --no-track origin/name creates a new branch named name and 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!






    share|improve this answer



























      0














      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.default setting requires that your branch have an upstream if you want to run git push without extra arguments.


      • Easier merge and rebase: the git merge and git rebase commands can use it. The git pull wrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runs git fetch for you, and then immediately—before you have a chance to decide whether it's a good idea based on what git fetch did—runs git merge or git rebase for you.


      • More-useful git status: the first line of git status tells 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 newbranch creates newbranch, but creates it from HEAD, so it doesn't set an upstream. That is, the new name newbranch now identifies the same commit that HEAD identified just before this.



      • git checkout -b newbranch origin/name creates newbranch and creates it using origin/name. That is, the new name newbranch now identifies the same commit as origin/name. This obeys your branch.autoSetupMerge configuration.



        git checkout -b newbranch existing-branch creates newbranch, using existing-branch as its starting point. That is, the new name and the existing name now identify the same commit. This also obeys your branch.autoSetupMerge configuration, but see below for why I separated this out.




      • git checkout name either uses an existing name, or creates a new branch named name using origin/name. If it creates a new branch, it obeys branch.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/name creates a new branch named name and does set its upstream.


      • git checkout --no-track origin/name creates a new branch named name and 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!






      share|improve this answer

























        0












        0








        0







        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.default setting requires that your branch have an upstream if you want to run git push without extra arguments.


        • Easier merge and rebase: the git merge and git rebase commands can use it. The git pull wrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runs git fetch for you, and then immediately—before you have a chance to decide whether it's a good idea based on what git fetch did—runs git merge or git rebase for you.


        • More-useful git status: the first line of git status tells 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 newbranch creates newbranch, but creates it from HEAD, so it doesn't set an upstream. That is, the new name newbranch now identifies the same commit that HEAD identified just before this.



        • git checkout -b newbranch origin/name creates newbranch and creates it using origin/name. That is, the new name newbranch now identifies the same commit as origin/name. This obeys your branch.autoSetupMerge configuration.



          git checkout -b newbranch existing-branch creates newbranch, using existing-branch as its starting point. That is, the new name and the existing name now identify the same commit. This also obeys your branch.autoSetupMerge configuration, but see below for why I separated this out.




        • git checkout name either uses an existing name, or creates a new branch named name using origin/name. If it creates a new branch, it obeys branch.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/name creates a new branch named name and does set its upstream.


        • git checkout --no-track origin/name creates a new branch named name and 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!






        share|improve this answer













        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.default setting requires that your branch have an upstream if you want to run git push without extra arguments.


        • Easier merge and rebase: the git merge and git rebase commands can use it. The git pull wrapper, which you don't have to use ever and which I recommend avoiding anyway, require an upstream. The wrapper first runs git fetch for you, and then immediately—before you have a chance to decide whether it's a good idea based on what git fetch did—runs git merge or git rebase for you.


        • More-useful git status: the first line of git status tells 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 newbranch creates newbranch, but creates it from HEAD, so it doesn't set an upstream. That is, the new name newbranch now identifies the same commit that HEAD identified just before this.



        • git checkout -b newbranch origin/name creates newbranch and creates it using origin/name. That is, the new name newbranch now identifies the same commit as origin/name. This obeys your branch.autoSetupMerge configuration.



          git checkout -b newbranch existing-branch creates newbranch, using existing-branch as its starting point. That is, the new name and the existing name now identify the same commit. This also obeys your branch.autoSetupMerge configuration, but see below for why I separated this out.




        • git checkout name either uses an existing name, or creates a new branch named name using origin/name. If it creates a new branch, it obeys branch.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/name creates a new branch named name and does set its upstream.


        • git checkout --no-track origin/name creates a new branch named name and 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!







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 13 hours ago









        torektorek

        194k18242322




        194k18242322





























            draft saved

            draft discarded
















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            1928 у кіно

            Захаров Федір Захарович

            Ель Греко