我正在开发一个 git 插件,我需要知道本地存储库何时changed(可以提交更改)、ahead(可以推送到远程)或behind(可以从远程拉取)使用命令行。
这就是我到目前为止正在做的事情:
可以承诺吗?
如果
git diff-index --name-only --ignore-submodules HEAD --
返回某些内容,
那么是的,有需要提交的更改。可以推吗?
如果
git status -sb
在其输出中包含单词 ahead,那么是的,有
正在致力于推动。可以拉吗?
尚未实施任何措施。
可以提交?部分似乎工作正常。 可以推送吗?只适用于master分支,这是一个很大的问题。
如何安全地检查每个分支上的 git 存储库是否有要提交的更改、提交要推送或需要
git pull
?
供日后参考。从 Git v2.17.0 开始
git status -sb
包含单词behind。 这样就可以直接用来检查拉动情况。
注意:运行
git fetch
之前记得先运行
git status -sb
来自这个答案。
git fetch
。behind_count = $(git rev-list --count HEAD..@{u})
。ahead_count = $(git rev-list --count @{u}..HEAD)
。 (假设您从哪里获取就是您推送到哪里,请参阅 push.default
配置选项)。behind_count
和 ahead_count
都为 0,则当前分支是最新的。behind_count
为 0 并且 ahead_count
大于 0,则当前分支位于前面。behind_count
大于0且ahead_count
为0,则当前分支落后。behind_count
和ahead_count
都大于0,则当前分支分叉。说明:
git rev-list
列出给定提交范围的所有提交。 --count
选项输出将列出多少提交,并抑制所有其他输出。HEAD
命名当前分支。@{u}
指当前分支的本地上游(由branch.<name>.remote
和branch.<name>.merge
配置)。还有@{push}
,通常与@{u}
指向相同。<rev1>..<rev2>
指定提交范围,其中包括可从 访问的提交,但排除可从 访问的提交。当 或 被省略时,它默认为 HEAD。您可以结合使用
git merge-base
和 git rev-parse
来完成此操作。如果 git merge-base <branch> <remote branch>
返回与 git rev-parse <remote branch>
相同,则您的本地分支领先。如果它返回与 git rev-parse <branch>
相同,那么你的本地分支落后了。如果 merge-base
返回的答案与 rev-parse
不同,则分支已分叉,您需要进行合并。
不过,最好在检查分支之前先做一下
git fetch
,否则你关于是否需要拉取的决定将会过时。您还需要验证您检查的每个分支是否都有远程跟踪分支。您可以使用 git for-each-ref --format='%(upstream:short)' refs/heads/<branch>
来做到这一点。该命令将返回 <branch>
的远程跟踪分支,如果没有,则返回空字符串。 SO 上的某个地方有一个不同的版本,如果分支没有远程跟踪分支,它将返回错误,这可能对您的目的更有用。
最后,我在我的 C++11 git-ws 插件中实现了这个。
string currentBranch = run("git rev-parse --abbrev-ref HEAD");
bool canCommit = run("git diff-index --name-only --ignore-submodules HEAD --").empty();
bool canPush = stoi(run("git rev-list HEAD...origin/" + currentBranch + " --ignore-submodules --count")[0]) > 0;
到目前为止似乎有效。
canPull
仍需测试和实施。
说明:
currentBranch
获取控制台输出,是当前分支名称的字符串canCommit
获取控制台是否输出某些内容(当前更改和 HEAD 之间的差异,忽略子模块)canPush
获取 origin/currentBranch
和本地仓库之间的更改计数 - 如果 > 0
,则可以推送本地仓库我制作了 @user1115652 答案的 bash 版本。
function branch_status() {
local a="master" b="origin/master"
local base=$( git merge-base $a $b )
local aref=$( git rev-parse $a )
local bref=$( git rev-parse $b )
if [[ $aref == "$bref" ]]; then
echo up-to-date
elif [[ $aref == "$base" ]]; then
echo behind
elif [[ $bref == "$base" ]]; then
echo ahead
else
echo diverged
fi
}
感谢@Trebor,我只是为此目的拼凑了一个简单的鱼函数:
#! /usr/bin/fish
#
# Echos (to stdout) whether your branch is up-to-date, behind, ahead or diverged from another branch.
# Don't forget to fetch before calling.
#
# @param branch
# @param otherbranch
#
# @echo string up-to-date/behind/ahead/diverged
#
# @example
#
# # if master is ahead of origin/master you can find out like this:
# #
# if test ( branch-status master origin/master ) = ahead
#
# echo "We should push"
#
# end
#
function branch-status
set -l a $argv[ 1 ]
set -l b $argv[ 2 ]
set -l base ( git merge-base $a $b )
set -l aref ( git rev-parse $a )
set -l bref ( git rev-parse $b )
if [ $aref = $bref ]; echo up-to-date
else if [ $aref = $base ]; echo behind
else if [ $bref = $base ]; echo ahead
else ; echo diverged
end
end
我认为这应该在 git 包中配备,例如 'git status -c' 来与远程仓库进行比较,无论它是领先还是落后。