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:password@github.com/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

Antony
  • 581
  • 4
  • 7
  • 24
  • 2
    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? – Mark Adelsberger Apr 20 '17 at 13:29
  • @MarkAdelsberger "yes, but" `git clone --single-branch` – Michał Politowski Apr 20 '17 at 13:36
  • @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. – Mark Adelsberger Apr 20 '17 at 13:41
  • @MarkAdelsberger How to checkout into another branch in python function. and **clone -b** clones particular branch, it exist – Antony Apr 20 '17 at 13:42
  • 1
    @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. – Mark Adelsberger Apr 20 '17 at 13:43
  • @MarkAdelsberger I didn't know much about git. Sorry for any misunderstanding by me. Thanks for your clearance. – Antony Apr 20 '17 at 13:45

4 Answers4

25

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

repo = Repo.clone_from(
    'http://user:password@github.com/user/project.git',
    '/home/antro/Project/',
    branch='master'
)

see here for more info

toanant
  • 331
  • 3
  • 9
3

From toanant's answer.

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

repo = Repo.clone_from(
    'http://user:password@github.com/user/project.git --single-branch',
    '/home/antro/Project/',
    branch='master'
)
das-g
  • 9,718
  • 4
  • 38
  • 80
Nam Pham
  • 316
  • 1
  • 6
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 @.)

Drakes
  • 23,254
  • 3
  • 51
  • 94
  • 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")`. – cybervedaa Feb 21 '22 at 19:46
  • 1
    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. – Drakes Feb 21 '22 at 21:47
0

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')
Hlib Babii
  • 599
  • 1
  • 7
  • 24