Why shouldn't I use this porcelain Git command to tell if my repo has any changes?

Viewed 924

I've hacked together an updater for my app, so that people with little to no coding skill can install, run, and update the app on their own machines.

Here is an example of an updater, written for Windows command prompt:

@echo off
for /f %%i in ('call git status --porcelain') do set stash=%%i
if not [%stash%] == [] (
  echo Stashing local changes...
  call git add .
  call git stash -q
)
echo Updating App...
call git pull origin master
if not [%stash%] == [] (
  echo Restoring local changes...
  call git stash apply -q
)
echo Updating Dependencies...
call npm update
echo Done
pause

As you can see, I'm calling git status --porcelain to tell whether or not an app has local changes which need to be stashed before pulling the remote master branch.

This command will return nothing if the working directory is clean, but will always return something if there are local changes, tracked or otherwise.

I've read from other SO posts that it's bad to use porcelain commands to do plumbing work in git, but in this case, it is working well for me, and I don't see why the git status --porcelain command would ever return something when there is a clean working directory.

So my questions are: Is it wrong to use porcelain for this specific use-case? And if so, why?

Bonus: What would be a better way to go about this?

2 Answers

Actually, there's nothing wrong in using git status with --porcelain switch. Moreover, when you peep into the docs you will see that you used the command exactly in the way it was designed:

Give the output in an easy-to-parse format for scripts. This is similar to the short output, but will remain stable across Git versions and regardless of user configuration. See below for details.

Another option here is to use -s switch (git status -s) which will also return easy-to-parse output but it may not be guaranteed to work in the same way for future versions.

I don't find this particular usage of git status incorrect in any way. It does the job, it does it reliably and in easy to understand way.

An equivalent command with porcelain may e.g. be:

git ls-files --exclude-per-directory=.gitignore --exclude-from=.git/info/exclude --others --modified -t

But from git ls-files docs on -t switch:

This feature is semi-deprecated. For scripting purpose, git-status(1)--porcelain and git-diff-files(1)--name-status are almost always superior alternatives, and users should look at git-status(1)--short or git-diff(1)--name-status for more user-friendly alternatives.

So you see that even git manual advises to use git status alternative.

git status --porcelain is not a porcelain command. The name of the option is misleading, but it actually means "give an easy to parse and stable output, suitable for use in porcelain scripts". So, --porcelain means "act as a plumbing command".

As already said in the other answer, there's nothing wrong with what you do, --porcelain is meant to be used the way you do.

Related