20

I'm developing a git plug-in, and I need to know when a local repo is changed (can commit changes), ahead (can push to remote) or behind (can pull from remote) using the command line.

This is what I am doing so far:

  • Can commit?

    If git diff-index --name-only --ignore-submodules HEAD -- returns something, then yes, there are changes to commit.

  • Can push?

    If git status -sb contains the word ahead in it's output, then yes, there are commits to push.

  • Can pull?

    Nothing implemented yet.

The can commit? part seems to work properly. Can push? only works for the master branch, and this is a huge problem.

How can I safely check if, on every branch, a git repo has changes to commit, commits to push, or needs a git pull?

4

6 回答 6

24

备查。从 Git v2.17.0 开始

git status -sb

包含后面的单词。因此可以直接用于检查拉动。

注意:记得运行git fetch前运行git status -sb

于 2018-04-26T01:35:26.443 回答
9

您可以使用 和 的组合来执行此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 上的某个地方有一个不同的版本,如果分支没有远程跟踪分支,它将返回错误,这可能对您的目的更有用。

于 2013-07-18T12:42:53.020 回答
7

最后,我在我的 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/ 和本地 repo 之间的更改计数currentBranch- 如果> 0可以推送本地 repo
于 2013-07-22T14:26:12.657 回答
7

这个答案

  1. 做一个提取:git fetch
  2. 获取当前分支落后了多少次提交:behind_count = $(git rev-list --count HEAD..@{u}).
  3. 获取当前分支前面有多少次提交:ahead_count = $(git rev-list --count @{u}..HEAD). (它假设您从哪里获取是您推送到哪里,请参阅push.default配置选项)。
  4. 如果两者behind_countahead_count为 0,则当前分支是最新的。
  5. 如果behind_count为 0 且ahead_count大于 0,则当前分支在前面。
  6. 如果behind_count大于 0 且ahead_count为 0,则当前分支落后。
  7. 如果两者behind_countahead_count大于 0,则当前分支是发散的。

解释:

  • git rev-list列出所有提交范围的提交。--count选项输出将列出多少次提交,并禁止所有其他输出。
  • HEAD命名当前分支。
  • @{u}指当前分支的本地上游(用branch.<name>.remoteand配置branch.<name>.merge)。还有@{push},它通常是分到相同的@{u}
  • <rev1>..<rev2>指定提交范围,其中包括可从 到达的提交,但不包括可从 到达的提交。如果省略或省略,则默认为 HEAD。
于 2021-06-30T02:49:13.290 回答
2

感谢@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
于 2017-07-30T22:52:38.733 回答
2

我制作了@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
}
于 2020-06-28T00:25:34.030 回答