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