Functions/Restore-GitItem.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
function Restore-GitItem {
    <#
    .SYNOPSIS
    Restore working tree files.

    .DESCRIPTION
    Restore specified paths in the working tree with some contents from a restore source. If a path is tracked but
    does not exist in the restore source, it will be removed to match the source.

    Use the `Force` switch to remove any uncommitted/unstaged changes during the checkout. Otherwise, the update
    will fail.

    This function implements the `git restore` command.

    .INPUTS
    PSGitHub.PullRequest. You can pipe in the output of PSGitHub's Get-GitHubPullRequest.
    #>


    [CmdletBinding()]
    param(
        # Specifies which git repository to update. Defaults to the current directory.
        [string] $RepoRoot = (Get-Location).ProviderPath,

        # A revision can be a specific commit ID/sha (short or long), branch name, tag name, etc.
        # Go to https://git-scm.com/docs/gitrevisions for full documentation on Git's revision syntax.
        [Parameter(ValueFromPipelineByPropertyName)]
        [Alias('FriendlyName')]
        [Alias('HeadRef')] # PSGitHub.PullRequest
        [Alias('Sha')]
        [string] $Source = 'HEAD',

        [Parameter(Position = 0, Mandatory, ValueFromPipelineByPropertyName, ValueFromRemainingArguments)]
        [Alias('FullName')]
        [ValidateNotNullOrEmpty()]
        [string[]] $Path,

        # Specifying -Staged will only restore the index. Specifying both restores both.
        [Parameter(Mandatory)]
        [switch] $Staged, # TODO

        # Specify the restore location. If neither option is specified, by default the working tree is restored.
        [Parameter(Mandatory)]
        [switch] $Worktree, # TODO

        # Remove any uncommitted changes when checking out/updating to `Revision`.
        [Switch] $Force
    )

    Set-StrictMode -Version 'Latest'

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

    $cancel = $false
    try {
        $checkoutOptions = [LibGit2Sharp.CheckoutOptions]::new()
        $checkoutOptions.OnCheckoutNotify = {
            param([string]$Path, [LibGit2Sharp.CheckoutNotifyFlags]$NotifyFlags)
            Write-Information "$($NotifyFlags): $Path"
            return -not $cancel -and -not $PSCmdlet.Stopping
        }
        $checkoutOptions.OnCheckoutProgress = {
            param([string]$Path, [int]$CompletedSteps, [int]$TotalSteps)
            if ($ProgressPreference -ne 'SilentlyContinue' -and $TotalSteps -ne 0) {
                $progressParams = @{
                    Activity = 'Checking files out'
                }
                if ($TotalSteps -ne 0) {
                    $progressParams.PercentComplete = (($CompletedSteps / $TotalSteps) * 100)
                }
                if ($Path) {
                    $progressParams.Status = $Path
                }
                Write-Progress @progressParams
            }
        }
        if ($Force) {
            $checkoutOptions.CheckoutModifiers = [LibGit2Sharp.CheckoutModifiers]::Force
        }

        # If -Source is not specified, the default restore source for the working tree is the index, and the
        # default restore source for the index is HEAD. When both --staged and --worktree are specified, --source
        # must also be specified.

        if ($Index) {
            $sourceCommit = $repo.Lookup($Source)
            $Path | ForEach-Object {
                [LibGit2Sharp.TreeEntry]$entry = $sourceCommit[$_]
                $repo.Index.Add($entry.Target, $_, $entry.Mode)
            }
        }
        if ($Worktree) {
            # ???
        }
    } finally {
        $cancel = $true
        $repo.Dispose()
    }
}