Public/Update-GitCommit.ps1
function Update-GitCommit { <# .SYNOPSIS Amends an existing commit. .DESCRIPTION By default, this command will update the last commit using git commit --amend. You can also provide the commit message of an existing commit to be amended. This command will, by default, immediately rewrite the git history to apply the change to the specified commit. > Note that this may also apply other fixups and squashes that have not yet been squashed. If there are changed files already in the index, this command will commit only those files. Otherwise, all changed files in the working tree are added and committed. .PARAMETER Reword Specifies to change the commit message of the last commit. Only the message is changed; files in the index and working tree are left uncommitted. .PARAMETER Message Provide the message of an existing commit to be amended. When used with the Reword parameter, this message becomes the new message for the commit. .PARAMETER NoRebase Specifies to create a fixup commit but not to apply it to the historical commit. By default, when fixing up a commit, a non-interactive rebase will be performed to apply the fixup. .OUTPUTS [void] #> [CmdletBinding(DefaultParameterSetName = 'Amend')] param ( [Parameter(ParameterSetName = 'Reword', Mandatory)] [switch]$Reword, [Parameter(ParameterSetName = 'Reword', Mandatory, Position = 0)] [Parameter(ParameterSetName = 'Fixup', Mandatory, Position = 0)] [Parameter(ParameterSetName = 'FixupAndRebase', Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string]$Message, [Parameter(ParameterSetName = 'Fixup', Mandatory)] [switch]$NoRebase ) [ValidateSet('Amend', 'Reword', 'Fixup', 'FixupAndRebase')]$Action = $PSCmdlet.ParameterSetName $Status = Get-GitStatus $IndexFiles = $Status | Where-Object Index | Select-Object -ExpandProperty File if (-not $Status -and -not $Reword) { throw "Nothing to commit" } if (-not $IndexFiles) { Write-Warning "Nothing in index; auto-staging all files" git add * } if ($Message -eq (Get-GitLog 1 | Select-Object -ExpandProperty Summary)) { $Action = 'Amend' } $EscapedMessage = $Message -replace '"', '\"' if ($Action -eq 'Amend') { git commit --amend --no-edit | Out-Null } elseif ($Action -eq 'Reword') { git stash --all | Out-Null git commit --amend --no-edit -m $EscapedMessage | Out-Null git stash pop --index | Out-Null } else { git commit -m "fixup! $EscapedMessage" | Out-Null $ShouldRebase = $? -and $Action -eq 'FixupAndRebase' } if ($? -and $Action -eq 'FixupAndRebase') { $History = Get-GitLog | Select-Object -ExpandProperty Summary $Message = $History[0] -replace '^fixup! ' $CountToRebase = $History.IndexOf($Message) if ($CountToRebase -gt 1) { Invoke-GitRebase -Count ($CountToRebase + 1) } else { # Could happen if: # - user specifies message manually, but it's before Get-GitLog's default limit # - argument completer no longer current with this command # - message gets garbled and doesn't match history exactly (then it would probably not rebase properly anyway) throw "Not rebasing to apply fixup; the target commit for the fixup is not within the default history search limit. Please rebase manually to apply the fixup." } } } Register-ArgumentCompleter -CommandName Update-GitCommit -ParameterName Message -ScriptBlock { param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $Completions = if ($fakeBoundParameters.Reword) { $LastCommit = Get-GitLog -Count 1 $LastCommit.Summary } else { $MatchingCommits = Get-GitLog @($MatchingCommits.Summary) -like "*$wordToComplete*" } $Completions -replace '"', '`"' -replace '\$', '`$' -replace '^|$', '"' # escape dbl-quotes, wrap in dbl-quotes } |