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