首页 > 解决方案 > What bash command can be used to tell if a local git repository is out of sync with its remote

问题描述

Searching in StackOverflow and on Google, I can find lots of items about how to sync, and do everything with git, except I can't find a reliable way using a bash script to tell if my local repository is in sync with its remote. I've tried:

1.

git branch -v |
perl -wlne'
   print "$ENV{reponame} [$1] --> $3 $2"
      if /^..(\S+)\s+([a-f0-9]+)\s+(\[(?:ahead|behind)\s+\d+\])/
' |
while IFS= read -r MOD; do
   printf ' %s\n' "$MOD"  # Replace with code that uses $MOD
done

and,

2.

isInSync=`git remote update>/dev/null; git status -uno | grep -o "is up to date"`
if [ $? -ne 0  ]; then
    echo " $reponame [$br] --> Out of sync with remote at $d"
    ok=false
fi

and have been trying to find a way to use:

  1. git log --oneline | head -n1 | sed # this I don't know.

to try to get the first word in the log file, which is the commit hash of the last commit, and compare it with:

rev=$(git rev-parse --short HEAD)

which is the commit hash of the local repository branch you are in.

The problem with #1 is that it doesn't seem to pick up when the local is out of sync with the remote.

The problem with # 2, is that it causes the local .git/config to get involved and produces odd attempts to access different remote repositories like heroic.

The problem with #3 is that I can't figure out how to get the hash code from the git log and then compare it to the $rev above. It would seem to be the best bet as when I check it on different computers in different states, it seems to convey the right information.

I am writing a bash script that checks a group of git projects and tells me their states, i.e. up to date, untracked files, uncommitted files, and out of sync with the remote.

Help would be appreciated in either suggesting a better way or how to do the extraction of the commit-hash from the log and compare it to the current commit-hash of the local last commit.

标签: bashgitsed

解决方案


As you are seeing, you have to define what you mean by in sync.

A Git repository first and foremost is a way to hold commits. The set of commits in the repository, as found by branch and tag names and other such names, is what is in the repository. The commits are the history.

Most Git repositories that users work with, however, are not "bare". They have a work-tree or working tree into which files can be extracted from any commit, and/or additional files created and/or various files modified and so on. This working area can be "clean" (matches a commit, more or less) or "dirty".

Is a "dirty" repository, with lots of work going on inside it, "in sync" with some other repository, even if both repositories have exactly the same set of commits? Or are these "not in sync"? What if the other repository has a work-tree and it's "dirty" in exactly the same way? That's something you need to define.

(Besides the work-tree, all repositories—even bare ones—have an index as well, which can also be "clean" or "dirty", and perhaps you should factor that in as well.)

A repository can have one or more remotes defined as well. Given a remote name, such as origin, Git can be told: connect to some network URL and obtain new commits from a Git over there, and put them into this repository. That's what your git remote update is doing. How many remotes that contacts—it could get some of them, or all of them, or maybe some are unreachable at the moment—is difficult to answer, as this is all quite configurable.

... [get] the commit hash of the last commit

Each branch name automatically holds the hash ID of the last commit in that branch. There can be more than one "last commit", in other words. Using HEAD is the right way to find the hash ID of the current commit, but this may not be the tip commit of any branch:

rev=$(git rev-parse HEAD)

If HEAD contains the name of an unborn branch, this step will fail. That state is the case in any totally-empty repository (because there are no commits, hence there can be no branch names; branch names are required to name some existing commit). It's also the state after a git checkout --orphan operation, however.

I am writing a bash script that checks a group of git projects and tells me their states, i.e. up to date, untracked files, uncommitted files, and out of sync with the remote.

So, you get to choose how to define each of these things.

In general, I would:

  • Optionally, have each repository contact its main upstream(s), whatever those may be: probably those defined by whatever git remote update does; consider here whether it's good or bad to allow --prune (see also the fetch.prune setting).
  • Check at least the current branch, as reported by git symbolic-ref HEAD: if this command fails, there is no current branch, i.e., we're on a detached HEAD.
  • Check the status as reported by git status --porcelain=v2 or similar, to look at the state of the index and work-tree. Consider checking submodule status here as well; git status may do this for you, or not, depending on settings.
  • Use the current branch's upstream setting, if (a) there is a current branch and (b) it has an upstream. This upstream setting is often the name of a branch in another Git repository. (It can instead be the name of a branch in this repository.) If so, use git rev-list --left-right --count branch...branch@{u} to count the number of commits ahead and/or behind, perhaps after the git remote update with or without --prune.
  • Optionally, check each branch name, keeping in mind that each Git repository has its own branch names and there's no particular reason, other than convenience and convention, to use the same names in two different Git repositories. That is, my dev might not be related to origin/dev, for instance. If my dev goes with origin/develop I probably set the upstream of dev to origin/develop, so consider checking each branch's upstream. Note that git branch -vv does this (and also counts ahead/behind values, unless told not to, and also has extra support for added work-trees now).

Except for current branch and dirtiness (which git status already reports), most of the work is just git remote update -p and git branch -vv, really.


推荐阅读