Search code examples
gitsubprocesspython-3.7git-fetch

git fetch https://<access-token>url-to-repo :git-branch not working


I have a git repo with master and branch1. on branch1- I cloned in two locations and I have to reset it to one previous commit in one location and then force push it to remote and fetch it to another location and reset it. I have to do it in some python script with subprocess. As I am able to reset in location1 and force push to remote, but I am not able to fetch it in location2 with the access token in https URL. If I could give credentials directly it works fine but not with access token URL.

Tried: git fetch https://<access-token>@repo-url :origin/branch1 which outputs

  • branch HEAD -> FETCH_HEAD

but origin/branch1 didn't go to the commit where the remote head is there, so I am not able to reset that specific commit. while:

  git fetch
  prompt - username <entered>
  prompt - password <entered>

makes origin/branch1 to the commit where I want and then I able to reset to it.

I expect some way to run git fetch command (can include credentials or access-token) and fetch the remote changes on branch1 so that I can reset it. As I am running from python subprocess, I couldn't provide credentials for the prompt.


Solution

  • git fetch https://<access-token>@repo-url :origin/branch1

    The arguments to git fetch are:

    • the name of a remote ... or, if you're going to be stubborn, you can use a raw URL here instead of the name of a remote, and that's what you've done;
    • any number of refspecs. You have used one refspec, specifically :origin/branch1.

    Refspecs have a general form of src:dst, where the src part is the name of a reference—e.g., a branch or tag name—found in the source repository, and dst is the name found in your own repository. (This may be prefixed by a force-flag +.) In this case you omitted the source and provided only a destination. Since you're using git fetch, the other Git is the source. So here, you have not provided the name of the branch in the source repository and git fetch will not attempt to guess.

    If you wish to use their branch1 as the source of your origin/branch1, provide a correct refspec. It's wise to use full reference names as well:

    git fetch <url> refs/heads/branch1:refs/remotes/origin/branch1
    

    for example.

    A standard fetch, using a remote name instead of a URL, obtains the default refspec from the remote.name.fetch setting. For a remote named origin this is typically:

    +refs/heads/*:refs/remotes/origin/*
    

    so that git fetch origin obtains all of their branch names (refs/heads/*), and uses those to forcibly update all of your corresponding remote-tracking names (refs/remotes/origin/*, with the * being filled in appropriately automatically). If the reason you're providing a raw URL, rather than the remote name origin, is that you need to insert the access token, you can do this and extract the remote.origin.fetch setting. For example:

    p = subprocess.run(["git", "config", "--get-all", "remote.origin.fetch"],
        capture_output=True, text=True)
    # for python 3.6 or earlier, use
    #   stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
    
    p.check_returncode()
    if p.stderr != "":
        ... do something here ...
    refspecs = p.stdout.rstrip('\n').split('\n')
    

    You can now add refspecs (a list of strings) to your git fetch arguments.


    Alternatively, if you must do this often, you might just add a remote that has the desired access token in it. Note that you can configure the fetch refspec of an alternative remote to overwrite refs/remotes/origin/* even if the new remote is named something other than origin. For instance:

    git remote add tokenized-origin <url-with-token>
    git config remote.tokenized-origin.fetch '+refs/heads/*:refs/remotes/origin/*'
    

    and then just:

    git fetch tokenized-origin
    

    whenever you want to do this update using the URL-with-embedded-token.