gitbetter.git
1import shlex 2import subprocess 3from contextlib import contextmanager 4from urllib.parse import urlparse 5 6from pathier import Pathier, Pathish 7 8 9class Git: 10 def __init__(self, capture_stdout: bool = False): 11 """If `capture_stdout` is `True`, all functions will return their generated `stdout` as a string. 12 Otherwise, the functions return the call's exit code.""" 13 self.capture_stdout = capture_stdout 14 15 @property 16 def capture_stdout(self) -> bool: 17 """If `True`, member functions will return the generated `stdout` as a string, 18 otherwise they return the command's exit code.""" 19 return self._capture_stdout 20 21 @capture_stdout.setter 22 def capture_stdout(self, should_capture: bool): 23 self._capture_stdout = should_capture 24 25 def _run(self, args: list[str]) -> str | int: 26 if self._capture_stdout: 27 return subprocess.run(args, stdout=subprocess.PIPE, text=True).stdout 28 else: 29 return subprocess.run(args).returncode 30 31 @contextmanager 32 def capture_output(self): 33 self.capture_stdout = True 34 yield self 35 self.capture_stdout = False 36 37 # Seat |===================================================Core===================================================| 38 39 def git(self, command: str) -> str | int: 40 """Base function for executing git commands. 41 Use this if another function doesn't meet your needs. 42 >>> git {command}""" 43 args = ["git"] + shlex.split(command) 44 return self._run(args) 45 46 # Seat 47 48 def add(self, args: str = "") -> str | int: 49 """>>> git add {args}""" 50 return self.git(f"add {args}") 51 52 def am(self, args: str = "") -> str | int: 53 """>>> git am {args}""" 54 return self.git(f"am {args}") 55 56 def annotate(self, args: str = "") -> str | int: 57 """>>> git annotate {args}""" 58 return self.git(f"annotate {args}") 59 60 def archive(self, args: str = "") -> str | int: 61 """>>> git archive {args}""" 62 return self.git(f"archive {args}") 63 64 def bisect(self, args: str = "") -> str | int: 65 """>>> git bisect {args}""" 66 return self.git(f"bisect {args}") 67 68 def blame(self, args: str = "") -> str | int: 69 """>>> git blame {args}""" 70 return self.git(f"blame {args}") 71 72 def branch(self, args: str = "") -> str | int: 73 """>>> git branch {args}""" 74 return self.git(f"branch {args}") 75 76 def bugreport(self, args: str = "") -> str | int: 77 """>>> git bugreport {args}""" 78 return self.git(f"bugreport {args}") 79 80 def bundle(self, args: str = "") -> str | int: 81 """>>> git bundle {args}""" 82 return self.git(f"bundle {args}") 83 84 def checkout(self, args: str = "") -> str | int: 85 """>>> git checkout {args}""" 86 return self.git(f"checkout {args}") 87 88 def cherry_pick(self, args: str = "") -> str | int: 89 """>>> git cherry-pick {args}""" 90 return self.git(f"cherry-pick {args}") 91 92 def citool(self, args: str = "") -> str | int: 93 """>>> git citool {args}""" 94 return self.git(f"citool {args}") 95 96 def clean(self, args: str = "") -> str | int: 97 """>>> git clean {args}""" 98 return self.git(f"clean {args}") 99 100 def clone(self, args: str = "") -> str | int: 101 """>>> git clone {args}""" 102 return self.git(f"clone {args}") 103 104 def commit(self, args: str = "") -> str | int: 105 """>>> git commit {args}""" 106 return self.git(f"commit {args}") 107 108 def config(self, args: str = "") -> str | int: 109 """>>> git config {args}""" 110 return self.git(f"config {args}") 111 112 def count_objects(self, args: str = "") -> str | int: 113 """>>> git count-objects {args}""" 114 return self.git(f"count-objects {args}") 115 116 def describe(self, args: str = "") -> str | int: 117 """>>> git describe {args}""" 118 return self.git(f"describe {args}") 119 120 def diagnose(self, args: str = "") -> str | int: 121 """>>> git diagnose {args}""" 122 return self.git(f"diagnose {args}") 123 124 def diff(self, args: str = "") -> str | int: 125 """>>> git diff {args}""" 126 return self.git(f"diff {args}") 127 128 def difftool(self, args: str = "") -> str | int: 129 """>>> git difftool {args}""" 130 return self.git(f"difftool {args}") 131 132 def fast_export(self, args: str = "") -> str | int: 133 """>>> git fast-export {args}""" 134 return self.git(f"fast-export {args}") 135 136 def fast_import(self, args: str = "") -> str | int: 137 """>>> git fast-import {args}""" 138 return self.git(f"fast-import {args}") 139 140 def fetch(self, args: str = "") -> str | int: 141 """>>> git fetch {args}""" 142 return self.git(f"fetch {args}") 143 144 def filter_branch(self, args: str = "") -> str | int: 145 """>>> git filter-branch {args}""" 146 return self.git(f"filter-branch {args}") 147 148 def format_patch(self, args: str = "") -> str | int: 149 """>>> git format-patch {args}""" 150 return self.git(f"format-patch {args}") 151 152 def fsck(self, args: str = "") -> str | int: 153 """>>> git fsck {args}""" 154 return self.git(f"fsck {args}") 155 156 def gc(self, args: str = "") -> str | int: 157 """>>> git gc {args}""" 158 return self.git(f"gc {args}") 159 160 def gitk(self, args: str = "") -> str | int: 161 """>>> git gitk {args}""" 162 return self.git(f"gitk {args}") 163 164 def gitweb(self, args: str = "") -> str | int: 165 """>>> git gitweb {args}""" 166 return self.git(f"gitweb {args}") 167 168 def grep(self, args: str = "") -> str | int: 169 """>>> git grep {args}""" 170 return self.git(f"grep {args}") 171 172 def gui(self, args: str = "") -> str | int: 173 """>>> git gui {args}""" 174 return self.git(f"gui {args}") 175 176 def help(self, args: str = "") -> str | int: 177 """>>> git help {args}""" 178 return self.git(f"help {args}") 179 180 def init(self, args: str = "") -> str | int: 181 """>>> git init {args}""" 182 return self.git(f"init {args}") 183 184 def instaweb(self, args: str = "") -> str | int: 185 """>>> git instaweb {args}""" 186 return self.git(f"instaweb {args}") 187 188 def log(self, args: str = "") -> str | int: 189 """>>> git log {args}""" 190 return self.git(f"log {args}") 191 192 def maintenance(self, args: str = "") -> str | int: 193 """>>> git maintenance {args}""" 194 return self.git(f"maintenance {args}") 195 196 def merge(self, args: str = "") -> str | int: 197 """>>> git merge {args}""" 198 return self.git(f"merge {args}") 199 200 def merge_tree(self, args: str = "") -> str | int: 201 """>>> git merge-tree {args}""" 202 return self.git(f"merge-tree {args}") 203 204 def mergetool(self, args: str = "") -> str | int: 205 """>>> git mergetool {args}""" 206 return self.git(f"mergetool {args}") 207 208 def mv(self, args: str = "") -> str | int: 209 """>>> git mv {args}""" 210 return self.git(f"mv {args}") 211 212 def notes(self, args: str = "") -> str | int: 213 """>>> git notes {args}""" 214 return self.git(f"notes {args}") 215 216 def pack_refs(self, args: str = "") -> str | int: 217 """>>> git pack-refs {args}""" 218 return self.git(f"pack-refs {args}") 219 220 def prune(self, args: str = "") -> str | int: 221 """>>> git prune {args}""" 222 return self.git(f"prune {args}") 223 224 def pull(self, args: str = "") -> str | int: 225 """>>> git pull {args}""" 226 return self.git(f"pull {args}") 227 228 def push(self, args: str = "") -> str | int: 229 """>>> git push {args}""" 230 return self.git(f"push {args}") 231 232 def range_diff(self, args: str = "") -> str | int: 233 """>>> git range-diff {args}""" 234 return self.git(f"range-diff {args}") 235 236 def rebase(self, args: str = "") -> str | int: 237 """>>> git rebase {args}""" 238 return self.git(f"rebase {args}") 239 240 def reflog(self, args: str = "") -> str | int: 241 """>>> git reflog {args}""" 242 return self.git(f"reflog {args}") 243 244 def remote(self, args: str = "") -> str | int: 245 """>>> git remote {args}""" 246 return self.git(f"remote {args}") 247 248 def repack(self, args: str = "") -> str | int: 249 """>>> git repack {args}""" 250 return self.git(f"repack {args}") 251 252 def replace(self, args: str = "") -> str | int: 253 """>>> git replace {args}""" 254 return self.git(f"replace {args}") 255 256 def request_pull(self, args: str = "") -> str | int: 257 """>>> git request-pull {args}""" 258 return self.git(f"request-pull {args}") 259 260 def rerere(self, args: str = "") -> str | int: 261 """>>> git rerere {args}""" 262 return self.git(f"rerere {args}") 263 264 def reset(self, args: str = "") -> str | int: 265 """>>> git reset {args}""" 266 return self.git(f"reset {args}") 267 268 def restore(self, args: str = "") -> str | int: 269 """>>> git restore {args}""" 270 return self.git(f"restore {args}") 271 272 def revert(self, args: str = "") -> str | int: 273 """>>> git revert {args}""" 274 return self.git(f"revert {args}") 275 276 def rm(self, args: str = "") -> str | int: 277 """>>> git rm {args}""" 278 return self.git(f"rm {args}") 279 280 def scalar(self, args: str = "") -> str | int: 281 """>>> git scalar {args}""" 282 return self.git(f"scalar {args}") 283 284 def shortlog(self, args: str = "") -> str | int: 285 """>>> git shortlog {args}""" 286 return self.git(f"shortlog {args}") 287 288 def show(self, args: str = "") -> str | int: 289 """>>> git show {args}""" 290 return self.git(f"show {args}") 291 292 def show_branch(self, args: str = "") -> str | int: 293 """>>> git show-branch {args}""" 294 return self.git(f"show-branch {args}") 295 296 def sparse_checkout(self, args: str = "") -> str | int: 297 """>>> git sparse-checkout {args}""" 298 return self.git(f"sparse-checkout {args}") 299 300 def stash(self, args: str = "") -> str | int: 301 """>>> git stash {args}""" 302 return self.git(f"stash {args}") 303 304 def status(self, args: str = "") -> str | int: 305 """>>> git status {args}""" 306 return self.git(f"status {args}") 307 308 def submodule(self, args: str = "") -> str | int: 309 """>>> git submodule {args}""" 310 return self.git(f"submodule {args}") 311 312 def switch(self, args: str = "") -> str | int: 313 """>>> git switch {args}""" 314 return self.git(f"switch {args}") 315 316 def tag(self, args: str = "") -> str | int: 317 """>>> git tag {args}""" 318 return self.git(f"tag {args}") 319 320 def verify_commit(self, args: str = "") -> str | int: 321 """>>> git verify-commit {args}""" 322 return self.git(f"verify-commit {args}") 323 324 def verify_tag(self, args: str = "") -> str | int: 325 """>>> git verify-tag {args}""" 326 return self.git(f"verify-tag {args}") 327 328 def version(self, args: str = "") -> str | int: 329 """>>> git version {args}""" 330 return self.git(f"version {args}") 331 332 def whatchanged(self, args: str = "") -> str | int: 333 """>>> git whatchanged {args}""" 334 return self.git(f"whatchanged {args}") 335 336 def worktree(self, args: str = "") -> str | int: 337 """>>> git worktree {args}""" 338 return self.git(f"worktree {args}") 339 340 # Seat |=================================================Convenience=================================================| 341 342 @property 343 def current_branch(self) -> str: 344 """Returns the name of the currently active branch.""" 345 capturing_output = self.capture_stdout 346 current_branch = "" 347 with self.capture_output(): 348 branches = self.branch().splitlines() # type: ignore 349 for branch in branches: 350 if branch.startswith("*"): 351 current_branch = branch[2:] 352 break 353 self.capture_stdout = capturing_output 354 return current_branch 355 356 @property 357 def origin_url(self) -> str | int: 358 """The remote origin url for this repo 359 >>> git remote get-url origin""" 360 return self.remote("get-url origin") 361 362 def add_all(self) -> str | int: 363 """Stage all modified and untracked files. 364 >>> git add .""" 365 return self.add(".") 366 367 def add_files(self, files: list[Pathish]) -> str | int: 368 """Stage a list of files.""" 369 args = " ".join([str(file).replace("\\", "/") for file in files]) 370 return self.add(args) 371 372 def add_remote_url(self, url: str, name: str = "origin") -> str | int: 373 """Add remote url to repo. 374 >>> git remote add {name} {url}""" 375 return self.remote(f"add {name} {url}") 376 377 def amend(self, files: list[Pathish] | None = None) -> str | int: 378 """Stage and commit changes to the previous commit. 379 380 If `files` is `None`, all files will be staged. 381 382 >>> git add {files} or git add . 383 >>> git commit --amend --no-edit 384 """ 385 return (self.add_files(files) if files else self.add_all()) + self.commit("--amend --no-edit") # type: ignore 386 387 def commit_all(self, message: str) -> str | int: 388 """Stage and commit all files with `message`. 389 >>> git add . 390 >>> git commit -m "{message}" """ 391 return self.add_all() + self.commit(f'-m "{message}"') # type: ignore 392 393 def commit_files(self, files: list[Pathish], message: str) -> str | int: 394 """Stage and commit a list of files with commit message `message`. 395 >>> git add {files} 396 >>> git commit -m "{message}" """ 397 return self.add_files(files) + self.commit(f'-m "{message}"') # type: ignore 398 399 def create_new_branch(self, branch_name: str) -> str | int: 400 """Create and switch to a new branch named with `branch_name`. 401 >>> git checkout -b {branch_name} --track""" 402 return self.checkout(f"-b {branch_name} --track") 403 404 def delete_branch(self, branch_name: str, local_only: bool = True) -> str | int: 405 """Delete `branch_name` from repo. 406 407 #### :params: 408 409 `local_only`: Only delete the local copy of `branch`, otherwise also delete the remote branch on origin and remote-tracking branch. 410 >>> git branch --delete {branch_name} 411 412 Then if not `local_only`: 413 >>> git push origin --delete {branch_name} 414 """ 415 output = self.branch(f"--delete {branch_name}") 416 if not local_only: 417 return output + self.push(f"origin --delete {branch_name}") # type: ignore 418 return output 419 420 def ignore(self, patterns: list[str]): 421 """Add `patterns` to `.gitignore`.""" 422 gitignore = Pathier(".gitignore") 423 if not gitignore.exists(): 424 gitignore.touch() 425 ignores = gitignore.split() 426 ignores += [pattern for pattern in patterns if pattern not in ignores] 427 gitignore.join(ignores) 428 429 def initcommit(self, files: list[Pathish] | None = None) -> str | int: 430 """Stage and commit `files` with the message `Initial commit`. 431 432 If `files` is not given, all files will be added and committed. 433 >>> git add {files} or git add . 434 >>> git commit -m "Initial commit" """ 435 return (self.add_files(files) if files else self.add_all()) + self.commit('-m "Initial commit"') # type: ignore 436 437 def list_branches(self) -> str | int: 438 """>>> git branch -vva""" 439 return self.branch("-vva") 440 441 def loggy(self) -> str | int: 442 """>>> git log --oneline --name-only --abbrev-commit --graph""" 443 return self.log("--oneline --name-only --abbrev-commit --graph") 444 445 def new_repo(self) -> str | int: 446 """Initialize a new repo in current directory. 447 >>> git init -b main""" 448 return self.init("-b main") 449 450 def push_new_branch(self, branch: str) -> str | int: 451 """Push a new branch to origin with tracking. 452 >>> git push -u origin {branch}""" 453 return self.push(f"-u origin {branch}") 454 455 def switch_branch(self, branch_name: str) -> str | int: 456 """Switch to the branch specified by `branch_name`. 457 >>> git checkout {branch_name}""" 458 return self.checkout(branch_name) 459 460 def undo(self) -> str | int: 461 """Undo uncommitted changes. 462 >>> git checkout .""" 463 return self.checkout(".") 464 465 # Seat |===============================Requires GitHub CLI to be installed and configured===============================| 466 467 @property 468 def owner(self) -> str: 469 return self._owner_reponame().split("/")[0] 470 471 @property 472 def repo_name(self) -> str: 473 return self._owner_reponame().split("/")[1] 474 475 def _change_visibility(self, visibility: str) -> str | int: 476 return self._run( 477 [ 478 "gh", 479 "repo", 480 "edit", 481 f"{self.owner}/{self.repo_name}", 482 "--visibility", 483 visibility, 484 ] 485 ) 486 487 def _owner_reponame(self) -> str: 488 """Returns "owner/repo-name", assuming there's one remote origin url and it's for github.""" 489 with self.capture_output(): 490 return urlparse(self.origin_url().strip("\n")).path.strip("/") # type: ignore 491 492 def create_remote(self, name: str, public: bool = False) -> str | int: 493 """Uses GitHub CLI (must be installed and configured) to create a remote GitHub repo. 494 495 #### :params: 496 497 `name`: The name for the repo. 498 499 `public`: Set to `True` to create the repo as public, otherwise it'll be created as private. 500 """ 501 visibility = "--public" if public else "--private" 502 return self._run(["gh", "repo", "create", name, visibility]) 503 504 def create_remote_from_cwd(self, public: bool = False) -> str | int: 505 """Use GitHub CLI (must be installed and configured) to create a remote GitHub repo from 506 the current working directory repo and add its url as this repo's remote origin. 507 508 #### :params: 509 510 `public`: Create the GitHub repo as a public repo, default is to create it as private. 511 """ 512 visibility = "public" if public else "private" 513 return self._run( 514 ["gh", "repo", "create", "--source", ".", f"--{visibility}", "--push"] 515 ) 516 517 def delete_remote(self) -> str | int: 518 """Uses GitHub CLI (must be isntalled and configured) to delete the remote for this repo.""" 519 return self._run( 520 ["gh", "repo", "delete", f"{self.owner}/{self.repo_name}", "--yes"] 521 ) 522 523 def make_private(self) -> str | int: 524 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to private.""" 525 return self._change_visibility("private") 526 527 def make_public(self) -> str | int: 528 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to public.""" 529 return self._change_visibility("public")
10class Git: 11 def __init__(self, capture_stdout: bool = False): 12 """If `capture_stdout` is `True`, all functions will return their generated `stdout` as a string. 13 Otherwise, the functions return the call's exit code.""" 14 self.capture_stdout = capture_stdout 15 16 @property 17 def capture_stdout(self) -> bool: 18 """If `True`, member functions will return the generated `stdout` as a string, 19 otherwise they return the command's exit code.""" 20 return self._capture_stdout 21 22 @capture_stdout.setter 23 def capture_stdout(self, should_capture: bool): 24 self._capture_stdout = should_capture 25 26 def _run(self, args: list[str]) -> str | int: 27 if self._capture_stdout: 28 return subprocess.run(args, stdout=subprocess.PIPE, text=True).stdout 29 else: 30 return subprocess.run(args).returncode 31 32 @contextmanager 33 def capture_output(self): 34 self.capture_stdout = True 35 yield self 36 self.capture_stdout = False 37 38 # Seat |===================================================Core===================================================| 39 40 def git(self, command: str) -> str | int: 41 """Base function for executing git commands. 42 Use this if another function doesn't meet your needs. 43 >>> git {command}""" 44 args = ["git"] + shlex.split(command) 45 return self._run(args) 46 47 # Seat 48 49 def add(self, args: str = "") -> str | int: 50 """>>> git add {args}""" 51 return self.git(f"add {args}") 52 53 def am(self, args: str = "") -> str | int: 54 """>>> git am {args}""" 55 return self.git(f"am {args}") 56 57 def annotate(self, args: str = "") -> str | int: 58 """>>> git annotate {args}""" 59 return self.git(f"annotate {args}") 60 61 def archive(self, args: str = "") -> str | int: 62 """>>> git archive {args}""" 63 return self.git(f"archive {args}") 64 65 def bisect(self, args: str = "") -> str | int: 66 """>>> git bisect {args}""" 67 return self.git(f"bisect {args}") 68 69 def blame(self, args: str = "") -> str | int: 70 """>>> git blame {args}""" 71 return self.git(f"blame {args}") 72 73 def branch(self, args: str = "") -> str | int: 74 """>>> git branch {args}""" 75 return self.git(f"branch {args}") 76 77 def bugreport(self, args: str = "") -> str | int: 78 """>>> git bugreport {args}""" 79 return self.git(f"bugreport {args}") 80 81 def bundle(self, args: str = "") -> str | int: 82 """>>> git bundle {args}""" 83 return self.git(f"bundle {args}") 84 85 def checkout(self, args: str = "") -> str | int: 86 """>>> git checkout {args}""" 87 return self.git(f"checkout {args}") 88 89 def cherry_pick(self, args: str = "") -> str | int: 90 """>>> git cherry-pick {args}""" 91 return self.git(f"cherry-pick {args}") 92 93 def citool(self, args: str = "") -> str | int: 94 """>>> git citool {args}""" 95 return self.git(f"citool {args}") 96 97 def clean(self, args: str = "") -> str | int: 98 """>>> git clean {args}""" 99 return self.git(f"clean {args}") 100 101 def clone(self, args: str = "") -> str | int: 102 """>>> git clone {args}""" 103 return self.git(f"clone {args}") 104 105 def commit(self, args: str = "") -> str | int: 106 """>>> git commit {args}""" 107 return self.git(f"commit {args}") 108 109 def config(self, args: str = "") -> str | int: 110 """>>> git config {args}""" 111 return self.git(f"config {args}") 112 113 def count_objects(self, args: str = "") -> str | int: 114 """>>> git count-objects {args}""" 115 return self.git(f"count-objects {args}") 116 117 def describe(self, args: str = "") -> str | int: 118 """>>> git describe {args}""" 119 return self.git(f"describe {args}") 120 121 def diagnose(self, args: str = "") -> str | int: 122 """>>> git diagnose {args}""" 123 return self.git(f"diagnose {args}") 124 125 def diff(self, args: str = "") -> str | int: 126 """>>> git diff {args}""" 127 return self.git(f"diff {args}") 128 129 def difftool(self, args: str = "") -> str | int: 130 """>>> git difftool {args}""" 131 return self.git(f"difftool {args}") 132 133 def fast_export(self, args: str = "") -> str | int: 134 """>>> git fast-export {args}""" 135 return self.git(f"fast-export {args}") 136 137 def fast_import(self, args: str = "") -> str | int: 138 """>>> git fast-import {args}""" 139 return self.git(f"fast-import {args}") 140 141 def fetch(self, args: str = "") -> str | int: 142 """>>> git fetch {args}""" 143 return self.git(f"fetch {args}") 144 145 def filter_branch(self, args: str = "") -> str | int: 146 """>>> git filter-branch {args}""" 147 return self.git(f"filter-branch {args}") 148 149 def format_patch(self, args: str = "") -> str | int: 150 """>>> git format-patch {args}""" 151 return self.git(f"format-patch {args}") 152 153 def fsck(self, args: str = "") -> str | int: 154 """>>> git fsck {args}""" 155 return self.git(f"fsck {args}") 156 157 def gc(self, args: str = "") -> str | int: 158 """>>> git gc {args}""" 159 return self.git(f"gc {args}") 160 161 def gitk(self, args: str = "") -> str | int: 162 """>>> git gitk {args}""" 163 return self.git(f"gitk {args}") 164 165 def gitweb(self, args: str = "") -> str | int: 166 """>>> git gitweb {args}""" 167 return self.git(f"gitweb {args}") 168 169 def grep(self, args: str = "") -> str | int: 170 """>>> git grep {args}""" 171 return self.git(f"grep {args}") 172 173 def gui(self, args: str = "") -> str | int: 174 """>>> git gui {args}""" 175 return self.git(f"gui {args}") 176 177 def help(self, args: str = "") -> str | int: 178 """>>> git help {args}""" 179 return self.git(f"help {args}") 180 181 def init(self, args: str = "") -> str | int: 182 """>>> git init {args}""" 183 return self.git(f"init {args}") 184 185 def instaweb(self, args: str = "") -> str | int: 186 """>>> git instaweb {args}""" 187 return self.git(f"instaweb {args}") 188 189 def log(self, args: str = "") -> str | int: 190 """>>> git log {args}""" 191 return self.git(f"log {args}") 192 193 def maintenance(self, args: str = "") -> str | int: 194 """>>> git maintenance {args}""" 195 return self.git(f"maintenance {args}") 196 197 def merge(self, args: str = "") -> str | int: 198 """>>> git merge {args}""" 199 return self.git(f"merge {args}") 200 201 def merge_tree(self, args: str = "") -> str | int: 202 """>>> git merge-tree {args}""" 203 return self.git(f"merge-tree {args}") 204 205 def mergetool(self, args: str = "") -> str | int: 206 """>>> git mergetool {args}""" 207 return self.git(f"mergetool {args}") 208 209 def mv(self, args: str = "") -> str | int: 210 """>>> git mv {args}""" 211 return self.git(f"mv {args}") 212 213 def notes(self, args: str = "") -> str | int: 214 """>>> git notes {args}""" 215 return self.git(f"notes {args}") 216 217 def pack_refs(self, args: str = "") -> str | int: 218 """>>> git pack-refs {args}""" 219 return self.git(f"pack-refs {args}") 220 221 def prune(self, args: str = "") -> str | int: 222 """>>> git prune {args}""" 223 return self.git(f"prune {args}") 224 225 def pull(self, args: str = "") -> str | int: 226 """>>> git pull {args}""" 227 return self.git(f"pull {args}") 228 229 def push(self, args: str = "") -> str | int: 230 """>>> git push {args}""" 231 return self.git(f"push {args}") 232 233 def range_diff(self, args: str = "") -> str | int: 234 """>>> git range-diff {args}""" 235 return self.git(f"range-diff {args}") 236 237 def rebase(self, args: str = "") -> str | int: 238 """>>> git rebase {args}""" 239 return self.git(f"rebase {args}") 240 241 def reflog(self, args: str = "") -> str | int: 242 """>>> git reflog {args}""" 243 return self.git(f"reflog {args}") 244 245 def remote(self, args: str = "") -> str | int: 246 """>>> git remote {args}""" 247 return self.git(f"remote {args}") 248 249 def repack(self, args: str = "") -> str | int: 250 """>>> git repack {args}""" 251 return self.git(f"repack {args}") 252 253 def replace(self, args: str = "") -> str | int: 254 """>>> git replace {args}""" 255 return self.git(f"replace {args}") 256 257 def request_pull(self, args: str = "") -> str | int: 258 """>>> git request-pull {args}""" 259 return self.git(f"request-pull {args}") 260 261 def rerere(self, args: str = "") -> str | int: 262 """>>> git rerere {args}""" 263 return self.git(f"rerere {args}") 264 265 def reset(self, args: str = "") -> str | int: 266 """>>> git reset {args}""" 267 return self.git(f"reset {args}") 268 269 def restore(self, args: str = "") -> str | int: 270 """>>> git restore {args}""" 271 return self.git(f"restore {args}") 272 273 def revert(self, args: str = "") -> str | int: 274 """>>> git revert {args}""" 275 return self.git(f"revert {args}") 276 277 def rm(self, args: str = "") -> str | int: 278 """>>> git rm {args}""" 279 return self.git(f"rm {args}") 280 281 def scalar(self, args: str = "") -> str | int: 282 """>>> git scalar {args}""" 283 return self.git(f"scalar {args}") 284 285 def shortlog(self, args: str = "") -> str | int: 286 """>>> git shortlog {args}""" 287 return self.git(f"shortlog {args}") 288 289 def show(self, args: str = "") -> str | int: 290 """>>> git show {args}""" 291 return self.git(f"show {args}") 292 293 def show_branch(self, args: str = "") -> str | int: 294 """>>> git show-branch {args}""" 295 return self.git(f"show-branch {args}") 296 297 def sparse_checkout(self, args: str = "") -> str | int: 298 """>>> git sparse-checkout {args}""" 299 return self.git(f"sparse-checkout {args}") 300 301 def stash(self, args: str = "") -> str | int: 302 """>>> git stash {args}""" 303 return self.git(f"stash {args}") 304 305 def status(self, args: str = "") -> str | int: 306 """>>> git status {args}""" 307 return self.git(f"status {args}") 308 309 def submodule(self, args: str = "") -> str | int: 310 """>>> git submodule {args}""" 311 return self.git(f"submodule {args}") 312 313 def switch(self, args: str = "") -> str | int: 314 """>>> git switch {args}""" 315 return self.git(f"switch {args}") 316 317 def tag(self, args: str = "") -> str | int: 318 """>>> git tag {args}""" 319 return self.git(f"tag {args}") 320 321 def verify_commit(self, args: str = "") -> str | int: 322 """>>> git verify-commit {args}""" 323 return self.git(f"verify-commit {args}") 324 325 def verify_tag(self, args: str = "") -> str | int: 326 """>>> git verify-tag {args}""" 327 return self.git(f"verify-tag {args}") 328 329 def version(self, args: str = "") -> str | int: 330 """>>> git version {args}""" 331 return self.git(f"version {args}") 332 333 def whatchanged(self, args: str = "") -> str | int: 334 """>>> git whatchanged {args}""" 335 return self.git(f"whatchanged {args}") 336 337 def worktree(self, args: str = "") -> str | int: 338 """>>> git worktree {args}""" 339 return self.git(f"worktree {args}") 340 341 # Seat |=================================================Convenience=================================================| 342 343 @property 344 def current_branch(self) -> str: 345 """Returns the name of the currently active branch.""" 346 capturing_output = self.capture_stdout 347 current_branch = "" 348 with self.capture_output(): 349 branches = self.branch().splitlines() # type: ignore 350 for branch in branches: 351 if branch.startswith("*"): 352 current_branch = branch[2:] 353 break 354 self.capture_stdout = capturing_output 355 return current_branch 356 357 @property 358 def origin_url(self) -> str | int: 359 """The remote origin url for this repo 360 >>> git remote get-url origin""" 361 return self.remote("get-url origin") 362 363 def add_all(self) -> str | int: 364 """Stage all modified and untracked files. 365 >>> git add .""" 366 return self.add(".") 367 368 def add_files(self, files: list[Pathish]) -> str | int: 369 """Stage a list of files.""" 370 args = " ".join([str(file).replace("\\", "/") for file in files]) 371 return self.add(args) 372 373 def add_remote_url(self, url: str, name: str = "origin") -> str | int: 374 """Add remote url to repo. 375 >>> git remote add {name} {url}""" 376 return self.remote(f"add {name} {url}") 377 378 def amend(self, files: list[Pathish] | None = None) -> str | int: 379 """Stage and commit changes to the previous commit. 380 381 If `files` is `None`, all files will be staged. 382 383 >>> git add {files} or git add . 384 >>> git commit --amend --no-edit 385 """ 386 return (self.add_files(files) if files else self.add_all()) + self.commit("--amend --no-edit") # type: ignore 387 388 def commit_all(self, message: str) -> str | int: 389 """Stage and commit all files with `message`. 390 >>> git add . 391 >>> git commit -m "{message}" """ 392 return self.add_all() + self.commit(f'-m "{message}"') # type: ignore 393 394 def commit_files(self, files: list[Pathish], message: str) -> str | int: 395 """Stage and commit a list of files with commit message `message`. 396 >>> git add {files} 397 >>> git commit -m "{message}" """ 398 return self.add_files(files) + self.commit(f'-m "{message}"') # type: ignore 399 400 def create_new_branch(self, branch_name: str) -> str | int: 401 """Create and switch to a new branch named with `branch_name`. 402 >>> git checkout -b {branch_name} --track""" 403 return self.checkout(f"-b {branch_name} --track") 404 405 def delete_branch(self, branch_name: str, local_only: bool = True) -> str | int: 406 """Delete `branch_name` from repo. 407 408 #### :params: 409 410 `local_only`: Only delete the local copy of `branch`, otherwise also delete the remote branch on origin and remote-tracking branch. 411 >>> git branch --delete {branch_name} 412 413 Then if not `local_only`: 414 >>> git push origin --delete {branch_name} 415 """ 416 output = self.branch(f"--delete {branch_name}") 417 if not local_only: 418 return output + self.push(f"origin --delete {branch_name}") # type: ignore 419 return output 420 421 def ignore(self, patterns: list[str]): 422 """Add `patterns` to `.gitignore`.""" 423 gitignore = Pathier(".gitignore") 424 if not gitignore.exists(): 425 gitignore.touch() 426 ignores = gitignore.split() 427 ignores += [pattern for pattern in patterns if pattern not in ignores] 428 gitignore.join(ignores) 429 430 def initcommit(self, files: list[Pathish] | None = None) -> str | int: 431 """Stage and commit `files` with the message `Initial commit`. 432 433 If `files` is not given, all files will be added and committed. 434 >>> git add {files} or git add . 435 >>> git commit -m "Initial commit" """ 436 return (self.add_files(files) if files else self.add_all()) + self.commit('-m "Initial commit"') # type: ignore 437 438 def list_branches(self) -> str | int: 439 """>>> git branch -vva""" 440 return self.branch("-vva") 441 442 def loggy(self) -> str | int: 443 """>>> git log --oneline --name-only --abbrev-commit --graph""" 444 return self.log("--oneline --name-only --abbrev-commit --graph") 445 446 def new_repo(self) -> str | int: 447 """Initialize a new repo in current directory. 448 >>> git init -b main""" 449 return self.init("-b main") 450 451 def push_new_branch(self, branch: str) -> str | int: 452 """Push a new branch to origin with tracking. 453 >>> git push -u origin {branch}""" 454 return self.push(f"-u origin {branch}") 455 456 def switch_branch(self, branch_name: str) -> str | int: 457 """Switch to the branch specified by `branch_name`. 458 >>> git checkout {branch_name}""" 459 return self.checkout(branch_name) 460 461 def undo(self) -> str | int: 462 """Undo uncommitted changes. 463 >>> git checkout .""" 464 return self.checkout(".") 465 466 # Seat |===============================Requires GitHub CLI to be installed and configured===============================| 467 468 @property 469 def owner(self) -> str: 470 return self._owner_reponame().split("/")[0] 471 472 @property 473 def repo_name(self) -> str: 474 return self._owner_reponame().split("/")[1] 475 476 def _change_visibility(self, visibility: str) -> str | int: 477 return self._run( 478 [ 479 "gh", 480 "repo", 481 "edit", 482 f"{self.owner}/{self.repo_name}", 483 "--visibility", 484 visibility, 485 ] 486 ) 487 488 def _owner_reponame(self) -> str: 489 """Returns "owner/repo-name", assuming there's one remote origin url and it's for github.""" 490 with self.capture_output(): 491 return urlparse(self.origin_url().strip("\n")).path.strip("/") # type: ignore 492 493 def create_remote(self, name: str, public: bool = False) -> str | int: 494 """Uses GitHub CLI (must be installed and configured) to create a remote GitHub repo. 495 496 #### :params: 497 498 `name`: The name for the repo. 499 500 `public`: Set to `True` to create the repo as public, otherwise it'll be created as private. 501 """ 502 visibility = "--public" if public else "--private" 503 return self._run(["gh", "repo", "create", name, visibility]) 504 505 def create_remote_from_cwd(self, public: bool = False) -> str | int: 506 """Use GitHub CLI (must be installed and configured) to create a remote GitHub repo from 507 the current working directory repo and add its url as this repo's remote origin. 508 509 #### :params: 510 511 `public`: Create the GitHub repo as a public repo, default is to create it as private. 512 """ 513 visibility = "public" if public else "private" 514 return self._run( 515 ["gh", "repo", "create", "--source", ".", f"--{visibility}", "--push"] 516 ) 517 518 def delete_remote(self) -> str | int: 519 """Uses GitHub CLI (must be isntalled and configured) to delete the remote for this repo.""" 520 return self._run( 521 ["gh", "repo", "delete", f"{self.owner}/{self.repo_name}", "--yes"] 522 ) 523 524 def make_private(self) -> str | int: 525 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to private.""" 526 return self._change_visibility("private") 527 528 def make_public(self) -> str | int: 529 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to public.""" 530 return self._change_visibility("public")
11 def __init__(self, capture_stdout: bool = False): 12 """If `capture_stdout` is `True`, all functions will return their generated `stdout` as a string. 13 Otherwise, the functions return the call's exit code.""" 14 self.capture_stdout = capture_stdout
If capture_stdout
is True
, all functions will return their generated stdout
as a string.
Otherwise, the functions return the call's exit code.
If True
, member functions will return the generated stdout
as a string,
otherwise they return the command's exit code.
40 def git(self, command: str) -> str | int: 41 """Base function for executing git commands. 42 Use this if another function doesn't meet your needs. 43 >>> git {command}""" 44 args = ["git"] + shlex.split(command) 45 return self._run(args)
Base function for executing git commands. Use this if another function doesn't meet your needs.
>>> git {command}
49 def add(self, args: str = "") -> str | int: 50 """>>> git add {args}""" 51 return self.git(f"add {args}")
>>> git add {args}
53 def am(self, args: str = "") -> str | int: 54 """>>> git am {args}""" 55 return self.git(f"am {args}")
>>> git am {args}
57 def annotate(self, args: str = "") -> str | int: 58 """>>> git annotate {args}""" 59 return self.git(f"annotate {args}")
>>> git annotate {args}
61 def archive(self, args: str = "") -> str | int: 62 """>>> git archive {args}""" 63 return self.git(f"archive {args}")
>>> git archive {args}
65 def bisect(self, args: str = "") -> str | int: 66 """>>> git bisect {args}""" 67 return self.git(f"bisect {args}")
>>> git bisect {args}
69 def blame(self, args: str = "") -> str | int: 70 """>>> git blame {args}""" 71 return self.git(f"blame {args}")
>>> git blame {args}
73 def branch(self, args: str = "") -> str | int: 74 """>>> git branch {args}""" 75 return self.git(f"branch {args}")
>>> git branch {args}
77 def bugreport(self, args: str = "") -> str | int: 78 """>>> git bugreport {args}""" 79 return self.git(f"bugreport {args}")
>>> git bugreport {args}
81 def bundle(self, args: str = "") -> str | int: 82 """>>> git bundle {args}""" 83 return self.git(f"bundle {args}")
>>> git bundle {args}
85 def checkout(self, args: str = "") -> str | int: 86 """>>> git checkout {args}""" 87 return self.git(f"checkout {args}")
>>> git checkout {args}
89 def cherry_pick(self, args: str = "") -> str | int: 90 """>>> git cherry-pick {args}""" 91 return self.git(f"cherry-pick {args}")
>>> git cherry-pick {args}
93 def citool(self, args: str = "") -> str | int: 94 """>>> git citool {args}""" 95 return self.git(f"citool {args}")
>>> git citool {args}
97 def clean(self, args: str = "") -> str | int: 98 """>>> git clean {args}""" 99 return self.git(f"clean {args}")
>>> git clean {args}
101 def clone(self, args: str = "") -> str | int: 102 """>>> git clone {args}""" 103 return self.git(f"clone {args}")
>>> git clone {args}
105 def commit(self, args: str = "") -> str | int: 106 """>>> git commit {args}""" 107 return self.git(f"commit {args}")
>>> git commit {args}
109 def config(self, args: str = "") -> str | int: 110 """>>> git config {args}""" 111 return self.git(f"config {args}")
>>> git config {args}
113 def count_objects(self, args: str = "") -> str | int: 114 """>>> git count-objects {args}""" 115 return self.git(f"count-objects {args}")
>>> git count-objects {args}
117 def describe(self, args: str = "") -> str | int: 118 """>>> git describe {args}""" 119 return self.git(f"describe {args}")
>>> git describe {args}
121 def diagnose(self, args: str = "") -> str | int: 122 """>>> git diagnose {args}""" 123 return self.git(f"diagnose {args}")
>>> git diagnose {args}
125 def diff(self, args: str = "") -> str | int: 126 """>>> git diff {args}""" 127 return self.git(f"diff {args}")
>>> git diff {args}
129 def difftool(self, args: str = "") -> str | int: 130 """>>> git difftool {args}""" 131 return self.git(f"difftool {args}")
>>> git difftool {args}
133 def fast_export(self, args: str = "") -> str | int: 134 """>>> git fast-export {args}""" 135 return self.git(f"fast-export {args}")
>>> git fast-export {args}
137 def fast_import(self, args: str = "") -> str | int: 138 """>>> git fast-import {args}""" 139 return self.git(f"fast-import {args}")
>>> git fast-import {args}
141 def fetch(self, args: str = "") -> str | int: 142 """>>> git fetch {args}""" 143 return self.git(f"fetch {args}")
>>> git fetch {args}
145 def filter_branch(self, args: str = "") -> str | int: 146 """>>> git filter-branch {args}""" 147 return self.git(f"filter-branch {args}")
>>> git filter-branch {args}
149 def format_patch(self, args: str = "") -> str | int: 150 """>>> git format-patch {args}""" 151 return self.git(f"format-patch {args}")
>>> git format-patch {args}
153 def fsck(self, args: str = "") -> str | int: 154 """>>> git fsck {args}""" 155 return self.git(f"fsck {args}")
>>> git fsck {args}
157 def gc(self, args: str = "") -> str | int: 158 """>>> git gc {args}""" 159 return self.git(f"gc {args}")
>>> git gc {args}
161 def gitk(self, args: str = "") -> str | int: 162 """>>> git gitk {args}""" 163 return self.git(f"gitk {args}")
>>> git gitk {args}
165 def gitweb(self, args: str = "") -> str | int: 166 """>>> git gitweb {args}""" 167 return self.git(f"gitweb {args}")
>>> git gitweb {args}
169 def grep(self, args: str = "") -> str | int: 170 """>>> git grep {args}""" 171 return self.git(f"grep {args}")
>>> git grep {args}
173 def gui(self, args: str = "") -> str | int: 174 """>>> git gui {args}""" 175 return self.git(f"gui {args}")
>>> git gui {args}
177 def help(self, args: str = "") -> str | int: 178 """>>> git help {args}""" 179 return self.git(f"help {args}")
>>> git help {args}
181 def init(self, args: str = "") -> str | int: 182 """>>> git init {args}""" 183 return self.git(f"init {args}")
>>> git init {args}
185 def instaweb(self, args: str = "") -> str | int: 186 """>>> git instaweb {args}""" 187 return self.git(f"instaweb {args}")
>>> git instaweb {args}
189 def log(self, args: str = "") -> str | int: 190 """>>> git log {args}""" 191 return self.git(f"log {args}")
>>> git log {args}
193 def maintenance(self, args: str = "") -> str | int: 194 """>>> git maintenance {args}""" 195 return self.git(f"maintenance {args}")
>>> git maintenance {args}
197 def merge(self, args: str = "") -> str | int: 198 """>>> git merge {args}""" 199 return self.git(f"merge {args}")
>>> git merge {args}
201 def merge_tree(self, args: str = "") -> str | int: 202 """>>> git merge-tree {args}""" 203 return self.git(f"merge-tree {args}")
>>> git merge-tree {args}
205 def mergetool(self, args: str = "") -> str | int: 206 """>>> git mergetool {args}""" 207 return self.git(f"mergetool {args}")
>>> git mergetool {args}
209 def mv(self, args: str = "") -> str | int: 210 """>>> git mv {args}""" 211 return self.git(f"mv {args}")
>>> git mv {args}
213 def notes(self, args: str = "") -> str | int: 214 """>>> git notes {args}""" 215 return self.git(f"notes {args}")
>>> git notes {args}
217 def pack_refs(self, args: str = "") -> str | int: 218 """>>> git pack-refs {args}""" 219 return self.git(f"pack-refs {args}")
>>> git pack-refs {args}
221 def prune(self, args: str = "") -> str | int: 222 """>>> git prune {args}""" 223 return self.git(f"prune {args}")
>>> git prune {args}
225 def pull(self, args: str = "") -> str | int: 226 """>>> git pull {args}""" 227 return self.git(f"pull {args}")
>>> git pull {args}
229 def push(self, args: str = "") -> str | int: 230 """>>> git push {args}""" 231 return self.git(f"push {args}")
>>> git push {args}
233 def range_diff(self, args: str = "") -> str | int: 234 """>>> git range-diff {args}""" 235 return self.git(f"range-diff {args}")
>>> git range-diff {args}
237 def rebase(self, args: str = "") -> str | int: 238 """>>> git rebase {args}""" 239 return self.git(f"rebase {args}")
>>> git rebase {args}
241 def reflog(self, args: str = "") -> str | int: 242 """>>> git reflog {args}""" 243 return self.git(f"reflog {args}")
>>> git reflog {args}
245 def remote(self, args: str = "") -> str | int: 246 """>>> git remote {args}""" 247 return self.git(f"remote {args}")
>>> git remote {args}
249 def repack(self, args: str = "") -> str | int: 250 """>>> git repack {args}""" 251 return self.git(f"repack {args}")
>>> git repack {args}
253 def replace(self, args: str = "") -> str | int: 254 """>>> git replace {args}""" 255 return self.git(f"replace {args}")
>>> git replace {args}
257 def request_pull(self, args: str = "") -> str | int: 258 """>>> git request-pull {args}""" 259 return self.git(f"request-pull {args}")
>>> git request-pull {args}
261 def rerere(self, args: str = "") -> str | int: 262 """>>> git rerere {args}""" 263 return self.git(f"rerere {args}")
>>> git rerere {args}
265 def reset(self, args: str = "") -> str | int: 266 """>>> git reset {args}""" 267 return self.git(f"reset {args}")
>>> git reset {args}
269 def restore(self, args: str = "") -> str | int: 270 """>>> git restore {args}""" 271 return self.git(f"restore {args}")
>>> git restore {args}
273 def revert(self, args: str = "") -> str | int: 274 """>>> git revert {args}""" 275 return self.git(f"revert {args}")
>>> git revert {args}
277 def rm(self, args: str = "") -> str | int: 278 """>>> git rm {args}""" 279 return self.git(f"rm {args}")
>>> git rm {args}
281 def scalar(self, args: str = "") -> str | int: 282 """>>> git scalar {args}""" 283 return self.git(f"scalar {args}")
>>> git scalar {args}
285 def shortlog(self, args: str = "") -> str | int: 286 """>>> git shortlog {args}""" 287 return self.git(f"shortlog {args}")
>>> git shortlog {args}
289 def show(self, args: str = "") -> str | int: 290 """>>> git show {args}""" 291 return self.git(f"show {args}")
>>> git show {args}
293 def show_branch(self, args: str = "") -> str | int: 294 """>>> git show-branch {args}""" 295 return self.git(f"show-branch {args}")
>>> git show-branch {args}
297 def sparse_checkout(self, args: str = "") -> str | int: 298 """>>> git sparse-checkout {args}""" 299 return self.git(f"sparse-checkout {args}")
>>> git sparse-checkout {args}
301 def stash(self, args: str = "") -> str | int: 302 """>>> git stash {args}""" 303 return self.git(f"stash {args}")
>>> git stash {args}
305 def status(self, args: str = "") -> str | int: 306 """>>> git status {args}""" 307 return self.git(f"status {args}")
>>> git status {args}
309 def submodule(self, args: str = "") -> str | int: 310 """>>> git submodule {args}""" 311 return self.git(f"submodule {args}")
>>> git submodule {args}
313 def switch(self, args: str = "") -> str | int: 314 """>>> git switch {args}""" 315 return self.git(f"switch {args}")
>>> git switch {args}
317 def tag(self, args: str = "") -> str | int: 318 """>>> git tag {args}""" 319 return self.git(f"tag {args}")
>>> git tag {args}
321 def verify_commit(self, args: str = "") -> str | int: 322 """>>> git verify-commit {args}""" 323 return self.git(f"verify-commit {args}")
>>> git verify-commit {args}
325 def verify_tag(self, args: str = "") -> str | int: 326 """>>> git verify-tag {args}""" 327 return self.git(f"verify-tag {args}")
>>> git verify-tag {args}
329 def version(self, args: str = "") -> str | int: 330 """>>> git version {args}""" 331 return self.git(f"version {args}")
>>> git version {args}
333 def whatchanged(self, args: str = "") -> str | int: 334 """>>> git whatchanged {args}""" 335 return self.git(f"whatchanged {args}")
>>> git whatchanged {args}
337 def worktree(self, args: str = "") -> str | int: 338 """>>> git worktree {args}""" 339 return self.git(f"worktree {args}")
>>> git worktree {args}
363 def add_all(self) -> str | int: 364 """Stage all modified and untracked files. 365 >>> git add .""" 366 return self.add(".")
Stage all modified and untracked files.
>>> git add .
368 def add_files(self, files: list[Pathish]) -> str | int: 369 """Stage a list of files.""" 370 args = " ".join([str(file).replace("\\", "/") for file in files]) 371 return self.add(args)
Stage a list of files.
373 def add_remote_url(self, url: str, name: str = "origin") -> str | int: 374 """Add remote url to repo. 375 >>> git remote add {name} {url}""" 376 return self.remote(f"add {name} {url}")
Add remote url to repo.
>>> git remote add {name} {url}
378 def amend(self, files: list[Pathish] | None = None) -> str | int: 379 """Stage and commit changes to the previous commit. 380 381 If `files` is `None`, all files will be staged. 382 383 >>> git add {files} or git add . 384 >>> git commit --amend --no-edit 385 """ 386 return (self.add_files(files) if files else self.add_all()) + self.commit("--amend --no-edit") # type: ignore
Stage and commit changes to the previous commit.
If files
is None
, all files will be staged.
>>> git add {files} or git add .
>>> git commit --amend --no-edit
388 def commit_all(self, message: str) -> str | int: 389 """Stage and commit all files with `message`. 390 >>> git add . 391 >>> git commit -m "{message}" """ 392 return self.add_all() + self.commit(f'-m "{message}"') # type: ignore
Stage and commit all files with message
.
>>> git add .
>>> git commit -m "{message}"
394 def commit_files(self, files: list[Pathish], message: str) -> str | int: 395 """Stage and commit a list of files with commit message `message`. 396 >>> git add {files} 397 >>> git commit -m "{message}" """ 398 return self.add_files(files) + self.commit(f'-m "{message}"') # type: ignore
Stage and commit a list of files with commit message message
.
>>> git add {files}
>>> git commit -m "{message}"
400 def create_new_branch(self, branch_name: str) -> str | int: 401 """Create and switch to a new branch named with `branch_name`. 402 >>> git checkout -b {branch_name} --track""" 403 return self.checkout(f"-b {branch_name} --track")
Create and switch to a new branch named with branch_name
.
>>> git checkout -b {branch_name} --track
405 def delete_branch(self, branch_name: str, local_only: bool = True) -> str | int: 406 """Delete `branch_name` from repo. 407 408 #### :params: 409 410 `local_only`: Only delete the local copy of `branch`, otherwise also delete the remote branch on origin and remote-tracking branch. 411 >>> git branch --delete {branch_name} 412 413 Then if not `local_only`: 414 >>> git push origin --delete {branch_name} 415 """ 416 output = self.branch(f"--delete {branch_name}") 417 if not local_only: 418 return output + self.push(f"origin --delete {branch_name}") # type: ignore 419 return output
Delete branch_name
from repo.
:params:
local_only
: Only delete the local copy of branch
, otherwise also delete the remote branch on origin and remote-tracking branch.
>>> git branch --delete {branch_name}
Then if not local_only
:
>>> git push origin --delete {branch_name}
421 def ignore(self, patterns: list[str]): 422 """Add `patterns` to `.gitignore`.""" 423 gitignore = Pathier(".gitignore") 424 if not gitignore.exists(): 425 gitignore.touch() 426 ignores = gitignore.split() 427 ignores += [pattern for pattern in patterns if pattern not in ignores] 428 gitignore.join(ignores)
Add patterns
to .gitignore
.
430 def initcommit(self, files: list[Pathish] | None = None) -> str | int: 431 """Stage and commit `files` with the message `Initial commit`. 432 433 If `files` is not given, all files will be added and committed. 434 >>> git add {files} or git add . 435 >>> git commit -m "Initial commit" """ 436 return (self.add_files(files) if files else self.add_all()) + self.commit('-m "Initial commit"') # type: ignore
Stage and commit files
with the message Initial commit
.
If files
is not given, all files will be added and committed.
>>> git add {files} or git add .
>>> git commit -m "Initial commit"
438 def list_branches(self) -> str | int: 439 """>>> git branch -vva""" 440 return self.branch("-vva")
>>> git branch -vva
442 def loggy(self) -> str | int: 443 """>>> git log --oneline --name-only --abbrev-commit --graph""" 444 return self.log("--oneline --name-only --abbrev-commit --graph")
>>> git log --oneline --name-only --abbrev-commit --graph
446 def new_repo(self) -> str | int: 447 """Initialize a new repo in current directory. 448 >>> git init -b main""" 449 return self.init("-b main")
Initialize a new repo in current directory.
>>> git init -b main
451 def push_new_branch(self, branch: str) -> str | int: 452 """Push a new branch to origin with tracking. 453 >>> git push -u origin {branch}""" 454 return self.push(f"-u origin {branch}")
Push a new branch to origin with tracking.
>>> git push -u origin {branch}
456 def switch_branch(self, branch_name: str) -> str | int: 457 """Switch to the branch specified by `branch_name`. 458 >>> git checkout {branch_name}""" 459 return self.checkout(branch_name)
Switch to the branch specified by branch_name
.
>>> git checkout {branch_name}
461 def undo(self) -> str | int: 462 """Undo uncommitted changes. 463 >>> git checkout .""" 464 return self.checkout(".")
Undo uncommitted changes.
>>> git checkout .
493 def create_remote(self, name: str, public: bool = False) -> str | int: 494 """Uses GitHub CLI (must be installed and configured) to create a remote GitHub repo. 495 496 #### :params: 497 498 `name`: The name for the repo. 499 500 `public`: Set to `True` to create the repo as public, otherwise it'll be created as private. 501 """ 502 visibility = "--public" if public else "--private" 503 return self._run(["gh", "repo", "create", name, visibility])
Uses GitHub CLI (must be installed and configured) to create a remote GitHub repo.
:params:
name
: The name for the repo.
public
: Set to True
to create the repo as public, otherwise it'll be created as private.
505 def create_remote_from_cwd(self, public: bool = False) -> str | int: 506 """Use GitHub CLI (must be installed and configured) to create a remote GitHub repo from 507 the current working directory repo and add its url as this repo's remote origin. 508 509 #### :params: 510 511 `public`: Create the GitHub repo as a public repo, default is to create it as private. 512 """ 513 visibility = "public" if public else "private" 514 return self._run( 515 ["gh", "repo", "create", "--source", ".", f"--{visibility}", "--push"] 516 )
Use GitHub CLI (must be installed and configured) to create a remote GitHub repo from the current working directory repo and add its url as this repo's remote origin.
:params:
public
: Create the GitHub repo as a public repo, default is to create it as private.
518 def delete_remote(self) -> str | int: 519 """Uses GitHub CLI (must be isntalled and configured) to delete the remote for this repo.""" 520 return self._run( 521 ["gh", "repo", "delete", f"{self.owner}/{self.repo_name}", "--yes"] 522 )
Uses GitHub CLI (must be isntalled and configured) to delete the remote for this repo.
524 def make_private(self) -> str | int: 525 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to private.""" 526 return self._change_visibility("private")
Uses GitHub CLI (must be installed and configured) to set the repo's visibility to private.
528 def make_public(self) -> str | int: 529 """Uses GitHub CLI (must be installed and configured) to set the repo's visibility to public.""" 530 return self._change_visibility("public")
Uses GitHub CLI (must be installed and configured) to set the repo's visibility to public.