I read a few other SO posts and google search results that git status --porcelain is not really the command you want to rely on if you programmatically infer the current status of the git branch. In the end, I pointed out the rev-parse , diff-index and diff-files commands for this, but the method I'm currently using is a bit buggy, especially on branches other than master. Topics such as Bureau for oh-my-zsh seem to use git status --porcelain , which I mentioned above was not recommended by the git community. So what is the correct way to read branches like these in the statuses?
A segment of code from the Oh-My-ZSH theme in the Bureau so that he can understand what behavior 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 }
In the end, I will support all of the above, here is my beginning on this and the basic commands that I now use to do something (sorry for the fact that Haskell, I hope this does not bother anyone from getting the essence of what the code does - 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"] []
Change AndrewC noted that -porcelain is described in documents as intended for parsing by scripts. This makes me ask when to use rev-parse vs. --porcelain ??
git parsing haskell
josiah
source share