I read over various other SO posts and Google search results that git status --porcelain
is not really the command you want to be relying on if you are parsing out the current git branch status programmatically. I was eventually pointed to rev-parse
, diff-index
, and diff-files
commands for doing this - however, the method I'm currently using is a little buggy, particularly on branches other than master. Themes like Bureau for oh-my-zsh seem to be using git status --porcelain
, which I stated above was not recommended by the Git community. So what's the proper way to read in such branch statuses as these?
Code segment from the Bureau Oh-My-ZSH theme so that it's clear what behaviour I'm trying to reproduce.
bureau_git_status () {
_INDEX=$(command git status --porcelain -b 2> /dev/null)
_STATUS=""
if $(echo "$_INDEX" | grep '^[AMRD]. ' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_STAGED"
fi
if $(echo "$_INDEX" | grep '^.[MTD] ' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_UNSTAGED"
fi
if $(echo "$_INDEX" | command grep -E '^\?\? ' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_UNTRACKED"
fi
if $(echo "$_INDEX" | grep '^UU ' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_UNMERGED"
fi
if $(command git rev-parse --verify refs/stash >/dev/null 2>&1); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_STASHED"
fi
if $(echo "$_INDEX" | grep '^## .*ahead' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_AHEAD"
fi
if $(echo "$_INDEX" | grep '^## .*behind' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_BEHIND"
fi
if $(echo "$_INDEX" | grep '^## .*diverged' &> /dev/null); then
_STATUS="$_STATUS$ZSH_THEME_GIT_PROMPT_DIVERGED"
fi
echo $_STATUS
}
I'm eventually going to support all of the behavior above, by here is my start on that and the basic commands I'm currently using to do things (sorry about the fact it's Haskell, hopefully that doesn't prevent anyone from getting the gist of what the code is doing - no pun intended).
hasCommitsToPush :: IO (Maybe Bool)
hasCommitsToPush = do
latestCommits <- liftM (fmap $ deleteNulls . splitOnNewLine) $ parseProcessResponse gitRemoteRefDiff
case latestCommits
of Nothing -> return Nothing
Just [] -> return $ Just False
Just [_] -> return $ Just True -- This case is for a new repository with the first commit in local but not yet pushed.
Just [latestRemoteCommit, latestLocalCommit] -> return . Just $ latestRemoteCommit /= latestLocalCommit
_ -> return Nothing
where gitRemoteRefDiff = readProcessWithExitCode "git" ["rev-parse", "@{u}", "HEAD"] []
hasStagedChanges :: IO (Maybe Bool)
hasStagedChanges = liftM (fmap isResponseNull) $ parseProcessResponse gitResponse
where gitResponse = readProcessWithExitCode "git" ["diff-index","--cached","--ignore-submodules","HEAD"] []
hasUnstagedChanges :: IO (Maybe Bool)
hasUnstagedChanges = liftM (fmap isResponseNull) $ parseProcessResponse gitStatus
where gitStatus = readProcessWithExitCode "git" ["diff-files","--ignore-submodules"] []
Edit AndrewC pointed out that --porcelain is described in the docs as being purposed for parsing by scripts. This causes me to ask the question, when should I use rev-parse
vs. --porcelain
??
To check if you're up-to-date with GitHub run git fetch origin before git status and you'll know you're up-to-date.
To check the status, open the git bash, and run the status command on your desired directory. It will run as follows: $ git status.
The git status command displays the state of the working directory and the staging area. It lets you see which changes have been staged, which haven't, and which files aren't being tracked by Git. Status output does not show you any information regarding the committed project history.
Just so there is an official answer:
As in the comments, the docs DO say that the --porcelain flag with Git Status is there to provide parsing for scripts. My source of confusion is that, in general, this is not the role of the porcelain flag, and traditionally, a 'plumbing' command would normally be specified for such a purpose in Git. Thus, in this case, using the --porcelain flag seems to be an accepted way of parsing out the status of Git repositories, but this is an exception to what --porcelain normally means.
More details are covered in the below SO posts that I uncovered while searching around for better explanations. What does git rev-parse do? What does the term "porcelain" mean in Git?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With