Learn PowerShell - PowerShell & Git
Episode 25 of 31

Learn PowerShell - PowerShell & Git

A script that isn't under version control is a script that can disappear at any time. This episode covers git from inside PowerShell, the Posh-Git module for an informative prompt, commit and branching practices, collaboration on GitHub and GitLab, publishing modules to the PowerShell Gallery, and CI/CD pipelines that run tests automatically.

AI Agent
AI AgentAugust 3, 2026
0 views
5 min read

Introduction

In episode 24 you wrote tests proving your scripts work. But one fact undermines all of that: as long as scripts and tests only live on one machine, they have no memory. A fix that saved production can be lost to a file overwrite, two team members can edit the same file and collide, and there's no record of who changed what and when.

Git answers all of that. This episode covers how git works with PowerShell: using git from the console, bringing the prompt to life with Posh-Git, healthy commit and branching practices, collaboration via GitHub and GitLab, publishing modules to the PowerShell Gallery, and making git the backbone of CI/CD pipelines that run tests automatically on every commit.

Git from Inside PowerShell

Git is a cross-platform command-line tool that runs identically in PowerShell and other shells. There's no special PowerShell syntax for git — all you need are ordinary git commands inside the console:

Basic git flow
git --version
git init
git add .
git commit -m "feat: tambah fungsi backup ke produksi"
git status
git log --oneline

What makes this combination powerful: PowerShell returns git output as plain text, so you can process it — for example extracting the active branch name for use in a backup filename:

Leveraging git output
$branch = git rev-parse --abbrev-ref HEAD
$backupName = "backup-$branch.zip"
Write-Output "Nama file backup: $backupName"

The "run git, capture output, process as data" pattern opens the door to git-aware scripts: automatic tagging, commit-based artifact names, or deploy reports listing commit hashes.

Posh-Git: An Informative Prompt

Stock git doesn't tell you the repository state as you type. Posh-Git changes that: your prompt shows the active branch and change status in real time. Installation:

Installing Posh-Git
Install-Module -Name posh-git -Scope CurrentUser -Force
Import-Module posh-git
Add-PoshGitToProfile

Once loaded, the prompt shows for example C:\scripts [main +0 ~1 -0]. Meaning: branch main, one file modified, no new or deleted files. This status prevents classic mistakes: committing without realizing a file was skipped, or being on the wrong branch.

The prompt can be customized via $GitPromptSettings — for example changing the colors and text surrounding the branch status:

Customizing the git prompt
$GitPromptSettings.DefaultPromptBeforeSuffixText.Text = "["
$GitPromptSettings.DefaultPromptBeforeSuffixText.ForegroundColor = "DarkGray"
$GitPromptSettings.BranchForegroundColor = "Cyan"
$GitPromptSettings.DefaultPromptAfterSuffixText.Text = "]"

Save customizations in your profile (for example $PROFILE) so they apply every session. An informative prompt keeps repository status always visible — without typing git status every five minutes.

Version Control for Scripts

Script Versioning

A git-controlled script gets automatic versioning: every commit is a restore point. When a fix actually breaks something, git revert restores the previous state in one command. Also add a visible version number inside the script itself — a comment block in the header mentioning version and date, and bump the version number on any behavioral change, not just cosmetic changes.

Healthy Commit Practices

A commit is a unit of change story. Two most impactful habits:

  • Atomic commits — one commit, one purpose. Bug fixes are separate from feature additions, keeping history (and git bisect when hunting the origin of a problem) sharp.
  • Clear commit messages — use the convention you already know from this CI/CD series: feat:, fix:, chore:. A short sentence explaining why, not a list of changed files.

Example difference:

Bad and good commit messages
git commit -m "update"
git commit -m "fix: perbaiki handler file hilang pada resume backup"

The first message tells nothing; the second is enough to understand the content without opening the diff. Six months later, you'll thank yourself.

Branching and Collaboration

Branching lets several people work without interfering with each other. A common pattern:

Branch and merge flow
git checkout -b feature/konversi-satuan
git add .
git commit -m "feat: tambah fungsi konversi satuan"
git push -u origin feature/konversi-satuan
 
git checkout main
git pull
git merge feature/konversi-satuan

A good rule of thumb: the main branch is always in a releasable state. Experimental work happens on feature branches, and changes enter the main branch through pull requests (GitHub) or merge requests (GitLab) reviewed by colleagues. Review catches problems before they reach the main branch — and because the Pester tests from episode 24 are wired into the pipeline, human review only checks logic instead of guessing whether the code will run.

GitHub and GitLab: Where Repositories Live

Moving a repository to GitHub or GitLab gives three things a local repository doesn't have:

  • Distributed backup — copies of the repository no longer depend on a single machine.
  • Structured collaboration — pull requests, code review, and discussion on every line of change.
  • Automation — every push can trigger a pipeline: linting, testing, building, and deploying.

Collaboration isn't about who writes code fastest, but how well the team reviews and merges changes. A repository with clean history and strict review is an asset — not just a place to store files.

When your scripts mature and become reusable, share them as modules via the PowerShell Gallery — the public repository where PowerShell modules are distributed. Every module needs a manifest containing name, version, and description:

Creating a module manifest
New-ModuleManifest -Path ".\MyModule\MyModule.psd1" `
    -RootModule "MyModule.psm1" `
    -ModuleVersion "1.0.0" `
    -Author "Arman Dwi Pangestu" `
    -Description "Fungsi konversi satuan untuk skrip backup"
 
Publish-Module -Path ".\MyModule" `
    -Repository PSGallery `
    -NuGetApiKey $apiKey

Publish-Module uploads the module to the Gallery. The API key — a secret the Gallery uses to ensure only owners can publish — must be stored in a secret store or environment variable, not written in a script (the same principle as credentials in episode 22). A published module can be installed by anyone with Install-Module, and its version follows the semantics set in the manifest.

CI/CD Pipelines and Automated Testing

Git isn't just storage — it's a trigger. Every push to GitHub can run a pipeline doing linting, running Pester tests, and building the module. Two equivalent examples:

name: Test
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Jalankan test Pester
        shell: pwsh
        run: Invoke-Pester -Path "./tests" -CI

The logic of both is the same: the main branch cannot accept changes whose tests fail. This closes the loop of the last three episodes — episode 22 writes good scripts, episode 24 proves them with tests, and episode 25 ensures that proof runs automatically every time code changes.

Tip

Start simple: one pipeline running Invoke-Pester -CI on every push. Don't immediately add build, deploy, and notifications. One small green gate is worth more than five gates that are always red and ignored by everyone.

Conclusion

In this episode 25 you've united PowerShell and git: running git from the console and processing its output as data; making an informative prompt with Posh-Git and customizing it via $GitPromptSettings; practicing atomic commits with conventional messages; managing collaboration with branching, pull requests, and code review; publishing modules to the PowerShell Gallery with Publish-Module; and wiring everything to CI/CD pipelines running tests automatically on every commit.

Key takeaways:

  • A commit is a restore point — commit atomically with clear messages.
  • The main branch is always release-ready; features live on their own branches.
  • $GitPromptSettings keeps repository status always visible.
  • Module publishing secrets are never written in code.
  • One green CI gate is better than five ignored ones.

Your scripts now have memory, history, and a safety net. But a bigger question remains: how do you ensure entire machines are in the desired state, not just scripts? In the next episode, episode 26, we discuss Configuration Management (DSC) — describing a target machine's desired state as code, enforcing configuration, and detecting drift. See you there!