bash 检查 Git 中是否需要 pull

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3258243/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:28:21  来源:igfitidea点击:

Check if pull needed in Git

gitbashshell

提问by takeshin

How do I check whether the remote repository has changed and I need to pull?

如何检查远程存储库是否已更改并且我需要拉取?

Now I use this simple script:

现在我使用这个简单的脚本:

git pull --dry-run | grep -q -v 'Already up-to-date.' && changed=1

But it is rather heavy.

但是比较重。

Is there a better way? The ideal solution would check all the remote branches, and return names of the changed branches and the number of new commits in each one.

有没有更好的办法?理想的解决方案是检查所有远程分支,并返回更改分支的名称以及每个分支中新提交的数量。

回答by Neil Mayhew

First use git remote update, to bring your remote refs up to date. Then you can do one of several things, such as:

首先使用git remote update, 使您的远程引用保持最新。然后,您可以执行以下几项操作之一,例如:

  1. git status -unowill tell you whether the branch you are tracking is ahead, behind or has diverged. If it says nothing, the local and remote are the same.

  2. git show-branch *masterwill show you the commits in all of the branches whose names end in 'master' (eg masterand origin/master).

  1. git status -uno会告诉您正在跟踪的分支是在前面、后面还是已经发散。如果它什么也没说,本地和远程是一样的。

  2. git show-branch *master将向您显示名称以“master”结尾的所有分支中的提交(例如masterorigin/master)。

If you use -vwith git remote update(git remote -v update) you can see which branches got updated, so you don't really need any further commands.

如果您使用-vwith git remote update( git remote -v update),您可以看到哪些分支已更新,因此您实际上不需要任何进一步的命令。

However, it looks like you want to do this in a script or program and end up with a true/false value. If so, there are ways to check the relationship between your current HEADcommit and the head of the branch you're tracking, although since there are four possible outcomes you can't reduce it to a yes/no answer. However, if you're prepared to do a pull --rebasethen you can treat "local is behind" and "local has diverged" as "need to pull", and the other two as "don't need to pull".

但是,看起来您想在脚本或程序中执行此操作并以真/假值结束。如果是这样,有一些方法可以检查您当前的HEAD提交与您正在跟踪的分支的负责人之间的关系,尽管由于有四种可能的结果,您不能将其简化为是/否答案。但是,如果您准备做一个,pull --rebase那么您可以将“本地落后”和“本地已发散”视为“需要拉动”,而将其他两个视为“不需要拉动”。

You can get the commit id of any ref using git rev-parse <ref>, so you can do this for masterand origin/masterand compare them. If they're equal, the branches are the same. If they're unequal, you want to know which is ahead of the other. Using git merge-base master origin/masterwill tell you the common ancestor of both branches, and if they haven't diverged this will be the same as one or the other. If you get three different ids, the branches have diverged.

您可以使用 获取任何 ref 的提交 ID git rev-parse <ref>,因此您可以对masterorigin/master执行此操作并比较它们。如果它们相等,则分支相同。如果它们不相等,您想知道哪个在另一个之前。Usinggit merge-base master origin/master会告诉你两个分支的共同祖先,如果它们没有分歧,这将与一个或另一个相同。如果您获得三个不同的 id,则分支已分叉。

To do this properly, eg in a script, you need to be able to refer to the current branch, and the remote branch it's tracking. The bash prompt-setting function in /etc/bash_completion.dhas some useful code for getting branch names. However, you probably don't actually need to get the names. Git has some neat shorthands for referring to branches and commits (as documented in git rev-parse --help). In particular, you can use @for the current branch (assuming you're not in a detached-head state) and @{u}for its upstream branch (eg origin/master). So git merge-base @ @{u}will return the (hash of the) commit at which the current branch and its upstream diverge and git rev-parse @and git rev-parse @{u}will give you the hashes of the two tips. This can be summarized in the following script:

要正确执行此操作,例如在脚本中,您需要能够引用当前分支以及它正在跟踪的远程分支。中的 bash 提示设置函数/etc/bash_completion.d有一些用于获取分支名称的有用代码。但是,您实际上可能并不需要获取名称。Git 有一些简洁的速记来引用分支和提交(如 中所述git rev-parse --help)。特别是,您可以将其@用于当前分支(假设您未处于分离头状态)@{u}及其上游分支(例如origin/master)。Sogit merge-base @ @{u}将返回当前分支及其上游分支的(哈希)提交,git rev-parse @git rev-parse @{u}为您提供两个提示的哈希。这可以总结为以下脚本:

#!/bin/sh

UPSTREAM=${1:-'@{u}'}
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse "$UPSTREAM")
BASE=$(git merge-base @ "$UPSTREAM")

if [ $LOCAL = $REMOTE ]; then
    echo "Up-to-date"
elif [ $LOCAL = $BASE ]; then
    echo "Need to pull"
elif [ $REMOTE = $BASE ]; then
    echo "Need to push"
else
    echo "Diverged"
fi

Note:older versions of git didn't allow @on its own, so you may have to use @{0}instead.

注意:旧版本的 git 不允许单独@使用,因此您可能必须@{0}改用。

The line UPSTREAM=${1:-'@{u}'}allows you optionally to pass an upstream branch explicitly, in case you want to check against a different remote branch than the one configured for the current branch. This would typically be of the form remotename/branchname. If no parameter is given, the value defaults to @{u}.

该行UPSTREAM=${1:-'@{u}'}允许您选择性地明确传递上游分支,以防您想检查与当前分支配置的远程分支不同的远程分支。这通常是remotename/branchname的形式。如果没有给出参数,则该值默认为@{u}

The script assumes that you've done a git fetchor git remote updatefirst, to bring the tracking branches up to date. I didn't build this into the script because it's more flexible to be able to do the fetching and the comparing as separate operations, for example if you want to compare without fetching because you already fetched recently.

该脚本假定您已完成 agit fetchgit remote updatefirst,以使跟踪分支保持最新状态。我没有将它构建到脚本中,因为能够将获取和比较作为单独的操作进行更灵活,例如,如果您想在不获取的情况下进行比较,因为您最近已经获取了。

回答by PlagueHammer

If you have an upstream branch

如果你有一个上游分支

git fetch <remote>
git status

If you don't have an upstream branch

如果你没有上游分支

Compare the two branches:

比较两个分支:

git fetch <remote>
git log <local_branch_name>..<remote_branch_name> --oneline

For example:

例如:

git fetch origin

# See if there are any incoming changes
git log HEAD..origin/master --oneline

(I'm assuming origin/masteris your remote tracking branch)

(我假设origin/master是您的远程跟踪分支)

If any commits are listed in the output above, then you have incoming changes -- you need to merge. If no commits are listed by git logthen there is nothing to merge.

如果上面的输出中列出了任何提交,那么您有传入的更改——您需要合并。如果没有列出提交,git log则没有任何要合并的内容。

Note that this will work even if you are on a feature branch -- that does not have a tracking remote, since if explicitly refers to origin/masterinstead of implicitly using the upstream branchremembered by Git.

请注意,即使您在没有跟踪远程的功能分支上,这也将起作用,因为如果显式引用origin/master而不是隐式使用Git 记住的上游分支

回答by Stephen Haberman

If this is for a script, you can use:

如果这是用于脚本,则可以使用:

git fetch
$(git rev-parse HEAD) == $(git rev-parse @{u})

(Note: the benefit of this vs. previous answers is that you don't need a separate command to get the current branch name. "HEAD" and "@{u}" (the current branch's upstream) take care of it. See "git rev-parse --help" for more details.)

(注意:这个和以前的答案相比的好处是你不需要一个单独的命令来获取当前分支名称。“HEAD”和“@{u}”(当前分支的上游)照顾它。见“git rev-parse --help”了解更多详情。)

回答by brool

The command

命令

git ls-remote origin -h refs/heads/master

will list the current head on the remote -- you can compare it to a previous value or see if you have the SHA in your local repo.

将列出遥控器上的当前头部——您可以将其与以前的值进行比较,或者查看您的本地存储库中是否有 SHA。

回答by wjordan

Here's a Bash one-liner that compares the current branch's HEAD commit hash against its remote upstream branch, no heavy git fetchor git pull --dry-runoperations required:

这是一个 Bash one-liner,将当前分支的 HEAD 提交哈希与其远程上游分支进行比较,不需要繁重git fetchgit pull --dry-run操作:

[ $(git rev-parse HEAD) = $(git ls-remote $(git rev-parse --abbrev-ref @{u} | \
sed 's/\// /g') | cut -f1) ] && echo up to date || echo not up to date

Here's how this somewhat dense line is broken down:

下面是这条有点密集的线是如何分解的:

  • Commands are grouped and nested using $(x)Bash command-substitutionsyntax.
  • git rev-parse --abbrev-ref @{u}returns an abbreviated upstream ref (e.g. origin/master), which is then converted into space-separated fields by the piped sedcommand, e.g. origin master.
  • This string is fed into git ls-remotewhich returns the head commit of the remote branch. This command will communicate with the remote repository. The piped cutcommand extracts just the first field (the commit hash), removing the tab-separated reference string.
  • git rev-parse HEADreturns the local commit hash.
  • The Bash syntax [ a = b ] && x || ycompletes the one-liner: this is a Bash string-comparison=within a test construct [ test ], followed by and-list and or-list constructs && true || false.
  • 命令使用$(x)Bash命令替换语法进行分组和嵌套。
  • git rev-parse --abbrev-ref @{u}返回一个缩写的上游引用(例如origin/master),然后通过管道sed命令将其转换为空格分隔的字段,例如origin master
  • 这个字符串被送入git ls-remote,返回远程分支的头部提交。此命令将与远程存储库通信。管道cut命令仅提取第一个字段(提交哈希),删除制表符分隔的引用字符串。
  • git rev-parse HEAD返回本地提交哈希。
  • Bash 语法[ a = b ] && x || y完成了单行:这是一个测试构造中的 Bash字符串比较,后跟 and-list 和 or-list 构造。=[ test ]&& true || false

回答by Bruno Adelé

I suggest you go see the script https://github.com/badele/gitcheck. I have coded this script for check in one pass all your Git repositories, and it shows who has not committed and who has not pushed/pulled.

我建议你去看看脚本https://github.com/badele/gitcheck。我已经编写了这个脚本,以便一次性检查所有 Git 存储库,它显示了谁没有提交,谁没有推送/拉取。

Here a sample result:

这是一个示例结果:

Enter image description here

在此处输入图片说明

回答by ma11hew28

I based this solution on the comments of @jberger.

我根据@jberger 的评论建立了这个解决方案。

if git checkout master &&
    git fetch origin master &&
    [ `git rev-list HEAD...origin/master --count` != 0 ] &&
    git merge origin/master
then
    echo 'Updated!'
else
    echo 'Not updated.'
fi

回答by thuovila

There are many very feature rich and ingenious answers already. To provide some contrast, I could make do with a very simple line.

已经有许多功能丰富且巧妙的答案。为了提供一些对比,我可以用一条非常简单的线来凑合。

# Check return value to see if there are incoming updates.
if ! git diff --quiet remotes/origin/HEAD; then
 # pull or whatever you want to do
fi

回答by Harikrishna

The below script works perfectly.

下面的脚本完美运行。

changed=0
git remote update && git status -uno | grep -q 'Your branch is behind' && changed=1
if [ $changed = 1 ]; then
    git pull
    echo "Updated successfully";
else
    echo "Up-to-date"
fi

回答by Jeet

I think the best way to do this would be:

我认为最好的方法是:

git diff remotes/origin/HEAD

Assuming that you have the this refspec registered. You should if you have cloned the repository, otherwise (i.e., if the repo was created de novo locally, and pushed to the remote), you need to add the refspec explicitly.

假设您已注册此 refspec。如果您已经克隆了存储库,则应该这样做,否则(即,如果存储库是在本地从头创建并推送到远程的),您需要显式添加 refspec。