functions/Get-GitLog.ps1
function Get-GitLog { <# .SYNOPSIS Gets a list of commits from the git log. .DESCRIPTION Gets a list of commits from the git log. .PARAMETER Repo The name of a git repository, or the path or a substring of the path of a repository directory or any of its subdirectories or files. If the Repo parameter is omitted, the current repository will be used if currently inside a repository; otherwise, nothing is returned. For examples of using the Repo parameter, refer to the help text for Get-GitRepo. .PARAMETER InRef A list of repository references (i.e. branch names, tag names, or commit SHA1 hashes). Commits reachable from any of these references are included in the results. If ommitted, defaults to HEAD. For further details on how to specify a reference, see https://git-scm.com/docs/gitrevisions#_specifying_revisions. .PARAMETER NotInRef A list of repository references (i.e. branch names, tag names, or commit SHA1 hashes). Commits reachable from any of these references are excluded from the results. If ommitted, defaults to HEAD. For further details on how to specify a reference, see https://git-scm.com/docs/gitrevisions#_specifying_revisions. .PARAMETER RefRange A revision range used to limit the commits returned, given in native git format e.g. "branch1...branch2". For further details on how to specify a range, see https://git-scm.com/docs/gitrevisions#_specifying_ranges. .PARAMETER Count Specifies the number of commits to retrieve. Commits are retrieved in reverse order, so specifying a Count of 5 will return the last 5 commits. .PARAMETER NoMerges Excludes merge commits (commits with more than one parent) from the results. .EXAMPLE ## Call from outside a repository without parameters ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Get-GitLog # Nothing was returned because a Repo was not provided. .EXAMPLE ## Call from outside a repository with Repo parameter ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main # checkout the main branch from the current location PS C:\> Get-GitLog -Repo MyToolbox | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox ba6dfdc703948adbd01590c965932ae8ff692aa0 nmbell Merging from feature1 MyToolbox beffe458a0460726f79316fd0dad2d2392a35b64 nmbell Add feature1_File1.txt MyToolbox 3a987081541ca2f31f575d47287cb3fdf82a1135 nmbell feature1 commit MyToolbox 87b1320518c17702d30e463966bc070ce6481459 nmbell Initial commit # The commits were returned even though the command was issued from outside the repository directory. .EXAMPLE ## Get commits from the current repository ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main -SetLocation # move to the repository directory and checkout the main branch PS C:\PowdrgitExamples\MyToolbox> Get-GitLog | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox ba6dfdc703948adbd01590c965932ae8ff692aa0 nmbell Merging from feature1 MyToolbox beffe458a0460726f79316fd0dad2d2392a35b64 nmbell Add feature1_File1.txt MyToolbox 3a987081541ca2f31f575d47287cb3fdf82a1135 nmbell feature1 commit MyToolbox 87b1320518c17702d30e463966bc070ce6481459 nmbell Initial commit .EXAMPLE ## Call with Count parameter ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main -SetLocation # move to the repository directory and checkout the main branch PS C:\PowdrgitExamples\MyToolbox> Get-GitLog -Count 3 | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox ba6dfdc703948adbd01590c965932ae8ff692aa0 nmbell Merging from feature1 MyToolbox beffe458a0460726f79316fd0dad2d2392a35b64 nmbell Add feature1_File1.txt MyToolbox 3a987081541ca2f31f575d47287cb3fdf82a1135 nmbell feature1 commit # Only the three most recent commits were returned. .EXAMPLE ## Call with NoMerges switch ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main -SetLocation # move to the repository directory and checkout the main branch PS C:\PowdrgitExamples\MyToolbox> Get-GitLog -NoMerges | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox beffe458a0460726f79316fd0dad2d2392a35b64 nmbell Add feature1_File1.txt MyToolbox 3a987081541ca2f31f575d47287cb3fdf82a1135 nmbell feature1 commit MyToolbox 87b1320518c17702d30e463966bc070ce6481459 nmbell Initial commit # Merge commits were omitted. .EXAMPLE ## Call with InRef and NotInRef ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main -SetLocation # move to the repository directory and checkout the main branch PS C:\PowdrgitExamples\MyToolbox> Get-GitLog -InRef feature3 -NotInRef main | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox 87e8501a197f8db5a54427c8a39803cf9e12ab66 nmbell Add feature3_FileA.txt # Only commits that were in the feature3 branch but not in main branch were returned. .EXAMPLE ## Call with RefRange ## PS C:\> $Powdrgit.Path = 'C:\PowdrgitExamples\MyToolbox;C:\PowdrgitExamples\Project1' # to ensure the repository paths are defined PS C:\> Set-GitBranch -Repo MyToolbox -BranchName main -SetLocation # move to the repository directory and checkout the main branch PS C:\PowdrgitExamples\MyToolbox> Get-GitLog -RefRange 'main..feature3' | Format-Table -Property RepoName,SHA1Hash,AuthorName,Subject RepoName SHA1Hash AuthorName Subject -------- -------- ---------- ------- MyToolbox 87e8501a197f8db5a54427c8a39803cf9e12ab66 nmbell Add feature3_FileA.txt # Equivalent to the previous example. .INPUTS [System.String[]] Accepts string objects via the Repo parameter. The output of Get-GitRepo can be piped into Get-GitLog. .OUTPUTS [GitCommit] Returns a custom GitCommit object. For details use Get-Member at a command prompt e.g.: PS C:\PowdrgitExamples\MyToolbox> Get-GitLog | Get-Member -MemberType Properties .NOTES Author : nmbell .LINK Get-GitCommit .LINK Get-GitCommitFile .LINK Get-GitFileHistory .LINK Get-GitRepo .LINK about_powdrgit .LINK https://github.com/nmbell/powdrgit/blob/main/help/about_powdrgit.md #> # Function alias [Alias('ggl')] # Use cmdlet binding [CmdletBinding( DefaultParameterSetName = 'InRef' , HelpURI = 'https://github.com/nmbell/powdrgit/blob/main/help/Get-GitLog.md' )] # Declare output type [OutputType('GitCommit')] # Declare parameters Param( [Parameter( Mandatory = $false , Position = 0 , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $true )] # [ArgumentCompleter()] [Alias('RepoName','RepoPath')] [String[]] $Repo , [Parameter( Mandatory = $false , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $true , ParameterSetName = 'InRef' )] # [ArgumentCompleter()] [Alias('SHA1Hash')] [String[]] $InRef , [Parameter( Mandatory = $false , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $false , ParameterSetName = 'InRef' )] # [ArgumentCompleter()] [String[]] $NotInRef , [Parameter( Mandatory = $false , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $false , ParameterSetName = 'RefRange' )] [String[]] $RefRange , [Parameter( Mandatory = $false , ValueFromPipeline = $false , ValueFromPipelineByPropertyName = $true )] [Int32] $Count , [Switch] $NoMerges ) BEGIN { $bk = 'B' # Common BEGIN: Set-StrictMode -Version 3.0 $thisFunctionName = $MyInvocation.MyCommand $start = Get-Date $indent = ($Powdrgit.DebugIndentChar[0]+' ')*($PowdrgitCallDepth++) $PSDefaultParameterValues += @{ '*:Verbose' = $(If ($DebugPreference -notin 'Ignore','SilentlyContinue') { $DebugPreference } Else { $VerbosePreference }) } # turn on Verbose with Debug Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Start: $($start.ToString('yyyy-MM-dd HH:mm:ss.fff'))" # Function BEGIN: Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Finding current location" $startLocation = $PWD.Path $startOfText = '!!>>' # commit info delimiter $endOfText = '<<!!' # commit info delimiter $separator = [char]30 # ASCII Record Separator $gitCommandTemplate = 'git log <InRef><NotInRef><Count><NoMerges>--date=iso8601-strict-local --format="'+$startOfText+'%H'+$separator+'%T'+$separator+'%P'+$separator+'%ad'+$separator+'%an'+$separator+'%ae'+$separator+'%cd'+$separator+'%cn'+$separator+'%ce'+$separator+'%D'+$separator+'%s'+$separator+'%b'+$endOfText+'"' # https://git-scm.com/docs/git-log#_pretty_formats } PROCESS { $bk = 'P' # Find the repository name from current location If (!$PSBoundParameters.ContainsKey('Repo')) { $Repo = Get-GitRepo -Current | Select-Object -ExpandProperty RepoPath } # Get the repository info $validRepos = Get-ValidRepo -Repo $Repo # Get the log entries ForEach ($validRepo in $validRepos) { # Go to the repository and get the repository info Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Moving to the repository directory: $($validRepo.RepoPath)" Set-GitRepo -Repo $validRepo.RepoPath -WarningAction Ignore # Get log entries $gitCommand = $gitCommandTemplate $refRangeReplacement = '<InRef><NotInRef>' $inRefReplacement = 'HEAD ' $notInRefReplacement = '' $countReplacement = '' $noMergesReplacement = '' If ($RefRange ) { $refRangeReplacement = $RefRange.Trim() +' ' } If ($InRef ) { $inRefReplacement = ($InRef -join ' ' ) +' ' } If ($NotInRef ) { $notInRefReplacement = '^'+($NotInRef -join ' ^') +' ' } If ($Count -or $Count -gt 0) { $countReplacement = '--max-count='+$Count.ToString()+' ' } If ($NoMerges ) { $noMergesReplacement = '--no-merges' +' ' } $gitCommand = $gitCommand.Replace('<InRef><NotInRef>',$refRangeReplacement) $gitCommand = $gitCommand.Replace('<InRef>' ,$inRefReplacement ) $gitCommand = $gitCommand.Replace('<NotInRef>' ,$notInRefReplacement) $gitCommand = $gitCommand.Replace('<Count>' ,$countReplacement ) $gitCommand = $gitCommand.Replace('<NoMerges>' ,$noMergesReplacement) Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Getting git log for $($validRepo.RepoName)" $gitResults = Invoke-GitExpression -Command $gitCommand -SuppressGitErrorStream ` | ConvertTo-GitParsableResults -StartOfText $startOfText -EndOfText $endOfText Write-Verbose "$(ts)$indent[$thisFunctionName][$bk]Found log entries: $('{0,3}' -f ($gitResults | Measure-Object).Count)" # Parse the results If ($gitResults) { ForEach ($line in $gitResults | Where-Object { $_.Trim() }) { $lineSplit = $line.Replace($startOfText,'').Replace($endOfText,'').Split($separator) # Output [GitCommit]@{ 'RepoName' = $validRepo.RepoName 'RepoPath' = $validRepo.RepoPath 'SHA1Hash' = $lineSplit[0] 'TreeHash' = $lineSplit[1] 'ParentHashes' = $lineSplit[2].Split(' ').Trim() 'IsMerge' = $lineSplit[2].Split(' ').Count -gt 1 'AuthorDate' = [DateTime]::Parse($lineSplit[3]) 'AuthorName' = $lineSplit[4] 'AuthorEmail' = $lineSplit[5] 'CommitterDate' = $lineSplit[6] 'CommitterName' = $lineSplit[7] 'CommitterEmail' = $lineSplit[8] 'RefNames' = $lineSplit[9].Split(',').Trim() 'Subject' = $lineSplit[10] 'Body' = $lineSplit[11] } } } } } END { $bk = 'E' # Function END: Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Setting location to original directory" Set-Location -Path $startLocation # Common END: $end = Get-Date $duration = New-TimeSpan -Start $start -End $end Write-Debug " $(ts)$indent[$thisFunctionName][$bk]Finish: $($end.ToString('yyyy-MM-dd HH:mm:ss.fff')) ($($duration.ToString('d\d\ hh\:mm\:ss\.fff')))" $PowdrgitCallDepth-- } } |