Functions/Merge-HgChangeset.ps1


function Merge-HgChangeset
{
    <#
    .SYNOPSIS
    Merges a revision into the current working directory.
     
    .DESCRIPTION
    Invokes Mercurial's merge command to merge a revision into the current working directory.
 
    If you are running this command interactively, *do not* pipe the output of this command anywhere, or capture it in anyway. If you do, you will hide Mercurial's prompts and the function/Mercurial will hang waiting for user input. Instead, to get the state/result of a merge, call `Get-HgMergeResult` *after* this function completes.
     
    ALIASES
      mghgc, hgmerge
 
    .OUTPUTS
    PsHg.MergeResult
 
    .LINK
    Get-HgMergeResult
     
    .EXAMPLE
    Merge-HgChangeset -Revision StableBranch
     
    Merges `StableBranch` into the current working directory.
     
    .EXAMPLE
    Merge-HgChangeset -Revision StableBranch -RepoRoot C:\Projects\psHg
     
    Merges `StableBranch` into the repository at `C:\Projects\psHg`.
     
    .EXAMPLE
    Merge-HgChangeset -Revision STableBranch -MergeTool 'internal:fail'
     
    Merges `StableBranch` into the current working directory, using Mercurial's internal `fail` merge tool to fail any merges that take place.
    #>

   [CmdletBinding(DefaultParameterSetName='NormalMerge',SupportsShouldProcess=$true)]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        # The revision to merge. Can be a branch, tag, node, ID, or revset query.
        $Revision,
        
        [Switch]
        # Perform a non-interactive merge, i.e. fail if there are any conflicts.
        $NonInteractive,
        
        [Parameter(ParameterSetName='WithTool')]
        # The merge tool to use when merging. Passed as the value to the merge command's `--tool` parameter.
        $MergeTool,
        
        [string]
        # The path to the repository to merge. Defaults to the current directory.
        $RepoRoot = (Resolve-HgRoot .)
    )

    Set-StrictMode -Version 'Latest'
    
    if( -not $RepoRoot )
    {
        return
    }
    
    if( -not (Test-HgRevision -Revision $Revision -RepoRoot $RepoRoot) )
    {
        Write-Error "Revision '$Revision' not found."
        return
    }
    
    $mergeToolArgName = ''
    $mergeToolArgValue = ''
    if( $pscmdlet.ParameterSetName -eq 'WithTool' )
    {    
        $mergeToolArgName = '--tool'
        $mergeToolArgValue = $MergeTool
    }
    elseif( $NonInteractive )
    {
        $mergeToolArgName = '--tool'
        $mergeToolArgValue = 'internal:fail'
    }

    $preMergeParent = Get-HgParent -RepoRoot $RepoRoot

    $argumentList = ('merge',$mergeToolArgName,$mergeToolArgValue,'-r',$Revision,'-R',$RepoRoot) | 
                        Where-Object { $_ }
        
    if( $NonInteractive )
    {
        $argumentList += '--noninteractive'
    }

    $Script:PsHg? = $true
    if( $pscmdlet.ShouldProcess( $RepoRoot, "merge $Revision" ) )
    {
        & 'hg.exe' $argumentList
        $hgExitCode = $LASTEXITCODE
        Write-Verbose -Message ('hg merge exit code: {0}' -f $hgExitCode)
        $Script:PsHg? = ($hgExitCode -eq 0)
        if( $hgExitCode -eq 1 -and $NonInteractive )
        {
            if( $preMergeParent )
            {
                Write-Error ('Reverting non-interactive merge because there were merge conflicts.')
                Update-HgRepository -RepoRoot $RepoRoot -Revision $preMergeParent.Node -Clean -NonInteractive:$NonInteractive
                $Script:PsHg? = $false  # To report that this merge failed.
            }
            else
            {
                Write-Error ('Unable to revert non-interactive merge: I don''t know what my parent revision was before the merge.')
            }
        }
    }
}

Set-Alias -Name 'Merge-HgRevision' -Value 'Merge-HgChangeset'
Set-Alias -Name 'hgmerge' -Value 'Merge-HgChangeset'
Set-Alias -Name 'mghgc' -Value 'Merge-HgChangeset'