bhylu.com

Advertisements

Git Branches and Pull Requests

A pull request asks collaborators to review and integrate a proposed branch on a hosting service. Creating or pushing a branch does not itself create that review record.

How it works

The local lab prepares the Git side of a proposal: create a branch, make one focused change, inspect the diff against main and push only that branch to the local origin. A real pull request would additionally name a target branch, describe the behavior and validation, receive review and satisfy the host’s checks. Those hosted actions are not performed here.

Run the disposable lab

Use Windows PowerShell 5.1 or later and Git 2.28 or later. The reviewed CLI is Git for Windows 2.53.0.windows.2. These are PowerShell examples, not Git Bash commands. Save the download as pull-requests.ps1 in a separate empty learning folder and run it in a separate process: powershell -NoProfile -ExecutionPolicy Bypass -File .\pull-requests.ps1. The execution-policy option applies to that process, not your machine policy.

The script creates bhylu-git-pull-requests and refuses an existing folder. It supplies two fictional seed files and repository-local settings, then runs the lesson commands. The literal separator is quoted as '--' so PowerShell passes it through the guard. A guard function named git calls the real CLI and stops on unexpected failures; Expect-GitFailure checks deliberately refused operations. Child-process configuration isolates your personal Git settings. File transports are allowed only for owned local remotes; internet transports are disabled in this lab. No hosting account, Apache or MySQL service is required. There is no Git playground. Leave the generated folder for inspection; choose another empty parent to run again.

Test boundary: Git preparation is executed locally; no hosted pull request is created.

Download the complete pull-requests.ps1 lab

Example

pull-requests.ps1

# Bhylu Git lab: Branches and Pull Requests
# Run in a separate PowerShell process, in an empty learning folder.
# Existing lab folders are refused; nothing is pushed to an internet host.
$ErrorActionPreference = 'Stop'
$script:GitExe = (Get-Command git -CommandType Application | Select-Object -First 1).Source
$script:LabRoot = Join-Path (Get-Location) 'bhylu-git-pull-requests'
if (Test-Path -LiteralPath $script:LabRoot) { throw 'Lab folder already exists. Choose another empty parent folder.' }
New-Item -ItemType Directory -Path $script:LabRoot | Out-Null
$env:GIT_CONFIG_NOSYSTEM = '1'
$env:GIT_CONFIG_GLOBAL = Join-Path $script:LabRoot 'empty-global-config'
[IO.File]::WriteAllText($env:GIT_CONFIG_GLOBAL, '')
$env:GIT_TERMINAL_PROMPT = '0'
$env:GIT_EDITOR = 'true'
$env:GIT_SEQUENCE_EDITOR = 'true'
$env:GIT_AUTHOR_DATE = '2026-01-10T10:00:00+00:00'
$env:GIT_COMMITTER_DATE = $env:GIT_AUTHOR_DATE
function git {
    & $script:GitExe -c protocol.allow=never -c protocol.file.allow=always @args
    if ($LASTEXITCODE -ne 0) { throw "Git exited with code $LASTEXITCODE" }
}
function Expect-GitFailure {
    & $script:GitExe -c protocol.allow=never -c protocol.file.allow=always @args
    if ($LASTEXITCODE -eq 0) { throw 'Expected Git to refuse this operation' }
}
function Assert-Equal($Actual, $Expected) {
    if ((($Actual | Out-String).Trim()) -cne (($Expected | Out-String).Trim())) { throw "Expected [$Expected], got [$Actual]" }
}
function Write-LabFile([string]$Name, [string]$Text) {
    $target = [IO.Path]::GetFullPath((Join-Path (Get-Location) $Name))
    if (!$target.StartsWith($script:LabRoot + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Path outside lab' }
    [IO.Directory]::CreateDirectory([IO.Path]::GetDirectoryName($target)) | Out-Null
    [IO.File]::WriteAllText($target, ($Text.Replace('\n', "`n") + "`n"), (New-Object Text.UTF8Encoding($false)))
}
function New-LabRepo([string]$Name) {
    New-Item -ItemType Directory -Path $Name | Out-Null
    Push-Location $Name
    try {
        git init --initial-branch=main
        git config --local user.name 'Repair Lab'
        git config --local user.email 'repair@example.invalid'
        git config --local core.autocrlf false
        git config --local commit.gpgSign false
        git config --local tag.gpgSign false
        git config --local core.hooksPath (Join-Path $script:LabRoot 'empty-hooks')
        Write-LabFile 'notes.md' 'Inspect hinge'
        Write-LabFile 'tasks.txt' 'desk=open'
        git add '--' notes.md tasks.txt
        git commit -m 'Record initial repair plan'
    } finally { Pop-Location }
}
Push-Location $script:LabRoot
try {
    New-LabRepo 'desk'
    Set-Location desk
    git init --bare --initial-branch=main ../shared.git
    git remote add origin ../shared.git
    git push -u origin main
    git switch -c collection-reminder
    Write-LabFile 'collection.txt' 'Bring the item label'
    git add '--' 'collection.txt'
    git commit -m 'Clarify collection reminder'
    Assert-Equal (git diff --name-only main...HEAD) @('collection.txt')
    git push -u origin collection-reminder
    Assert-Equal (git --git-dir=../shared.git show collection-reminder:collection.txt) @('Bring the item label')
    Assert-Equal (git --git-dir=../shared.git ls-tree --name-only main '--' collection.txt) @('')
    Write-Output 'Verified: pull-requests'
} finally { Pop-Location }

Focus on the lesson commands

This excerpt omits the seed repository and guard helpers. Use the complete download to run it.

Lesson excerpt

git init --bare --initial-branch=main ../shared.git
git remote add origin ../shared.git
git push -u origin main
git switch -c collection-reminder
Write-LabFile 'collection.txt' 'Bring the item label'
git add '--' 'collection.txt'
git commit -m 'Clarify collection reminder'
Assert-Equal (git diff --name-only main...HEAD) @('collection.txt')
git push -u origin collection-reminder
Assert-Equal (git --git-dir=../shared.git show collection-reminder:collection.txt) @('Bring the item label')
Assert-Equal (git --git-dir=../shared.git ls-tree --name-only main '--' collection.txt) @('')

Expected result

The proposed branch contains the reminder; remote main does not contain it yet.

The complete script ends with Verified: pull-requests only after its checks pass. Object IDs, temporary paths and progress output can differ.

The triple-dot diff compares the proposed branch with its merge base against main. Review that actual scope before opening a request. During discussion, new commits may alter what is being reviewed, so approvals and check results must correspond to the relevant tip under the team’s policy.

Official reference

Advertisements