14

I'm developing a Powershell script for create a program release. In order to do it I want to check if the git working tree is clean and there are no uncommitted changes.

I've read this post but it's related to bash.

How can I check from inside a powershell script if the git working tree is clean and there's anything to commit? I don't care about untracked files.

I've tried something like

  $gitOutput = (git status -z) | Out-String
  if ($gitOutput) {
    "output"
  } else {
    "no Output"
  }

The problem is that I print output also when everything is committed but there are some untracked files, that's something that I'd like to avoid. I want to ignore untracked files and check only if all tracked files are committed.

Jepessen
  • 10,380
  • 11
  • 73
  • 124

3 Answers3

24

Use git status --porcelain to get the output as a list that's easy to parse.

Untracked files are prefixed with the status ??, so you can easily filter those out and then check if there are uncommitted changes based on whether there is any output left:

if(git status --porcelain |Where {$_ -match '^\?\?'}){
    # untracked files exist
} 
elseif(git status --porcelain |Where {$_ -notmatch '^\?\?'}) {
    # uncommitted changes
}
else {
    # tree is clean
}
Mathias R. Jessen
  • 135,435
  • 9
  • 130
  • 184
  • This will filter out any lines that **don't** start ?? which means it will report clean when there are tracked changes pending and only report not clean when there are untracked changes - which is not what was required. The regex should be {$_-match '^[^\?\?]'} this will filter out ?? instead. – TheLogicMan Oct 26 '18 at 07:53
  • 1
    @TheLogicMan Thanks, you're right, updated the answer – Mathias R. Jessen Oct 26 '18 at 10:27
  • 3
    I personally simply do `if (-not (git status --porcelain)) { echo "clean!" }`, or the other way around, `if (git status --porcelain) { throw "not clean!" }`. It works because any value will be truthy (changes detected), and no value will be falsy (no changes detected). – Christian Rondeau Apr 04 '19 at 02:57
6

I found one another solution using git status --porcelain.

$ChangedFiles = $(git status --porcelain | Measure-Object | Select-Object -expand Count)
if ($ChangedFiles -gt 0)
{
    Write-Output "Found $ChangedFiles changed files"
}
gvdm
  • 2,614
  • 4
  • 32
  • 64
5

git status --porcelain returns git status in an stable, easy-to-parse format.

In my own testing, without additional flags it returns specifically an empty string if there are no modifications to tracked files and also no untracked files. To ignore untracked files, the flag --untracked-files=no may be added. The simple powershell statements below leverage that to yield booleans $hasEditsToTrackedFiles and $hasEditsToTrackedFilesOrHasUntrackedFiles.

Using the --untracked-files=no flag seems a little simpler and easier to understand than doing a regex match. Possibly --short could be used here in place of --porcelain, but i haven't tested it.

$hasEditsToTrackedFiles                    = !([string]::IsNullOrEmpty($(git status --porcelain --untracked-files=no)))
$hasEditsToTrackedFilesOrHasUntrackedFiles = !([string]::IsNullOrEmpty($(git status --porcelain)))
orion elenzil
  • 3,643
  • 3
  • 31
  • 45
  • Please explain how the code works, and why it is the appropriate solution. We want to educate not just solve the immediate answer. – the Tin Man Jan 19 '20 at 04:39
  • 1
    Please consider adding some explanation or details to your answer. While it might answer the question, just adding a piece of code as an answer, doesn't per say help OP or future community members understand the issue or the proposed solution. – Maxim Jan 19 '20 at 09:35