GitPython Quick Start Tutorial

Welcome to the GitPython Quickstart Guide! Designed for developers seeking a practical and interactive learning experience, this concise resource offers step-by-step code snippets to swiftly initialize/clone repositories, perform essential Git operations, and explore GitPython’s capabilities. Get ready to dive in, experiment, and unleash the power of GitPython in your projects!

git.Repo

There are a few ways to create agit.Repo object

Initialize a new git Repo

# $ git init <path/to/dir>fromgitimportReporepo=Repo.init(path_to_dir)

Existing local git Repo

repo=Repo(path_to_dir)

Clone from URL

For the rest of this tutorial we will use a clone fromhttps://github.com/gitpython-developers/QuickStartTutorialFiles.git

# $ git clone <url> <local_dir>repo_url="https://github.com/gitpython-developers/QuickStartTutorialFiles.git"repo=Repo.clone_from(repo_url,local_dir)

Trees & Blobs

Latest Commit Tree

tree=repo.head.commit.tree

Any Commit Tree

prev_commits=list(repo.iter_commits(all=True,max_count=10))# Last 10 commits from all branches.tree=prev_commits[0].tree

Display level 1 Contents

files_and_dirs=[(entry,entry.name,entry.type)forentryintree]files_and_dirs# Output# [(< git.Tree "SHA1-HEX_HASH" >, 'Downloads', 'tree'),#  (< git.Tree "SHA1-HEX_HASH" >, 'dir1', 'tree'),#  (< git.Blob "SHA1-HEX_HASH" >, 'file4.txt', 'blob')]

Recurse through the Tree

defprint_files_from_git(root,level=0):forentryinroot:print(f'{"-"*4*level}|{entry.path},{entry.type}')ifentry.type=="tree":print_files_from_git(entry,level+1)
print_files_from_git(tree)# Output# | Downloads, tree# ----| Downloads / file3.txt, blob# | dir1, tree# ----| dir1 / file1.txt, blob# ----| dir1 / file2.txt, blob# | file4.txt, blob

Usage

Add file to staging area

# We must make a change to a file so that we can add the update to gitupdate_file="dir1/file2.txt"# we'll use local_dir/dir1/file2.txtwithopen(f"{local_dir}/{update_file}","a")asf:f.write("\nUpdate version 2")

Now lets add the updated file to git

# $ git add <file>add_file=[update_file]# relative path from git rootrepo.index.add(add_file)# notice the add function requires a list of paths

Notice the add method requires a list as a parameter

Warning: If you experience any trouble with this, try to invokegit instead via repo.git.add(path)

Commit

# $ git commit -m <message>repo.index.commit("Update to file2")

List of commits associated with a file

# $ git log <file># Relative path from git rootrepo.iter_commits(all=True,max_count=10,paths=update_file)# Gets the last 10 commits from all branches.# Outputs: <generator object Commit._iter_from_process_or_stream at 0x7fb66c186cf0>

Notice this returns a generator object

commits_for_file_generator=repo.iter_commits(all=True,max_count=10,paths=update_file)commits_for_file=list(commits_for_file_generator)commits_for_file# Outputs: [<git.Commit "SHA1-HEX_HASH-2">,# <git.Commit "SHA1-HEX-HASH-1">]

returns list ofCommit objects

Printing text files

Lets print the latest version of<local_dir>/dir1/file2.txt

print_file="dir1/file2.txt"tree[print_file]# The head commit tree.# Output <git.Blob "SHA1-HEX-HASH">
blob=tree[print_file]print(blob.data_stream.read().decode())# Output# File 2 version 1# Update version 2

Previous version of<local_dir>/dir1/file2.txt

commits_for_file=list(repo.iter_commits(all=True,paths=print_file))tree=commits_for_file[-1].tree# Gets the first commit tree.blob=tree[print_file]print(blob.data_stream.read().decode())# Output# File 2 version 1

Status

  • Untracked files

    Lets create a new file

    f=open(f"{local_dir}/untracked.txt","w")# Creates an empty file.f.close()
    repo.untracked_files# Output: ['untracked.txt']
  • Modified files

    # Let's modify one of our tracked files.withopen(f"{local_dir}/Downloads/file3.txt","w")asf:f.write("file3 version 2")# Overwrite file 3.
    repo.index.diff(None)# Compares staging area to working directory.# Output: [<git.diff.Diff object at 0x7fb66c076e50>,# <git.diff.Diff object at 0x7fb66c076ca0>]

    returns a list ofDiff objects

    diffs=repo.index.diff(None)fordindiffs:print(d.a_path)# Output# Downloads/file3.txt

Diffs

Compare staging area to head commit

diffs=repo.index.diff(repo.head.commit)fordindiffs:print(d.a_path)# Output
# Let's add untracked.txt.repo.index.add(["untracked.txt"])diffs=repo.index.diff(repo.head.commit)fordindiffs:print(d.a_path)# Output# untracked.txt

Compare commit to commit

first_commit=list(repo.iter_commits(all=True))[-1]diffs=repo.head.commit.diff(first_commit)fordindiffs:print(d.a_path)# Output# dir1/file2.txt

More Resources

Remember, this is just the beginning! There’s a lot more you can achieve with GitPython in your development workflow.To explore further possibilities and discover advanced features, check out the fullGitPython tutorialand theAPI Reference. Happy coding!