12

An earlier question resulted in some ideas on how to check whether your Git repo contains a dirty index or untracked files. The answer I adopted from that discussion was the following:

#!/bin/sh
exit $(git status --porcelain | wc -l)

The idea behind that answer was to emulate what the programmer would do: run git status and then examine the output.

Unfortunately git status --porcelain and git status do not do exactly the same thing. In particular, git status will report unpushed changes, while git status --porcelain will not. Here is an example

[jarmo@localhost math-hl]$ git status --porcelain
[jarmo@localhost math-hl]$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)
#
nothing to commit, working directory clean

So my question is: what do I need to add to the original script to also identify when the repo has unpushed changes? In particular, would this be a correct approach?

#!/bin/bash
if [ $(git status --porcelain | wc -l) != "0" \
        -o $(git log @{u}.. | wc -l) != "0" ];  then
        echo "local repo is not clean"

Would it be ok, in the long run, to rely on git log, or should I use a "plumbing" command instead?

Community
  • 1
  • 1
user2851270
  • 151
  • 1
  • 1
  • 5

2 Answers2

6

The idea in git scripts is to always use:

See "What does the term porcelain mean in Git?".
As I explain, the --porcelain option is, unfortunately (because its naming is confusing), the "plumbing" way to get a status, that is the "reliable" way, meaning its format won't change over time, which is why it is the recommended command for scripting.

For git log, it is better to use git rev-list:

git rev-list HEAD@{upstream}..HEAD

See "How to know if git repository has changes that have not been synchronized with server (origin)?"

Sled
  • 18,541
  • 27
  • 119
  • 168
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Yep, git rev-list seems to work pretty well. In order to also observe unpulled changes, I needed to add a corresponding "git rev-list HEAD..HEAD@{upstream}" Thanks. – user2851270 Oct 15 '13 at 08:52
3

TLDR;

git status --branch --porcelain
           ^^^^^^^^

Note: git status --porcelain has just been made a bit more reliable with commit 7a76c28, for git 1.9.2 (April 2014), by Matthieu Moy moy)

disable translation when --porcelain is used

"git status --branch --porcelain" displays the status of the branch (ahead, behind, gone), and used gettext to translate the string.

Use hardcoded strings when --porcelain is used, but keep the gettext translation for "git status --short" which is essentially the same, but meant to be read by a human.

That means git status --porcelain keep displaying a different result than git status, this time because of the lack of translation.
But that output is now always the same (independent of the LOCALE used for the translation, since said translation is now deactivated by the --porcelain option)


And git status --porcelain is improved again in Git 2.13 (Q2 2017)

"git status --porcelain" is supposed to give a stable output, but a few strings were left as translatable by mistake.

See commit b9e2bc5 (14 Mar 2017) by Michael J Gruber (mjg).
(Merged by Junio C Hamano -- gitster -- in commit 58e9773, 17 Mar 2017)

Make sure that the remaining two strings (initial commit, detached head) are stable, too.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thanks for the answer. Is `git status --short` considered "'stable"? Or is there are way `git status --porcelain` can give relative URLs like git status does? Thanks. – Mosh Feu Sep 09 '20 at 04:37
  • @MoshFeu It is stable, but not meant to be used in scripts. – VonC Sep 09 '20 at 04:41
  • So what can I use in script in order to get `git status` relative paths? And what do you mean by `not meant to be used in scripts`? – Mosh Feu Sep 09 '20 at 04:50
  • @MoshFeu I mean not meant to be parsed, as I detailed in https://stackoverflow.com/a/6978402/6309. What is missing with `git status --porcelain` in your case? – VonC Sep 09 '20 at 05:45
  • If the terminal is in a subfolder (.e.g `myFolder`). In `status -s` the url is relative to the file `../myFile` while `status --porcelain` is relative to the repo root `myFolder/myFile`. I need it for `git add` which accepts the relative-to-file format. I just found `status --porcelain=version`. In `v2` the url is relative-to-file. But now I'm trying to understand what the rest of data means (permission, sha etc.) and if I can understand from it if the file staged or not. – Mosh Feu Sep 09 '20 at 08:30
  • @MoshFeu That would be better asked in a separate question, with more details o what you see and what you expect. – VonC Sep 09 '20 at 08:33
  • This answer contains the answer to the question: `--branch` is what to add. I would recommend an edit to emphasize that aspect. This was very helpful to me. – Eric Allen Jan 13 '23 at 13:40
  • @EricAllen Thank you for your feedback. I have edited the answer accordingly. Don't hesitate to propose another edit and improve this answer. – VonC Jan 13 '23 at 20:54