How to clone from specific branch from Git using Gitpython
Asked Answered
G

4

13

I tried to clone a repository from git using GitPython in python function. I used GitPython library for cloning from git in my python function and my code snippet as follows:

from git import Repo

Repo.clone_from('http://user:[email protected]/user/project.git', /home/antro/Project/')

It clones from master branch. How do I clone from other branch using GitPython or any other library is available to clone from individual branches? Please let me know.

I am aware of clone by mentioning branch in commandline using

git clone -b branch http://github.com/user/project.git

Glittery answered 20/4, 2017 at 13:23 Comment(6)
There is no such thing as "cloning from a branch". When you clone, you clone the whole repo. What clone -b does is, after cloning the entire repo, it checks out the specific branch instead of the default branch (which is usually master). So instead of looking for something exotic, why not just do a branch checkout after the clone?Ard
@MarkAdelsberger "yes, but" git clone --single-branchHenshaw
@MichałPolitowski - Oh, yes. That. I forget about that because it has only ever caused me trouble. Any more I only use the negation of that flag (for making shallow repos that aren't hobbled). Well, I would still take the position that OP probably means just to check out the branch and is conflating terms, since the CLI command specified in the question does clone the whole repo.Ard
@MarkAdelsberger How to checkout into another branch in python function. and clone -b clones particular branch, it existGlittery
@Antro - If I knew the python command I'd have posted an answer instead of a comment. And no, clone -b does not clone a particular branch. It checks out a particular branch.Ard
@MarkAdelsberger I didn't know much about git. Sorry for any misunderstanding by me. Thanks for your clearance.Glittery
S
25

just pass the branch name parameter, e.g. :-

repo = Repo.clone_from(
    'http://user:[email protected]/user/project.git',
    '/home/antro/Project/',
    branch='master'
)

see here for more info

Scheelite answered 20/4, 2017 at 13:54 Comment(1)
how to add --single-branch option?Oratorical
K
3

From toanant's answer.

This works for me with the --single-branch option

repo = Repo.clone_from(
    'http://user:[email protected]/user/project.git --single-branch',
    '/home/antro/Project/',
    branch='master'
)
Kroo answered 11/11, 2019 at 7:50 Comment(0)
I
3

GitPython uses a keyword args transformation under the hood:

# cmd.py
def transform_kwarg(self, name: str, value: Any, split_single_char_options: bool) -> List[str]:
    if len(name) == 1:
        if value is True:
            return ["-%s" % name]
        elif value not in (False, None):
            if split_single_char_options:
                return ["-%s" % name, "%s" % value]
            else:
                return ["-%s%s" % (name, value)]
    else:
        if value is True:
            return ["--%s" % dashify(name)]
        elif value is not False and value is not None:
            return ["--%s=%s" % (dashify(name), value)]
    return []

A resulting list of command parts is fed into subprocess.Popen, so you do not want to add --single-branch to the repo URL. If you do, a strange list will be passed to Popen. For example:

['-v', '--branch=my-branch', 'https://github.com/me/my-project.git --single-branch', '/tmp/clone/here']

However, armed with this new information, you can pass any git CLI flags you like just by using the kwargs. You may then ask yourself, "How do I pass in a dash to a keyword like single-branch?" That's a no-go in Python. You will see a dashify function in the above code which transforms any flag from, say, single_branch=True to single-branch, and then to --single-branch.

Full Example:

Here is a useful example for cloning a single, shallow branch using a personal access token from GitHub:

repo_url = "https://github.com/me/private-project.git"
branch = "wip-branch"
# Notice the trailing : below
credentials = base64.b64encode(f"{GHE_TOKEN}:".encode("latin-1")).decode("latin-1")
Repo.clone_from(
    url=repo_url,
    c=f"http.{repo_url}/.extraheader=AUTHORIZATION: basic {credentials}",
    single_branch=True,
    depth=1,
    to_path=f"/clone/to/here",
    branch=branch,
)

The command list sent to Popen then looks like this:

['git', 'clone', '-v', '-c', 'http.https://github.com/me/private-project.git/.extraheader=AUTHORIZATION: basic XTE...UwNTo=', '--single-branch', '--depth=1', '--bare', '--branch=wip-branch', 'https://github.com/me/private-project.git', '/clone/to/here']

(PSA: Please do not actually send your personal tokens as part of the URL before the @.)

Intervocalic answered 17/7, 2021 at 22:16 Comment(2)
thank you for the example and the explanation. I'd like to understand why you're doing credentials = base64.b64encode(f"{GHE_TOKEN}:".encode("latin-1")).decode("latin-1").Nape
Ah. IIRC b64encode results in bytes. The RFC spec wants the authorization header in latin-1 (ascii). So I encoded the token in latin-1 first to be sure it could be decoded correctly, ran base64 to get bytes, then decoded it back to ascii to be certain the HTTP header will accept it. The first latin-1 could be skipped, perhaps, but it is userland input, so sneaky, invisible UTF-8 spaces could make their way into the token. Some people watermark their code/strings or add invisible chars to try for buffer overflows, so I got in the habit of defensive coding as well. Good question.Intervocalic
O
1

For --single-branch option, you can just pass a single_branch argument to the Repo.clone_from() method:

Repo.clone_from(repo, path, single_branch=True, b='branch')
Outsmart answered 22/4, 2021 at 12:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.