Git.ps1
|
# Copyright (c) Microsoft Corporation. # Licensed under the MIT License. function Initialize-GitConfig { <# .SYNOPSIS Configure git before the first use; assigns name and email for the current user and sets up some useful defaults #> [CmdletBinding()] param ( [switch] $Force ) $gitName = git config --global user.name if( $gitName -and (-not $Force) ) { Write-Warning "Looks like git is already configured. If you want to overwrite git config settings anyway, use -Force switch." return } # Git name and email (required) if( $env:USERDOMAIN -eq "Redmond" ) { # Figure out name of the current user from Active Directory $ntAccount = New-Object Security.Principal.NTAccount($env:USERDOMAIN, $env:USERNAME) $sid = $ntAccount.Translate([Security.Principal.SecurityIdentifier]) $ldap = [adsi] "LDAP://<SID=$sid>" git config --global user.name $ldap.cn git config --global user.email "$ENV:USERNAME@microsoft.com" } else { $name = Read-Host "User name" git config --global user.name $name $email = Read-Host "User email" git config --global user.email $email } Write-Output "Git user name and email are configured" git config --global --replace-all color.grep auto git config --global --replace-all color.grep.filename "green" git config --global --replace-all color.grep.linenumber "cyan" git config --global --replace-all color.grep.match "magenta" git config --global --replace-all color.grep.separator "black" git config --global --replace-all grep.lineNumber true git config --global --replace-all grep.extendedRegexp true git config --global --replace-all color.diff.meta "yellow" git config --global --replace-all color.diff.frag "cyan" git config --global --replace-all color.diff.func "cyan bold" git config --global --replace-all color.diff.commit "yellow bold" Write-Output "Git defaults are configured" # Aliases for the most used commands git config --global alias.co checkout git config --global alias.ci commit git config --global alias.st status git config --global alias.br branch git config --global alias.lg "log --graph --pretty=format:'%C(reset)%C(yellow)%h%C(reset) -%C(bold yellow)%d%C(reset) %s %C(green)(%cr) %C(cyan)<%an>%C(reset)' --abbrev-commit --date=relative -n 10" git config --global alias.gr "grep --break --heading --line-number -iIE" Write-Output "Git aliases are configured" } function Open-GitExtensions { <# .SYNOPSIS Open GitExtensions GUI frontend By default the browse window in the current folder would be opened .PARAMETER Args Any arguments that should be passed to the git extensions .PARAMETER NewEnvironment Use new environment for the process. This is a workaround for CoreXT that redefines the available dot net runtimes and this messes up with the .NET 8 runtime lookup done by the latest GitExtensions .EXAMPLE gite commit Open git extension commit dialog for the repo in the current folder #> param ( [Parameter( Mandatory = $false )] [string[]] $args, [switch] $NewEnvironment ) if( -not (Get-Command GitExtensions.exe -ea Ignore) ) { throw "GitExtensions.exe must be discoverable via PATH environment variable" } $param = $args if( -not $param ) { $param = @("browse") } if( $NewEnvironment ) { pwsh -nop -c "Start-Process GitExtensions.exe -UseNewEnvironment -WorkingDirectory $pwd -ArgumentList $($param -join ' ')" } else { & GitExtensions.exe $param } } function Get-CommitAuthorName( [string] $commit ) { <# .SYNOPSIS Get author name from a git commit #> git log -1 --pretty=format:'%aN' $commit } function Get-CommitAuthorEmail( [string] $commit ) { <# .SYNOPSIS Get author email from a git commit #> git log -1 --pretty=format:'%aE' $commit } function Get-CommitAuthorDate( [string] $commit ) { <# .SYNOPSIS Get author commit date from a git commit #> git log -1 --pretty=format:'%ai' $commit } function Get-CommitMessage( [string] $commit ) { <# .SYNOPSIS Get commit message from a git commit #> git log -1 --pretty=format:'%B' $commit } function Undo-GitCommit { <# .SYNOPSIS Revert the last git commit but keep all changes staged .DESCRIPTION Performs 'git reset --soft HEAD~1' which undoes the last commit while preserving all changes in the staging area (index). This is useful when you want to amend, restructure, or redo your last commit without losing any work. .EXAMPLE Undo-GitCommit Reverts the last commit, leaving changes staged and ready to recommit. #> [CmdletBinding()] param() $lastCommit = git log -1 --pretty=format:'%h %s' 2>&1 if( $LASTEXITCODE -ne 0 ) { Write-Error "No git repository found or no commits exist." return } git reset --soft HEAD~1 if( $LASTEXITCODE -eq 0 ) { Write-Output "Undid commit: $lastCommit" Write-Output "Changes are still staged." } else { Write-Error "Failed to undo the last commit." } } function Reset-GitWorkingTree { <# .SYNOPSIS Discard all uncommitted changes in the working tree and staging area .DESCRIPTION Performs 'git checkout -- .' to discard modified tracked files and 'git clean -fd' to remove untracked files and directories. This restores the working tree to match the last commit exactly. .PARAMETER IncludeUntracked Also remove untracked files and directories. Default is $true. .EXAMPLE Reset-GitWorkingTree Discards all uncommitted changes including untracked files. .EXAMPLE Reset-GitWorkingTree -IncludeUntracked:$false Discards only tracked file changes, keeping untracked files. #> [CmdletBinding(SupportsShouldProcess)] param ( [switch] $IncludeUntracked = $true ) $status = git status --porcelain 2>&1 if( $LASTEXITCODE -ne 0 ) { Write-Error "No git repository found." return } if( -not $status ) { Write-Output "Working tree is already clean." return } if( $PSCmdlet.ShouldProcess("working tree", "Discard all uncommitted changes") ) { git reset HEAD -- . 2>&1 | Out-Null git checkout -- . if( $IncludeUntracked ) { git clean -fd } if( $LASTEXITCODE -eq 0 ) { Write-Output "All uncommitted changes have been discarded." } else { Write-Error "Failed to reset the working tree." } } } |