bash - 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:
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.
解决方案
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 thefetch.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 thegit 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 toorigin/dev
, for instance. If mydev
goes withorigin/develop
I probably set the upstream ofdev
toorigin/develop
, so consider checking each branch's upstream. Note thatgit 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.
推荐阅读
- git - 就分支而言,m/master 在 git 中是什么意思?
- shapes - Halcon - 获得分支分数
- bash - 尝试使用 awk 命令删除一些字符串
- java - 找不到基本名称的捆绑包警告
- javascript - Chrome 扩展:如何从活动选项卡中的控制台获取错误
- r - 如何估计函数中的参数?
- java - Java多维多类型数组(Map/List/Collection)?
- c++ - 如果匹配(从头开始),则删除字符串的第一部分的最简单方法?(使用升压是可以的)
- c++ - 我如何编写类似 std::variant 的开关之类的代码?
- r - R 4.0 使用 Rtools/ 而不是 rtools40/