src/aliases.ps1
#!/usr/bin/env pwsh $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest if (-not (Test-Command git) -and (-not (Get-Variable -Name PWSHRC_FORCE_MODULES_EXPORT_UNSUPPORTED -Scope Global -ValueOnly -ErrorAction SilentlyContinue))) { return } [string] $git_bin = $null if (Test-Command hub) { $git_bin = "hub" function Invoke-Hub { hub @args } Set-Alias -Name git -Value hub } elseif (Test-Command git) { $git_bin = "git" } <# .SYNOPSIS Adds remote ${Env:GIT_HOSTING}:$repo to current repo. .PARAMETER repo The name of the repo to add. .COMPONENT Git #> function git_remote { param( [Parameter(Mandatory = $true, Position = 0)] [string] $repo ) if (-not $Env:GIT_HOSTING) { throw "Please set the environment variable GIT_HOSTING to the hostname of your git hosting provider." } Write-Output "Running: git remote add origin ${Env:GIT_HOSTING}:$repo.git" & $git_bin remote add origin "${GIT_HOSTING}:${1}".git } <# .SYNOPSIS Push into origin refs/heads/master. .COMPONENT Git #> function git_first_push { Write-Output "Running: git push origin master:refs/heads/master" & $git_bin push origin master:refs/heads/master } <# .SYNOPSIS Publishes current branch to remote origin. .COMPONENT Git #> function git_pub() { $BRANCH=(git rev-parse --abbrev-ref HEAD) Write-Output "Publishing ${BRANCH} to remote origin" & $git_bin push -u origin "${BRANCH}" } <# .SYNOPSIS Applies changes to HEAD that revert all changes after this commit. .PARAMETER target The commit to revert to. .COMPONENT Git #> function git_revert() { param( [Parameter(Mandatory = $true, Position = 0)] [string] $target ) & $git_bin reset $target & $git_bin reset --soft "HEAD@{1}" & $git_bin commit -m "Revert to $target" & $git_bin reset --hard } <# .SYNOPSIS Resets the current HEAD to this commit. .PARAMETER target The commit to reset to. .COMPONENT Git #> function git_rollback { param( [Parameter(Mandatory = $true, Position = 0)] [string] $target ) function is_clean { if ((git diff --shortstat 2> $null | Select-Object -Last 1)) { throw "Your branch is dirty, please commit your changes" } } function commit_exists { param( [Parameter(Mandatory = $true, Position = 0)] [string] $target ) if (git rev-list --quiet $target) { throw "Commit $target does not exist" } } function keep_changes { param( [Parameter(Mandatory = $true, Position = 0)] [string] $target ) $userAccepts = $PSCmdlet.ShouldContinue("Do you want to keep all changes from rolled back revisions in your working tree?") if ($userAccepts) { Write-Output "Rolling back to commit $target with unstaged changes." & $git_bin reset $target } else { Write-Output "Rolling back to commit $target with a clean working tree." & $git_bin reset --hard $target } } if ((git symbolic-ref HEAD 2> $null)) { is_clean commit_exists $target $userAccepts = $PSCmdlet.ShouldContinue("WARNING: This will change your history and move the current HEAD back to commit $target, continue?") if ($userAccepts) { keep_changes $target } } else { Write-Error "you're currently not in a git repository" } } <# .SYNOPSIS & $git_bin rm's missing files. .COMPONENT Git #> function git_remove_missing_files() { [string[]] $files = (git ls-files -d) & $git_bin update-index --remove @files } <# .SYNOPSIS Adds files to git's exclude file (same as .gitignore). .PARAMETER file The file to add to the exclude file. .COMPONENT Git #> function local-ignore() { param( [Parameter(Mandatory = $true, Position = 0)] [string] $file ) $file | Out-File -Append .git/info/exclude } <# .SYNOPSIS Get a quick overview for your git repo. .COMPONENT Git #> function git_info() { if ((git symbolic-ref HEAD 2> $null)) { # print informations Write-Output "git repo overview" Write-Output "-----------------" Write-Output # print all remotes and thier details foreach ($remote in (git remote show)) { Write-Output "${remote}": & $git_bin remote show "${remote}" Write-Output } # print status of working repo Write-Output "status:" if ((git status -s 2> $null)) { & $git_bin status -s } else { Write-Output "working directory is clean" } # print at least 5 last log entries Write-Output Write-Output "log:" & $git_bin log -5 --oneline Write-Output } else { throw "you're currently not in a git repository" } } <# .SYNOPSIS Display stats per author. .COMPONENT Git #> function git_stats { param( [Parameter(Mandatory = $false, Position = 0)] [switch] $w, [Parameter(Mandatory = $false, Position = 1)] [switch] $M, [Parameter(Mandatory = $false, Position = 2)] [switch] $C, [Parameter(Mandatory = $false, Position = 3, ValueFromRemainingArguments = $true)] [string[]] $rest ) # awesome work from https://github.com/esc/git-stats # including some modifications [string] $currentBranchName = (git symbolic-ref HEAD 2> $null) if ($currentBranchName) { Write-Output "Number of commits per author:" & $git_bin --no-pager shortlog -sn --all $AUTHORS=(git shortlog -sn --all | ConvertFrom-Csv -Delimiter "`t" -Header CommitsCount, Author | Select-Object -ExpandProperty Author) $LOGOPTS="" if ($w) { $LOGOPTS="${LOGOPTS} -w" } if ($M) { $LOGOPTS="${LOGOPTS} -M" } if ($C) { $LOGOPTS="${LOGOPTS} -C --find-copies-harder" } foreach ($a in $AUTHORS) { Write-Output '-------------------' Write-Output "Statistics for: ${a}" [PSObject[]] $authorChangesPerFile = ( & $git_bin log ${LOGOPTS} --all --numstat --format="%n" --author="${a}" ` | Select-Object -Unique ` | ConvertFrom-Csv -Delimiter "`t" -Header LinesAdded, LinesDeleted, File ) [int] $filesChangedCount = $authorChangesPerFile.Count [int] $linesAddedCount = $authorChangesPerFile | Measure-Object -Property LinesAdded -Sum | Select-Object -ExpandProperty Sum [int] $linesDeletedCount = $authorChangesPerFile | Measure-Object -Property LinesDeleted -Sum | Select-Object -ExpandProperty Sum [int] $mergeCommitsCount = ( & $git_bin log --all --merges --author="Bruce Markham" | Where-Object { $_.StartsWith("commit") } ).Count Write-Output "Number of files changed: $filesChangedCount" Write-Output "Number of lines added: $linesAddedCount" Write-Output "Number of lines deleted: $linesDeletedCount" Write-Output "Number of merges: " $mergeCommitsCount } } else { Write-Error "you're currently not in a git repository" } } <# .SYNOPSIS Places the latest .gitignore file for a given project type in the current directory, or concatenates onto an existing .gitignore. .PARAMETER type The language/type of the project, used for determining the contents of the .gitignore file. .EXAMPLE gittowork java .COMPONENT Git #> function gittowork() { param( [Parameter(Mandatory = $true, Position = 0)] [string] $type ) $result=(Invoke-RestMethod "https://www.gitignore.io/api/$type") if (-not $result) { Write-Output "Query '$type' has no match. See a list of possible queries with 'gittowork list'" } elif ($type -eq "list") { Write-Output "${result}" } else { if (Test-Path .gitignore -ErrorAction SilentlyContinue) { Write-Output ".gitignore already exists, appending..." } $result | Out-File -Append .gitignore } } <# .SYNOPSIS Empties the git cache, and readds all files not blacklisted by .gitignore. .COMPONENT Git #> function gitignore-reload() { # The .gitignore file should not be reloaded if there are uncommited changes. # Firstly, require a clean work tree. The function require_clean_work_tree() # was stolen with love from https://www.spinics.net/lists/git/msg142043.html # Begin require_clean_work_tree() # Update the index & $git_bin update-index -q --ignore-submodules --refresh $err=0 # Disallow unstaged changes in the working tree & $git_bin diff-files --quiet --ignore-submodules -- if ($LASTEXITCODE -ne 0) { Write-Error "Cannot reload .gitignore: Your index contains unstaged changes." & $git_bin diff-index --cached --name-status -r --ignore-submodules HEAD -- | Write-Error err=1 } # Disallow uncommited changes in the index & $git_bin diff-index --cached --quiet HEAD --ignore-submodules if ($LASTEXITCODE -ne 0) { Write-Eror "Cannot reload .gitignore: Your index contains uncommited changes." & $git_bin diff-index --cached --name-status -r --ignore-submodules HEAD -- | Write-Error err=1 } # Prompt user to commit or stash changes and exit if ($err -ne 0) { Write-Error "Please commit or stash them." } # End require_clean_work_tree() # If we're here, then there are no uncommited or unstaged changes dangling around. # Proceed to reload .gitignore if ($err -eq 0) { # Remove all cached files & $git_bin rm -r --cached . # Re-add everything. The changed .gitignore will be picked up here and will exclude the files # now blacklisted by .gitignore Write-Warning "Running git add ." & $git_bin add . Write-Warning "Files readded. Commit your new changes now." } } <# .SYNOPSIS Creates the git changelog from one point to another by date. .PARAMETER commit_range The range of commits to include in the changelog. .PARAMETER format The format of the changelog. Can be either 'md' or 'txt'. .EXAMPLE git-changelog origin/master...origin/release md .COMPONENT Git #> function git-changelog() { param( [Parameter(Mandatory = $true, Position = 0)] [string] $commit_range, [Parameter(Mandatory = $false, Position = 1)] [ValidateSet("md", "txt")] [string] $format = "md" ) # --------------------------------------------------------------- # ORIGINAL ANSWER: https://stackoverflow.com/a/2979587/10362396 | # --------------------------------------------------------------- if(-not ($commit_range -like "*...*")) { throw "Please include the valid 'diff' to make changelog" } $NEXT=[DateTime]::Now.ToString("yyyy-MM-dd") if ($format -eq "md") { Write-Output "# CHANGELOG $commit_range" [string[]] $dates = (git log "$commit_range" --no-merges --format="%cd" --date=short | Sort-Object -Descending -Unique) foreach ($DATE in $dates) { Write-Output Write-Output "### ${DATE}" & $git_bin log --no-merges --format=" * (%h) %s by [%an](mailto:%ae)" --since="${DATE} 00:00:00" --until="${NEXT} 24:00:00" $NEXT=$DATE } } else { Write-Output "CHANGELOG $commit_range" Write-Output ---------------------- [string[]] $dates = (git log "$commit_range" --no-merges --format="%cd" --date=short | Sort-Object -Descending -Unique) foreach ($DATE in $dates) { Write-Output Write-Output "[${DATE}]" & $git_bin log --no-merges --format=" * (%h) %s by %an <%ae>" --since="${DATE} 00:00:00" --until="${NEXT} 24:00:00" $NEXT=$DATE } } } function Invoke-Git { & $git_bin @args } Set-Alias -Name g -Value Invoke-Git Set-Alias -Name get -Value Invoke-Git Set-Alias -Name gall -Value Add-GitTrackedFilesAll function Add-GitTrackedFilesVerbosely { & $git_bin add -v @args } Set-Alias -Name gav -Value Add-GitTrackedFilesVerbosely function Invoke-GitBranch { & $git_bin branch @args } Set-Alias -Name gb -Value Invoke-GitBranch Set-Alias -Name gbD -Value Remove-GitBranchForcefully Set-Alias -Name gbl -Value Get-GitBranchList function Get-GitBranchListAll { & $git_bin branch --list --all @args } Set-Alias -Name gbla -Value Get-GitBranchListAll function Get-GitBranchListRemotes { & $git_bin branch --list --remotes @args } Set-Alias -Name gblr -Value Get-GitBranchListRemotes function Rename-GitBranch { & $git_bin branch --move @args } Set-Alias -Name gbm -Value Rename-GitBranch function Get-GitBranchRemotes { & $git_bin branch --remotes @args } Set-Alias -Name gbr -Value Get-GitBranchRemotes function New-GitBranchTracked { & $git_bin branch --track @args } Set-Alias -Name gbt -Value New-GitBranchTracked Set-Alias -Name gdel -Value Remove-GitBranchForcefully # for-each-ref function Get-GitRemoteBranchesAuthors { & $git_bin for-each-ref --format="%(authorname) %09 %(if)%(HEAD)%(then)*%(else)%(refname:short)%(end) %09 %(creatordate)" refs/remotes/ --sort=authorname DESC @args # FROM https://stackoverflow.com/a/58623139/1036239 } Set-Alias -Name gbc -Value Get-GitRemoteBranchesAuthors function Update-GitCommitFilesVerboselyAll { & $git_bin commit -v -a @args } Set-Alias -Name gca -Value Update-GitCommitFilesVerboselyAll function Update-GitCommitByHead { & $git_bin commit -a --amend -C HEAD @args # Add uncommitted and unstaged changes to the last commit } Set-Alias -Name gcaa -Value Update-GitCommitByHead function Update-GitCommit { & $git_bin commit --amend @args } Set-Alias -Name gcamd -Value Update-GitCommit function Write-GitCommitInteractively { & $git_bin commit --interactive @args } Set-Alias -Name gci -Force -Value Write-GitCommitInteractively function Write-GitCommitGpgSignedByKey { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $true, Position = 1)] [string] $KeyId, [Parameter(Mandatory = $false, Position = 2, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit -S -am $Message $KeyId @rest } Set-Alias -Name gcsam -Value Write-GitCommitGpgSignedByKey function Use-GitBranchTracked { & $git_bin checkout --track @args } Set-Alias -Name gct -Value Use-GitBranchTracked # clone function Invoke-GitClone { & $git_bin clone @args } Set-Alias -Name gcl -Value Invoke-GitClone # clean function Remove-GitUntrackedFiles { & $git_bin clean -fd @args } Set-Alias -Name gclean -Value Remove-GitUntrackedFiles # cherry-pick function Start-GitCherryPickExplained { & $git_bin cherry-pick -x @args } Set-Alias -Name gcpx -Value Start-GitCherryPickExplained function Invoke-GitDifftool { & $git_bin difftool @args } Set-Alias -Name gdt -Value Invoke-GitDifftool # archive function Export-GitRepositoryZip { & $git_bin archive --format zip --output @args } Set-Alias -Name gexport -Value Export-GitRepositoryZip # fetch function Update-GitRemoteChanges { & $git_bin fetch --all --prune @args } Set-Alias -Name gfa -Value Update-GitRemoteChanges function Update-GitRemoteChangesTags { & $git_bin fetch --all --prune --tags @args } Set-Alias -Name gft -Value Update-GitRemoteChangesTags function Update-GitRemoteChangesTagsVerbose { & $git_bin fetch --all --prune --tags --verbose @args } Set-Alias -Name gftv -Value Update-GitRemoteChangesTagsVerbose function Update-GitRemoteChangesVerbose { & $git_bin fetch --all --prune --verbose @args } Set-Alias -Name gfv -Value Update-GitRemoteChangesVerbose function Merge-GitRepositoryFromUpstreamBranchMain { & $git_bin fetch origin -v if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin fetch upstream -v if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin merge upstream/$(Get-GitBranchDefault) @args } Set-Alias -Name gmu -Value Merge-GitRepositoryFromUpstreamBranchMain function Update-GitBranchBaseFromRemote { & $git_bin fetch if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin rebase @args } Set-Alias -Name gup -Value Update-GitBranchBaseFromRemote # log function Get-GitLogGraphStylized { & $git_bin log --graph --pretty=format:'\''%C(bold)%h%Creset%C(magenta)%d%Creset %s %C(yellow)<%an> %C(cyan)(%cr)%Creset'\'' --abbrev-commit --date=relative @args } Set-Alias -Name gg -Value Get-GitLogGraphStylized function Get-GitLogGraphStylizedDated { & $git_bin log --graph --date=short --pretty=format:'\''%C(auto)%h %Cgreen%an%Creset %Cblue%cd%Creset %C(auto)%d %s'\'' @args } Set-Alias -Name ggf -Value Get-GitLogGraphStylizedDated function Get-GitLogGraphStylizedStat { Get-GitLogGraphStylized --stat @args } Set-Alias -Name ggs -Value Get-GitLogGraphStylizedStat function Get-GitLogBranchCommitsUnpushed { & $git_bin log --branches --not --remotes --no-walk --decorate --oneline @args # FROM https://stackoverflow.com/questions/39220870/in-git-list-names-of-branches-with-unpushed-commits } Set-Alias -Name ggup -Value Get-GitLogBranchCommitsUnpushed function Get-GitLogGraph { & $git_bin log --graph --pretty=oneline --abbrev-commit @args } Set-Alias -Name gll -Value Get-GitLogGraph function Get-GitLogCommitsPulledLast { & $git_bin log HEAD@{1}..HEAD@{0} @args # Show commits since last pull, see http://blogs.atlassian.com/2014/10/advanced-git-aliases/ } Set-Alias -Name gnew -Value Get-GitLogCommitsPulledLast function Invoke-GitWhatchanged { & $git_bin whatchanged @args } Set-Alias -Name gwc -Value Invoke-GitWhatchanged function Get-GitUntrackedFiles { & $git_bin ls-files . --exclude-standard --others @args # Show untracked files } Set-Alias -Name glsut -Value Get-GitUntrackedFiles function Get-GitConflictedFiles { & $git_bin diff --name-only --diff-filter=U @args # Show unmerged (conflicted) files } Set-Alias -Name glsum -Value Get-GitConflictedFiles function Invoke-GitGui { & $git_bin gui @args } Set-Alias -Name ggui -Value Invoke-GitGui function Set-LocationGitHome { Set-Location "$(git rev-parse --show-toplevel)" @args # Git home } Set-Alias -Name ghm -Value Set-LocationGitHome function New-GitPatchFile { & $git_bin format-patch -1 @args | Get-Item } Set-Alias -Name gpatch -Value New-GitPatchFile function Publish-GitCommitsToOriginFromHead { & $git_bin push origin HEAD @args } Set-Alias -Name gpo -Value Publish-GitCommitsToOriginFromHead function Publish-GitCommitsToOriginMain { & $git_bin push origin $(Get-GitBranchDefault) @args } Set-Alias -Name gpom -Value Publish-GitCommitsToOriginMain function Publish-GitCommitsSettingUpstream { & $git_bin push --set-upstream @args } Set-Alias -Name gpu -Value Publish-GitCommitsSettingUpstream Set-Alias -Name gpunch -Value Publish-GitCommitsForcefullyWithLease function Publish-GitCommitsSettingUpstreamToOrigin { & $git_bin push --set-upstream origin @args } Set-Alias -Name gpuo -Value Publish-GitCommitsSettingUpstreamToOrigin function Publish-GitCommitsSettingUpstreamToOriginFromCurrent { & $git_bin push --set-upstream origin $(git symbolic-ref --short HEAD) @args } Set-Alias -Name gpuoc -Value Publish-GitCommitsSettingUpstreamToOriginFromCurrent # pull function Invoke-GitPull { & $git_bin pull @args } # Set-Alias -Name gl -Value 'git pull' function Update-GitBranchBaseFromUpstreamBranchMain { & $git_bin pull upstream $(Get-GitBranchDefault) @args } Set-Alias -Name glum -Value Update-GitBranchBaseFromUpstreamBranchMain function Invoke-GitRepositorySync { & $git_bin pull if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin push @args } Set-Alias -Name gpp -Value Invoke-GitRepositorySync Set-Alias -Name gpr -Value Update-GitBranchBaseFromRemote Set-Alias -Name gr -Value Invoke-GitRemote Set-Alias -Name gra -Value Add-GitRemote Set-Alias -Name grv -Value Get-GitRemotesList # rm function Remove-GitTrackedFiles { & $git_bin rm @args } Set-Alias -Name grm -Value Remove-GitTrackedFiles # rebase function Invoke-GitRebase { & $git_bin rebase @args } Set-Alias -Name grb -Value Invoke-GitRebase function Resume-GitBranchBaseUpdate { & $git_bin rebase --continue @args } Set-Alias -Name grbc -Value Resume-GitBranchBaseUpdate function Update-GitBranchBaseFromMain { & $git_bin rebase $(Get-GitBranchDefault) @args } Set-Alias -Name grmn -Value Update-GitBranchBaseFromMain function Update-GitBranchBaseFromMainInteractively { & $git_bin rebase $(Get-GitBranchDefault) -i @args } Set-Alias -Name grmi -Value Update-GitBranchBaseFromMainInteractively function Update-GitBranchBaseFromMainInteractivelyWithAutosquash { xwith @{ GIT_SEQUENCE_EDITOR = "" } { & $git_bin rebase $(Get-GitBranchDefault) -i --autosquash @args } @args } Set-Alias -Name grma -Value Update-GitBranchBaseFromMainInteractivelyWithAutosquash function Update-GitBranchBaseFromOriginUpdatedBranchMain { & $git_bin fetch origin $(Get-GitBranchDefault) if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin rebase origin/$(Get-GitBranchDefault) if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin update-ref refs/heads/$(Get-GitBranchDefault) origin/$(Get-GitBranchDefault) @args # Rebase with latest remote } Set-Alias -Name gprom -Value Update-GitBranchBaseFromOriginUpdatedBranchMain # reset function Reset-GitWorkingTreeToHead { & $git_bin reset HEAD @args } Set-Alias -Name gus -Value Reset-GitWorkingTreeToHead function Reset-GitWorkingTreeToLastCommitLoseChangesAndCleanFully { Reset-GitWorkingTreeToLastCommitLoseChanges if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin clean -dfx } Set-Alias -Name gpristine -Value Reset-GitWorkingTreeToLastCommitLoseChangesAndCleanFully function Get-GitStatusShort { & $git_bin status -s @args } Set-Alias -Name gss -Value Get-GitStatusShort # shortlog function Get-GitContributors { & $git_bin shortlog -sn @args } Set-Alias -Name gcount -Value Get-GitContributors Set-Alias -Name gsl -Value Get-GitContributors # svn function Publish-GitRepositoryToSvn { & $git_bin svn dcommit @args } Set-Alias -Name gsd -Value Publish-GitRepositoryToSvn function Update-GitRepositoryFromSvn { & $git_bin svn rebase @args # Git SVN } Set-Alias -Name gsr -Value Update-GitRepositoryFromSvn function New-GitBranchFromStash { & $git_bin stash branch @args } Set-Alias -Name gstb -Value New-GitBranchFromStash # kept due to long-standing usage Set-Alias -Name gstpo -Value Pop-GitStashEntry ## 'stash push' introduced in git v2.13.2 Set-Alias -Name gstpu -Value Push-GitStashEntry Set-Alias -Name gstpum -Value Push-GitStashEntryWithMessage ## 'stash save' deprecated since git v2.16.0, alias is now push Set-Alias -Name gsts -Value Push-GitStashEntry function Push-GitStashEntryWithMessage { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin stash push -m $Message @rest } Set-Alias -Name gstsm -Value Push-GitStashEntryWithMessage # submodules function Update-GitSubmoduleInitRecursive { & $git_bin submodule update --init --recursive @args } Set-Alias -Name gsu -Value Update-GitSubmoduleInitRecursive # switch # these aliases requires git v2.23+ function Invoke-GitSwitch { & $git_bin switch @args } Set-Alias -Name gsw -Value Invoke-GitSwitch function Switch-GitBranchNew { & $git_bin switch --create @args } Set-Alias -Name gswc -Value Switch-GitBranchNew function Switch-GitBranchMain { & $git_bin switch $(Get-GitBranchDefault) @args } Set-Alias -Name gswm -Value Switch-GitBranchMain function Switch-GitBranchAndTrack { & $git_bin switch --track @args } Set-Alias -Name gswt -Value Switch-GitBranchAndTrack # functions function gdv() { & $git_bin diff --ignore-all-space @args | vim -R -t } function Add-GitTrackedFiles { & $git_bin add @args } Set-Alias -Name ga -Value Add-GitTrackedFiles function Add-GitTrackedFilesAll { & $git_bin add --all @args } Set-Alias -Name gaa -Value Add-GitTrackedFilesAll function Add-GitTrackedFilesInteractively { & $git_bin add --interactive @args } Set-Alias -Name gai -Value Add-GitTrackedFilesInteractively Set-Alias -Name galias -Value git_list_aliases # Amend the most recent local commit: function Update-GitCommitMessage { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --amend -m $Message @rest # Only change commit message (optionally 'git add' files) } Set-Alias -Name gam -Value Update-GitCommitMessage function Update-GitCommitFilesAndMessage { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --amend -am $Message @rest # Add all modified files and change commit messag } Set-Alias -Name gama -Value Update-GitCommitFilesAndMessage function Update-GitCommitFiles { & $git_bin commit --amend --no-edit @args # Keep commit message (optionally 'git add' files) } Set-Alias -Name gan -Value Update-GitCommitFiles function Update-GitCommitFilesAll { & $git_bin commit --amend --no-edit -a @args # Add all modified files, but keep commit message } Set-Alias -Name gana -Value Update-GitCommitFilesAll function Invoke-GitAddInteractivelyPatch { & $git_bin add --patch @args } Set-Alias -Name gap -Value Invoke-GitAddInteractivelyPatch function Get-GitBranchListAll { & $git_bin branch --all @args } Set-Alias -Name gba -Value Get-GitBranchListAll function Remove-GitBranch { & $git_bin branch --delete @args } Set-Alias -Name gbd -Value Remove-GitBranch function Remove-GitBranchForcefully { & $git_bin branch --delete --force @args } Set-Alias -Name gbdf -Value Remove-GitBranchForcefully function Invoke-GitBlame { & $git_bin blame @args } Set-Alias -Name gbl -Value Invoke-GitBlame # 'git blame' that optionally takes line numbers: # Usage: gbll <file> [<from line>] [<to line>] # E.g. gbll README.md 10 # = gbll README.md 10 10 # = gbll README.md 10,10 # = git blame README.md -L 10,10 Set-Alias -Name gbll -Value 'git_blame_line' function Get-GitBranchList { & $git_bin branch --list @args } Set-Alias -Name gbls -Value Get-GitBranchList function Invoke-GitBisect { & $git_bin bisect @args } Set-Alias -Name gbs -Value Invoke-GitBisect function Confirm-GitBisectCommitBad { & $git_bin bisect bad @args } Set-Alias -Name gbsb -Value Confirm-GitBisectCommitBad function Confirm-GitBisectCommitGood { & $git_bin bisect good @args } Set-Alias -Name gbsg -Value Confirm-GitBisectCommitGood function Reset-GitBisect { & $git_bin bisect reset @args } Set-Alias -Name gbsr -Value Reset-GitBisect function Start-GitBisect { & $git_bin bisect start @args } Set-Alias -Name gbss -Value Start-GitBisect function Write-GitCommitHelpfullyVerbose { & $git_bin commit --verbose @args } Set-Alias -Name gc -Force -Value Write-GitCommitHelpfullyVerbose function Write-GitCommitAll { & $git_bin commit -am @args } Set-Alias -Name gcam -Value Write-GitCommitAll function Write-GitCommitAllWithEmptyMessage { & $git_bin commit --allow-empty-message -am "" @args } Set-Alias -Name gcame -Value Write-GitCommitAllWithEmptyMessage function Write-GitCommitAllGpgSigned { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --gpg-sign -am $Message @rest } Set-Alias -Name gcamg -Value Write-GitCommitAllGpgSigned function Write-GitCommitAllSignedoff { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --signoff -am $Message @rest } Set-Alias -Name gcams -Value 'git commit --signoff -am' function Write-GitCommitAllAsUpdate { & $git_bin commit -am "Update" @args } Set-Alias -Name gcamu -Value Write-GitCommitAllAsUpdate function Write-GitCommitAllowEmpty { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --allow-empty -m $Message @rest } Set-Alias -Name gcem -Value Write-GitCommitAllowEmpty function Invoke-GitConfig { & $git_bin config @args } Set-Alias -Name gcf -Value Invoke-GitConfig function Get-GitConfigList { & $git_bin config --list ` | ForEach-Object {[PSCustomObject]@{ Key=($_.Substring(0, $_.IndexOf('='))); Value=($_.Substring($_.IndexOf('=')+1)) }} } Set-Alias -Name gcfl -Value Get-GitConfigList Set-Alias -Name gcfls -Value Get-GitConfigList function Invoke-GitCloneWithSubmodulesRecursed { & $git_bin clone --recurse-submodules @args } Set-Alias -Name gcls -Value Invoke-GitCloneWithSubmodulesRecursed Set-Alias -Name gclcd -Value git_clone_and_cd function Write-GitCommit { param( [Parameter(Mandatory = $true, Position = 0)] [string] $message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit -m $message @rest } Set-Alias -Name gcm -Force -Value Write-GitCommit function Write-GitCommitGpgSigned { param( [Parameter(Mandatory = $true, Position = 0)] [string] $message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --gpg-sign -m $message @rest } Set-Alias -Name gcmg -Value Write-GitCommitGpgSigned function Write-GitCommitSignedoff { param( [Parameter(Mandatory = $true, Position = 0)] [string] $message, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin commit --signoff -m $message @rest } Set-Alias -Name gcms -Value Write-GitCommitSignedoff # Count the number of commits on a branch: Set-Alias -Name gcnt -Value git_count Set-Alias -Name gcnta -Value git_count_all function Use-GitBranch { & $git_bin checkout @args } Set-Alias -Name gco -Value Use-GitBranch function Use-GitBranchNew { & $git_bin checkout -b @args } Set-Alias -Name gcob -Value Use-GitBranchNew function Use-GitBranchPrevious { & $git_bin checkout - @args # "checkout branch before" } Set-Alias -Name gcobb -Value Use-GitBranchPrevious # Check out a child commit: # Usage: gcoc [<number of commits after HEAD>] # E.g. gcoc = gcoc 1 => checks out direct child # gcoc 2 => checks out grandchild Set-Alias -Name gcoc -Value git_checkout_child function Use-GitBranchDevelop { & $git_bin checkout develop @args } Set-Alias -Name gcod -Value Use-GitBranchDevelop function Use-GitBranchMain { & $git_bin checkout $(Get-GitBranchDefault) @args } Set-Alias -Name gcom -Value Use-GitBranchMain # Check out a parent commit: # Usage: gcop [<number of commits before HEAD>] # E.g. gcop = gcop 1 => checks out direct parent # gcop 2 => checks out grandparent Set-Alias -Name gcop -Value git_checkout_parent function Start-GitCherryPick { & $git_bin cherry-pick @args } Set-Alias -Name gcp -Value Start-GitCherryPick function Stop-GitCherryPick { & $git_bin cherry-pick --abort @args } Set-Alias -Name gcpa -Value Stop-GitCherryPick function Resume-GitCherryPick { & $git_bin cherry-pick --continue @args } Set-Alias -Name gcpc -Value Resume-GitCherryPick function Get-GitDiff { & $git_bin diff @args } Set-Alias -Name gd -Value Get-GitDiff function Get-GitDiffStaged { & $git_bin diff --staged @args } Set-Alias -Name gds -Value Get-GitDiffStaged # Show the diff between latest stash and local working tree: function Get-GitDiffStash { & $git_bin diff stash@{0} @args # = git stash show -l } Set-Alias -Name gdst -Value Get-GitDiffStash # Show the diff between latest stash and HEAD: function Get-GitDiffStashHead { & $git_bin diff stash@{0} HEAD @args } Set-Alias -Name gdsth -Value Get-GitDiffStashHead # Show the diff between latest stash and its original parent commit: function Get-GitDiffStashParent { & $git_bin diff stash@{0}^ stash@{0} @args # = git stash show -p } Set-Alias -Name gdstp -Value Get-GitDiffStashParent function Invoke-GitFetch { & $git_bin fetch @args } Set-Alias -Name gf -Value Invoke-GitFetch function Invoke-GitFetchOrigin { & $git_bin fetch origin @args } Set-Alias -Name gfo -Value Invoke-GitFetchOrigin # git graph branches: function Get-GitLogGraphBranchesSimplifiedStylized { & $git_bin log --graph --all --simplify-by-decoration --date=format:"%d/%m/%y" --pretty=format:"%C(yellow)%h%Creset%x09%C(bold green)%D%Creset%n%C(white)%ad%Creset%x09%C(bold)%s%Creset%n" @args } Set-Alias -Name ggb -Value Get-GitLogGraphBranchesSimplifiedStylized # Ignore already tracked files: function Add-GitSkipWorktreeFlag { & $git_bin update-index --skip-worktree @args } Set-Alias -Name gignore -Value Add-GitSkipWorktreeFlag function Remove-GitSkipWorktreeFlag { & $git_bin update-index --no-skip-worktree @args } Set-Alias -Name gunignore -Value Remove-GitSkipWorktreeFlag function Get-GitIgnoredFiles { & $git_bin ls-files -v | Where-Object { $_.StartsWith("S") } } Set-Alias -Name gignored -Value Get-GitIgnoredFiles # Best default 'git log': function Get-GitLogStylizedNameStatus { Get-GitLogStylized --name-status @args } Set-Alias -Name gl -Force -Value Get-GitLogStylizedNameStatus # View the full change history of a single file: # Usage: glf <file> [<from line>] [<to line>] Set-Alias -Name glf -Value git_log_file # Fancy 'git log --graph': function Get-GitLogStylizedGraph { Get-GitLogStylized --graph @args } Set-Alias -Name glg -Value Get-GitLogStylizedGraph # Fancy 'git log --graph --oneline': function Get-GitLogGraphOnelineStylized { & $git_bin log --graph --date=format:"%d/%m/%y" --pretty=format:"%C(yellow)%h%Creset %C(white)%ad%Creset %C(bold)%s %C(bold green)%D%Creset%n" @args } Set-Alias -Name glgo -Value Get-GitLogGraphOnelineStylized # Fancy 'git log --graph --stat': function Get-GitLogStylizedGraphStat { Get-GitLogStylized --graph --stat @args } Set-Alias -Name glgs -Value Get-GitLogStylizedGraphStat # Fancy 'git log --oneline': function Get-GitLogOnelineStylized { & $git_bin log --date=format:"%d/%m/%y" --pretty=format:"%C(yellow)%h%Creset %C(white)%ad%Creset %C(bold)%s %C(bold green)%D%Creset" @args } Set-Alias -Name glo -Value Get-GitLogOnelineStylized # Locate all commits in which a specific line of code (string) was first introduced: # Usage: gloc <Line-of-Code> [<file>] Set-Alias -Name gloc -Value git_locate_string # Regular 'git log' in style: function Get-GitLogStylized { & $git_bin log --date=format:"%A %B %d %Y at %H:%M" --pretty=format:"%C(yellow)%H%Creset%x09%C(bold green)%D%Creset%n%<|(40)%C(white)%ad%x09%an%Creset%n%n %C(bold)%s%Creset%n%w(0,4,4)%n%-b%n" @args # %w(0,4,4): no line-wrap, indent first line 4 chars, subsequent lines also 4 lines } Set-Alias -Name glog -Value Get-GitLogStylized function Get-GitLogStylizedReverseNameStatus { Get-GitLogStylized --reverse --name-status @args } Set-Alias -Name glr -Value Get-GitLogStylizedReverseNameStatus function Get-GitTrackedFiles { & $git_bin ls-files @args } Set-Alias -Name gls -Value Get-GitTrackedFiles function Invoke-GitMerge { & $git_bin merge @args } Set-Alias -Name gm -Force -Value Invoke-GitMerge function Merge-GitRepositoryFromOriginBranchMain { & $git_bin merge origin/$(Get-GitBranchDefault) @args } Set-Alias -Name gmom -Value Merge-GitRepositoryFromOriginBranchMain function Merge-GitRepositoryFromUpstreamBranchMain { & $git_bin merge upstream/$(Get-GitBranchDefault) @args } Set-Alias -Name gmum -Value Merge-GitRepositoryFromUpstreamBranchMain function Move-GitTrackedFiles { & $git_bin mv @args } Set-Alias -Name gmv -Value Move-GitTrackedFiles function Invoke-GitPush { & $git_bin push @args } Set-Alias -Name gp -Force -Value Invoke-GitPush function Remove-GitRemoteBranch { & $git_bin push --delete @args } Set-Alias -Name gpd -Value Remove-GitRemoteBranch function Remove-GitRemoteBranchOrigin { & $git_bin push --delete origin @args } Set-Alias -Name gpdo -Value Remove-GitRemoteBranchOrigin function Publish-GitCommitsForcefullyWithLease { & $git_bin push --force-with-lease @args } Set-Alias -Name gpf -Value Publish-GitCommitsForcefullyWithLease function Publish-GitCommitsWithTags { & $git_bin push if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } & $git_bin push --tags @args } Set-Alias -Name gpt -Value Publish-GitCommitsWithTags function Update-GitRepository { & $git_bin pull @args } Set-Alias -Name gpl -Value Update-GitRepository function Update-GitBranchBaseFromRemote { & $git_bin pull --rebase @args } Set-Alias -Name gplr -Value Update-GitBranchBaseFromRemote function Update-GitRepositoryAndSubmodules { & $git_bin pull --recurse-submodules @args } Set-Alias -Name gplrs -Value Update-GitRepositoryAndSubmodules # `grhard` is intentionally more verbose because `--hard` is unsafe; # there is no way to recover uncommitted changes. # In general the `--keep` flag is preferable. It will do exactly the same, # but abort if a file has uncommitted changes. # Having to type 'grhard' in full will make us think twice # about whether we REALLY want to get rid of all dirty files. function Reset-GitWorkingTreeToLastCommitAndUnstageChanges { & $git_bin reset --mixed @args # Keep changes, but unstage them (`--mixed` = default behaviour) } Set-Alias -Name gr -Value Reset-GitWorkingTreeToLastCommitAndUnstageChanges function Reset-GitWorkingTreeToLastCommitLoseChanges { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param( [Parameter(Mandatory = $false, Position = 0)] [string[]] $rest ) [string] $action = "Resetting working tree to last commit, losing all changes." if ($PSCmdlet.ShouldProcess($action)) { & $git_bin reset --hard @rest # Remove changes, including anything uncommitted (Dangerous!) } else { Write-Warning "Not: $action" } } Set-Alias -Name grhard -Value Reset-GitWorkingTreeToLastCommitLoseChanges function Reset-GitWorkingTreeToLastCommitAndKeepChanges { & $git_bin reset --keep @args # Safer version of `--hard`: reset is aborted if a file is dirty } Set-Alias -Name grk -Value Reset-GitWorkingTreeToLastCommitAndKeepChanges function Reset-GitStagedChanges { & $git_bin reset --soft @args # Keep changes, and keep them staged } Set-Alias -Name grs -Value Reset-GitStagedChanges # Reset HEAD to a previous commit: # Usage: grh [<number of commits before HEAD>] # E.g. grh = grh 1 => Reset HEAD to previous commit # grh 2 => Reset HEAD 2 commits function git_reset_head_mixed { git_reset_head --mixed @args } Set-Alias -Name grh -Value git_reset_head_mixed function git_reset_head_hard { git_reset_head --hard @args } Set-Alias -Name grhhard -Value git_reset_head_hard function git_reset_head_keep { git_reset_head --keep @args } Set-Alias -Name grhk -Value git_reset_head_keep function git_reset_head_soft { git_reset_head --soft @args } Set-Alias -Name grhs -Value git_reset_head_soft function Update-GitBranchBaseFromBranchMain { & $git_bin rebase $(Get-GitBranchDefault) @args } Set-Alias -Name grbm -Value Update-GitBranchBaseFromDefaultBranch function Invoke-GitRemote { & $git_bin remote @args } Set-Alias -Name grem -Value Invoke-GitRemote function Add-GitRemote { & $git_bin remote add @args } Set-Alias -Name grema -Value Add-GitRemote function Remove-GitRemote { & $git_bin remote rm @args } Set-Alias -Name gremrm -Value Remove-GitRemote function Set-GitRemoteUrl { & $git_bin remote set-url @args } Set-Alias -Name gremset -Value Set-GitRemoteUrl function Show-GitRemote { & $git_bin remote show @args } Set-Alias -Name gremsh -Value Show-GitRemote function Get-GitRemotesList { & $git_bin remote -v @args } Set-Alias -Name gremv -Value Get-GitRemotesList function Invoke-GitReflog { & $git_bin reflog @args # Useful to restore lost commits after reset } Set-Alias -Name grl -Value Invoke-GitReflog # Yes, I am aware gs is commonly aliased to ghostscript, # but since my usage of ghostscript is rare compared to git, # I can live with typing 'ghostscript' in full when necessary. function Get-GitStatus { & $git_bin status @args } Set-Alias -Name gs -Value Get-GitStatus function Invoke-GitShowStylized { & $git_bin show --date=format:"%A %B %d %Y at %H:%M" --pretty=format:"%C(yellow)%H%Creset%x09%C(bold green)%D%Creset%n%<|(40)%C(white)%ad%x09%an%Creset%n%n %C(bold)%s%Creset%n%w(0,4,4)%+b%n" @args } Set-Alias -Name gsh -Value Invoke-GitShowStylized Set-Alias -Name gshsf -Value git_show_stash_file Set-Alias -Name gssll -Value git_status_short_with_loglines function Invoke-GitStash { & $git_bin stash @args } Set-Alias -Name gst -Value Invoke-GitStash function Use-GitStashEntry { & $git_bin stash apply @args } Set-Alias -Name gsta -Value Use-GitStashEntry function Remove-GitStashEntry { & $git_bin stash drop @args } Set-Alias -Name gstd -Value Remove-GitStashEntry function Get-GitStashList { & $git_bin stash list @args } Set-Alias -Name gstl -Value Get-GitStashList Set-Alias -Name gstls -Value Get-GitStashList function Push-GitStashEntry { & $git_bin stash push @args } Set-Alias -Name gstp -Value Push-GitStashEntry function Pop-GitStashEntry { & $git_bin stash pop @args } Set-Alias -Name gstpop -Value Pop-GitStashEntry # Show the diff between latest stash and local working tree: function Get-GitStashDiffFromWorkingTree { & $git_bin stash show -l @args # = git diff stash@{0} } Set-Alias -Name gstsl -Value Get-GitStashDiffFromWorkingTree # Show the diff between latest stash and its original parent commit: function Get-GitStashDiffFromParent { & $git_bin stash show -p @args # = git diff stash@{0}^! = git diff stash@{0}^ stash@{0 } Set-Alias -Name gstsp -Value Get-GitStashDiffFromParent function Invoke-GitSubmodule { & $git_bin submodule @args } Set-Alias -Name gsub -Value Invoke-GitSubmodule function Add-GitSubmodule { & $git_bin submodule add @args } Set-Alias -Name gsuba -Value Add-GitSubmodule function Update-GitSubmoduleInit { & $git_bin submodule update --init @args # Initialize submodules } Set-Alias -Name gsubi -Value Update-GitSubmoduleInit function Invoke-GitSubmoduleAllPull { & $git_bin submodule foreach git pull @args } Set-Alias -Name gsubpl -Value Invoke-GitSubmoduleAllPull function Invoke-GitSubmoduleAllPullOrigin { & $git_bin submodule foreach git pull origin $(Get-GitBranchDefault) @args } Set-Alias -Name gsubplom -Value Invoke-GitSubmoduleAllPullOrigin function Get-GitSubmoduleStatus { & $git_bin submodule status @args } Set-Alias -Name gsubs -Value Get-GitSubmoduleStatus function Update-GitSubmoduleFromRemoteMerge { & $git_bin submodule update --remote --merge @args # Update submodules } Set-Alias -Name gsubu -Value Update-GitSubmoduleFromRemoteMerge function Invoke-GitTag { & $git_bin tag @args } Set-Alias -Name gt -Value Invoke-GitTag function Add-GitTagAnnotated { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $true, Position = 1)] [string] $Name, [Parameter(Mandatory = $false, Position = 2, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin tag -am $Message $Name @args # <- takes message before annotated tag name: e.g. gtam 'Release v1.0.0' v1.0.0 } Set-Alias -Name gtam -Value Add-GitTagAnnotated function Add-GitTagGpgSigned { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Message, [Parameter(Mandatory = $true, Position = 1)] [string] $Name, [Parameter(Mandatory = $false, Position = 2, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin tag -sm $Message $Name @rest # GPG sign an annotated tag } Set-Alias -Name gtsm -Value Add-GitTagGpgSigned function Remove-GitTag { param( [Parameter(Mandatory = $true, Position = 0)] [string] $Tag, [Parameter(Mandatory = $false, Position = 1, ValueFromRemainingArguments = $true)] [string[]] $rest ) & $git_bin tag --delete $Tag @rest } Set-Alias -Name gtd -Value Remove-GitTag function Get-GitTagList { & $git_bin tag --list @args } Set-Alias -Name gtl -Value Get-GitTagList Set-Alias -Name gtls -Value Get-GitTagList function Get-GitWhatChangedStylized { & $git_bin whatchanged -p --date=format:"%A %B %d %Y at %H:%M" --pretty=format:"%n%n%C(yellow)%H%Creset%x09%C(bold green)%D%Creset%n%<|(40)%C(white)%ad%x09%an%Creset%n%n %C(bold)%s%Creset%n%w(0,4,4)%+b%n" @args } Set-Alias -Name gwch -Value Get-GitWhatChangedStylized # Functions ################ # git blame that optionally takes line numbers: # Usage: git_blame_line <file> [<from line>] [<to line>] function git_blame_line { param( [Parameter(Mandatory=$true, Position=0)] [string] $File, [Parameter(Mandatory=$false, Position=1, ParameterSetName='FromLine')] [Parameter(Mandatory=$true, Position=1, ParameterSetName='FromLineToLine')] [Nullable[int]] $FromLine, [Parameter(Mandatory=$true, Position=1, ParameterSetName='LineRange')] [ValidateCount(2,2)] [int[]] $LineRange, [Parameter(Mandatory=$true, Position=2, ParameterSetName='FromLineToLine')] [Nullable[int]] $ToLine ) if ($LineRange) { $FromLine = $LineRange[0] $ToLine = $LineRange[1] } elseif ($null -eq $FromLine) { $FromLine = 1 } if ($null -eq $ToLine) { $ToLine = $FromLine } & $git_bin blame $File -L "$FromLine,$ToLine" } # Checkout parent/older commit: function git_checkout_parent() { param( [Parameter(Mandatory=$false, Position=0)] [ValidateRange(1, [int]::MaxValue)] [int] $Offset = 1 ) & $git_bin checkout HEAD~$Offset } # Checkout child/newer commit: function git_checkout_child { param( [Parameter(Mandatory=$false, Position=0)] [ValidateRange(1, [int]::MaxValue)] [int] $Offset = 1 ) [string[]] $children=(git log --all --ancestry-path ^HEAD --format=format:%H) if (-not $children) { Write-Output 'This commit does not have any children' Write-Output "HEAD remains at "+(git log -1 --oneline) return 1 } else { # Take the first child, or the one specified by the input arg: $child=$children[$Offset-1] # If the child to checkout is at the branch's tip ... if ($children.Count -le $Offset) { [string[]] $branches=(git branch --contains $child) -split ' ' # ... and there is only 1 branch with that commit ... if ($branches.Count -eq 1) { # ... checkout the branch itself instead of the specific hash: $child=$branch } } } & $git_bin checkout $child } function git_clone_and_cd { param( [Parameter(Mandatory=$true, Position=0)] [string] $Repo, [Parameter(Mandatory=$false, Position=1)] [string] $Name = $null ) if (-not $Name) { $Name = $(basename $Repo .git) } & $git_bin clone --recurse-submodules $Repo $Name Set-Location $Name } function git_count { [int] $count = (git rev-list --count HEAD) Write-Output "$count commits total up to current HEAD" } function git_count_all { & $git_bin shortlog -sn Write-Output "+ _______________________________________" Write-Output Write-Output " "+(git_count) } # Locate all commits in which a specific line of code (string) was first introduced: function git_locate_string { param( [Parameter(Mandatory=$true, Position=0)] [string] $Text, [Parameter(Mandatory=$false, Position=1)] [string] $File = $null ) Get-GitLogStylizedNameStatus -S $Text -- $File } # View the full change history of a single file: function git_log_file { param( [Parameter(Mandatory=$true, Position=0)] [string] $File, [Parameter(Mandatory=$false, Position=1, ParameterSetName='FromLine')] [Parameter(Mandatory=$true, Position=1, ParameterSetName='FromLineToLine')] [Nullable[int]] $FromLine, [Parameter(Mandatory=$true, Position=1, ParameterSetName='LineRange')] [ValidateCount(2,2)] [int[]] $LineRange, [Parameter(Mandatory=$true, Position=2, ParameterSetName='FromLineToLine')] [Nullable[int]] $ToLine ) if (-not $FromLine) { Get-GitLogStylized -p -- $File exit } elseif ( $LineRange ) { $FromLine = $LineRange[0] $ToLine = $LineRange[1] } elseif( -not $ToLine ) { $ToLine = $FromLine } Get-GitLogStylized -L ${FromLine},${ToLine}:${File} } # Check if main exists and use instead of master: function Get-GitBranchDefault { [bool] $mainBranchExists = (-not [string]::IsNullOrWhiteSpace((git branch --list main))) if ($mainBranchExists) { return "main" } else { return "master" } } # Reset the head to a previous commit (defaults to direct parent): function git_reset_head { param( [Parameter(Mandatory=$false, Position=0)] [ValidateSet('--hard', '--keep', '--soft', '--merge', '--keep', '')] [string] $Mode = '', [Parameter(Mandatory=$false, Position=1)] [Nullable[int]] $Count = $null ) & $git_bin reset HEAD~$Count $Mode if ($LASTEXITCODE -ne 0) { # Failure case: Write-Output -n 'HEAD remains at ' & $git_bin log -1 --oneline exit 1 } elseif ($Mode -ne '--hard') { # Success case (unless --hard was specified): Write-Output -n 'HEAD is now at ' & $git_bin log -1 --oneline } } # Show a specified file from stash x (defaults to lastest stash): # Usage: git_show_stash_file <file> [<stash number>] function git_show_stash_file { param() { [Parameter(Mandatory=$true, Position=0)] [string] $File [Parameter(Mandatory=$false, Position=1)] [int] $StashNumber = 0 } & $git_bin show stash@{$StashNumber}:$File } # Print short status and log of latest commits: function git_status_short_with_loglines { param( [Parameter(Mandatory=$false, Position=0)] [int] $Count = 3 ) [string] $gitStatus = (git status -s | Out-String) if (-not $gitStatus) { Write-Output 'Nothing to commit, working tree clean' } else { Write-Output $gitStatus } & $git_bin log -$Count --oneline } Set-Alias -Name pushgr -Value Push-LocationGitRoot Set-Alias -Name cdgr -Value Set-LocationGitRoot |