Why call git branch --unset-upstream to fixup?

后端 未结 8 1290
夕颜
夕颜 2020-12-12 09:42

I\'m more of a novice when it comes to advanced operations in git. I maintain my blog using the blogging framework Octopress. Though Octopress is not under any development s

相关标签:
8条回答
  • 2020-12-12 10:33

    TL;DR version: remote-tracking branch origin/master used to exist, but does not now, so local branch source is tracking something that does not exist, which is suspicious at best—it means a different Git feature is unable to do anything for you—and Git is warning you about it. You have been getting along just fine without having the "upstream tracking" feature work as intended, so it's up to you whether to change anything.

    For another take on upstream settings, see Why do I have to "git push --set-upstream origin <branch>"?


    This warning is a new thing in Git, appearing first in Git 1.8.5. The release notes contain just one short bullet-item about it:

    • "git branch -v -v" (and "git status") did not distinguish among a branch that is not based on any other branch, a branch that is in sync with its upstream branch, and a branch that is configured with an upstream branch that no longer exists.

    To describe what it means, you first need to know about "remotes", "remote-tracking branches", and how Git handles "tracking an upstream". (Remote-tracking branches is a terribly flawed term—I've started using remote-tracking names instead, which I think is a slight improvement. Below, though, I'll use "remote-tracking branch" for consistency with Git documentation.)

    Each "remote" is simply a name, like origin or octopress in this case. Their purpose is to record things like the full URL of the places from which you git fetch or git pull updates. When you use git fetch remote,1 Git goes to that remote (using the saved URL) and brings over the appropriate set of updates. It also records the updates, using "remote-tracking branches".

    A "remote-tracking branch" (or remote-tracking name) is simply a recording of a branch name as-last-seen on some "remote". Each remote is itself a Git repository, so it has branches. The branches on remote "origin" are recorded in your local repository under remotes/origin/. The text you showed says that there's a branch named source on origin, and branches named 2.1, linklog, and so on on octopress.

    (A "normal" or "local" branch, of course, is just a branch-name that you have created in your own repository.)

    Last, you can set up a (local) branch to "track" a "remote-tracking branch". Once local branch L is set to track remote-tracking branch R, Git will call R its "upstream" and tell you whether you're "ahead" and/or "behind" the upstream (in terms of commits). It's normal (even recommend-able) for the local branch and remote-tracking branches to use the same name (except for the remote prefix part), like source and origin/source, but that's not actually necessary.

    And in this case, that's not happening. You have a local branch source tracking a remote-tracking branch origin/master.

    You're not supposed to need to know the exact mechanics of how Git sets up a local branch to track a remote one, but they are relevant below, so I'll show how this works. We start with your local branch name, source. There are two configuration entries using this name, spelled branch.source.remote and branch.source.merge. From the output you showed, it's clear that these are both set, so that you'd see the following if you ran the given commands:

    $ git config --get branch.source.remote
    origin
    $ git config --get branch.source.merge
    refs/heads/master
    

    Putting these together,2 this tells Git that your branch source tracks your "remote-tracking branch", origin/master.

    But now look at the output of git branch -a, which shows all the local and remote-tracking branch names in your repository. The remote-tracking names are listed under remotes/ ... and there is no remotes/origin/master. Presumably there was, at one time, but it's gone now.

    Git is telling you that you can remove the tracking information with --unset-upstream. This will clear out both branch.source.origin and branch.source.merge, and stop the warning.

    It seems fairly likely that what you want, though, is to switch from tracking origin/master, to tracking something else: probably origin/source, but maybe one of the octopress/ names.

    You can do this with git branch --set-upstream-to,3 e.g.:

    $ git branch --set-upstream-to=origin/source
    

    (assuming you're still on branch "source", and that origin/source is the upstream you want—there is no way for me to tell which one, if any, you actually want, though).

    (See also How do you make an existing Git branch track a remote branch?)

    I think the way you got here is that when you first did a git clone, the thing you cloned-from had a branch master. You also had a branch master, which was set to track origin/master (this is a normal, standard setup for git). This meant you had branch.master.remote and branch.master.merge set, to origin and refs/heads/master. But then your origin remote changed its name from master to source. To match, I believe you also changed your local name from master to source. This changed the names of your settings, from branch.master.remote to branch.source.remote and from branch.master.merge to branch.source.merge ... but it left the old values, so branch.source.merge was now wrong.

    It was at this point that the "upstream" linkage broke, but in Git versions older than 1.8.5, Git never noticed the broken setting. Now that you have 1.8.5, it's pointing this out.


    That covers most of the questions, but not the "do I need to fix it" one. It's likely that you have been working around the broken-ness for years now, by doing git pull remote branch (e.g., git pull origin source). If you keep doing that, it will keep working around the problem—so, no, you don't need to fix it. If you like, you can use --unset-upstream to remove the upstream and stop the complaints, and not have local branch source marked as having any upstream at all.

    The point of having an upstream is to make various operations more convenient. For instance, git fetch followed by git merge will generally "do the right thing" if the upstream is set correctly, and git status after git fetch will tell you whether your repo matches the upstream one, for that branch.

    If you want the convenience, re-set the upstream.


    1git pull uses git fetch, and as of Git 1.8.4, this (finally!) also updates the "remote-tracking branch" information. In older versions of Git, the updates did not get recorded in remote-tracking branches with git pull, only with git fetch. Since your Git must be at least version 1.8.5 this is not an issue for you.

    2Well, this plus a configuration line I'm deliberately ignoring that is found under remote.origin.fetch. Git has to map the "merge" name to figure out that the full local name for the remote-branch is refs/remotes/origin/master. The mapping almost always works just like this, though, so it's predictable that master goes to origin/master.

    3Or, with git config. If you just want to set the upstream to origin/source the only part that has to change is branch.source.merge, and git config branch.source.merge refs/heads/source would do it. But --set-upstream-to says what you want done, rather than making you go do it yourself manually, so that's a "better way".

    0 讨论(0)
  • 2020-12-12 10:33

    Actually torek told you already how to use the tools much better than I would be able to do. However, in this case I think it is important to point out something peculiar if you follow the guidelines at http://octopress.org/docs/deploying/github/. Namely, you will have multiple github repositories in your setup. First of all the one with all the source code for your website in say the directory $WEBSITE, and then the one with only the static generated files residing in $WEBSITE/_deploy. The funny thing of the setup is that there is a .gitignore file in the $WEBSITE directory so that this setup actually works.

    Enough introduction. In this case the error might also come from the repository in _deploy.

    cd _deploy
    
    git branch -a
    * master
    remotes/origin/master
    remotes/origin/source
    

    In .git/config you will normally need to find something like this:

    [core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
    [remote "origin"]
        url = git@github.com:yourname/yourname.github.io.git
        fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
        remote = origin
        merge = refs/heads/master
    

    But in your case the branch master does not have a remote.

    [core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
    [remote "origin"]
        url = git@github.com:yourname/yourname.github.io.git
        fetch = +refs/heads/*:refs/remotes/origin/*
    

    Which you can solve by:

    cd _deploy
    git branch --set-upstream-to=origin/master
    

    So, everything is as torek told you, but it might be important to point out that this very well might concern the _deploy directory rather than the root of your website.

    PS: It might be worth to use a shell such as zsh with a git plugin to not be bitten by this thing in the future. It will immediately show that _deploy concerns a different repository.

    0 讨论(0)
提交回复
热议问题