Tips and Traps¶
GitPython is a wrapper around the
git
command. It requires thegit
command to be on the search path in order to work. Also, sometimes it is easier to call thegit
command viasubprocess.run
directly instead of using GitPython.The
git
command (and thus GitPython) accepts URLs both with and without the trailing.git
.
!pip3 install GitPython
import git
from git import Repo
url = "https://github.com/dclong/docker-ubuntu_b.git"
dir_local = "/tmp/test_gitpython"
url = "https://github.com/dclong/docker-ubuntu_b"
dir_local = "/tmp/test_gitpython"
Clone a Repository¶
!rm -rf {dir_local}
repo = git.Repo.clone_from(url, dir_local, branch="main")
repo
ls /tmp/test_gitpython/
Verify that the GitHub repository is cloned to local.
!ls {dir_local}
Clone the local repository to another location (which is not very useful as you can directly copy the directory to the new location).
repo2 = Repo(dir_local).clone(f"/tmp/{dir_local}")
repo2
!ls /tmp/{dir_local}
Infomation of the Local Repository¶
heads = repo.heads
heads
main = heads.main
main
Get the commit pointed to by head called master.
main.commit
main.rename("main2")
Verify that the main
branch has been renamed to main2
.
!cd {dir_local} && git branch
Get the Active Branch¶
repo.active_branch.name
Get All Branches¶
repo.branches
Get the Remote Name¶
repo.remote().name
Get all Remotes¶
repo.remotes
Commits¶
Get the latest commit in a branch.
repo.commit("main")
repo.commit("main").diff(repo.commit("origin/dev"))
repo.commit("origin/dev")
repo.refs
Changed Files¶
Update a file.
!echo "# add a line of comment" >> {dir_local}/build.sh
repo = Repo(dir_local)
files_changed = [item.a_path for item in repo.index.diff(None)]
files_changed
Staged Files¶
repo = Repo(dir_local)
index = repo.index
index.add("build.sh")
The file build.sh
is now staged.
files_stage = [item.a_path for item in repo.index.diff("HEAD")]
files_stage
files_changed = [item.a_path for item in repo.index.diff(None)]
files_changed
Commit the change.
index.commit("update build.sh")
files_stage = [item.a_path for item in repo.index.diff("HEAD")]
files_stage
remote = repo.remote()
remote
Push the Commits¶
Push the local main2
branch to the remote main2
branch.
remote.push("main2")
The above is equivalent to the following more detailed specification.
remote.push("refs/heads/main2:refs/heads/main2")
Push the local main2
branch to the remote main
branch.
remote.push("refs/heads/main2:refs/heads/main")
Pull a Branch¶
repo.active_branch
remote.pull(repo.active_branch)
!ls {dir_local}
git checkout¶
help(repo.refs[4].checkout)
?repo.git.checkout
repo.active_branch
The force=True
option discard any local changes no matter switching branch might be blocked by the local changes or not.
repo.git.checkout("dev", force=True)
repo.git.checkout("main", force=True)
repo.active_branch
git tag¶
List all tags.
repo.tags
Add a tag.
repo.create_tag("v1.0.0")
repo.tags
repo.tag("refs/tags/v1.0.0")
tag2 = repo.tag("refs/tags/v2.0.0")
tag2
repo.tags
The GitCommandError is thrown when the tag already exists.
repo.create_tag("v1.0.0")
repo.remote().push("v1.0.0")
git diff¶
help(repo.refs[4].commit.diff)
url = "https://github.com/dclong/docker-ubuntu_b.git"
dir_local = "/tmp/" + url[(url.rindex("/") + 1) :]
!rm -rf {dir_local}
repo = git.Repo.clone_from(url, dir_local, branch="main")
repo
repo.refs
diffs = repo.refs[4].commit.diff(repo.refs[3].commit)
diffs
diffs = repo.refs[4].commit.diff(repo.refs[2].commit)
diffs
str(diffs[0])
repo.refs[5].name
print(repo.git.status())
repo.git.checkout("debian", force=True)
repo.git.checkout(b="a_new_branch", force=True)
nima = repo.refs[4].checkout(force=True, b="nima")
nima
diffs = nima.commit.diff(repo.refs[-1].commit)
diffs[0].diff
Diff the dev
and the main
branch,
which is equivalent to the Git command
git diff dev..main
.
repo.refs[2].commit.diff(repo.refs[1].commit)
diffs = repo.refs[2].commit.diff(repo.refs[0].commit)
diffs
diffs[0]
diffs = repo.refs[6].commit.diff(repo.refs[7].commit)
diffs
diffs = repo.refs[4].commit.diff(repo.refs[7].commit)
diffs
diffs[0].diff
diffs = repo.refs[7].commit.diff(repo.refs[4].commit)
diffs
diffs[0].diff
any(ele for ele in [""])
repo.branches[0].name
for branch in repo.branches:
branch.
commit = repo.head.commit
commit
type(repo.branches[0])
repo.refs[4].commit.diff(repo.refs[2].commit)
repo.refs[4].commit.diff(repo.refs[3].commit)
help(repo.git.branch)
repo.heads
Diff the debian
and the main
branches but limit diff to specified paths
(via the paths
parameter).
diffs = repo.refs[4].commit.diff(repo.refs[2].commit, paths=["build.sh", "scripts"])
diffs