Functions/Get-GitCommit.ps1

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

function Get-GitCommit {
    <#
    .SYNOPSIS
    Gets the sha-1 ID for specific changes in a Git repository.

    .DESCRIPTION
    The `Get-GitCommit` gets all the commits in a repository, from most recent to oldest.

    To get a commit for a specific named revision, e.g. HEAD, a branch, a tag), pass the name to the `Revision` parameter.

    To get the commit of the current checkout, pass `HEAD` to the `Revision` parameter.
    #>

    [CmdletBinding(DefaultParameterSetName = 'CommitFilter')]
    [OutputType([PowerGit.CommitInfo])]
    param(
        [Parameter(ParameterSetName = 'All')]
        [switch]
        # Get all the commits in the repository.
        $All,

        [Parameter(Mandatory, Position = 0, ParameterSetName = 'Lookup')]
        [string]
        # A named revision to get, e.g. `HEAD`, a branch name, tag name, etc.
        # To get the commit of the current checkout, pass `HEAD`.
        $Revision,

        [Parameter(ParameterSetName = 'CommitFilter')]
        [string]
        # The starting commit from which to generate a list of commits. Defaults to `HEAD`.
        $Since = 'HEAD',

        [Parameter(ParameterSetName = 'CommitFilter')]
        [string]
        # The commit and its ancestors which will be` excluded from the returned commit list which starts at `Since`.
        $Until,

        [Parameter(ParameterSetName = 'CommitFilter')]
        [switch]
        # Do not include any merge commits in the generated commit list.
        $NoMerges,

        [switch]
        # Include the patch for each commit.
        $Patch,

        [string]
        # The path to the repository. Defaults to the current directory.
        $RepoRoot
    )

    Set-StrictMode -Version 'Latest'
    Use-CallerPreference -Cmdlet $PSCmdlet -Session $ExecutionContext.SessionState

    $repo = Find-GitRepository -Path $RepoRoot
    if ( -not $repo ) {
        return
    }

    try {
        $commits = if ( $PSCmdlet.ParameterSetName -eq 'All' ) {
            $filter = New-Object -TypeName 'LibGit2Sharp.CommitFilter'
            $filter.IncludeReachableFrom = $repo.Refs
            $repo.Commits.QueryBy($filter)
        } elseif ( $PSCmdlet.ParameterSetName -eq 'Lookup' ) {
            $change = $repo.Lookup($Revision)
            if ( $change ) {
                $change
            } else {
                Write-Error -Message ('Commit ''{0}'' not found in repository ''{1}''.' -f $Revision, $repo.Info.WorkingDirectory) -ErrorAction $ErrorActionPreference
                return
            }
        } elseif ( $PSCmdlet.ParameterSetName -eq 'CommitFilter') {
            $IncludeFromCommit = $repo.Lookup($Since)

            if (-not $IncludeFromCommit) {
                Write-Error -Message ('Commit ''{0}'' not found in repository ''{1}''.' -f $Since, $repo.Info.WorkingDirectory) -ErrorAction $ErrorActionPreference
                return
            }

            $CommitFilter = [LibGit2Sharp.CommitFilter]::new()
            $CommitFilter.IncludeReachableFrom = $IncludeFromCommit.Sha

            if ($Until) {
                $ExcludeFromCommit = $repo.Lookup($Until)
                if (-not $ExcludeFromCommit) {
                    Write-Error -Message ('Commit ''{0}'' not found in repository ''{1}''.' -f $Until, $repo.Info.WorkingDirectory) -ErrorAction $ErrorActionPreference
                    return
                }
                if ($IncludeFromCommit.Sha -eq $ExcludeFromCommit.Sha) {
                    Write-Error -Message ('Commit reference ''{0}'' and ''{1}'' refer to the same commit with hash ''{2}''.' -f $Since, $Until, $IncludeFromCommit.Sha)
                    return
                }
                $CommitFilter.ExcludeReachableFrom = $ExcludeFromCommit.Sha
            }

            $filteredCommits = $repo.Commits.QueryBy($CommitFilter)

            if ($NoMerges) {
                $filteredCommits = $filteredCommits | Where-Object { $_.Parents.Count -le 1 }
            }

            $filteredCommits
        }
        $commits | ForEach-Object {
            [LibGit2Sharp.Patch]$patchObj = $null
            if ($Patch) {
                $parent = [System.Linq.Enumerable]::FirstOrDefault($_.Parents)
                if ($parent) {
                    $patchObj = [PowerGit.Diff]::GetTreePatch($repo, $_, $parent)
                }
            }
            [PowerGit.CommitInfo]::new($_, $patchObj)
        }
    } finally {
        $repo.Dispose()
    }
}