git checkout到当前分支的最新提交

时间:2016-10-11 07:48:06

标签: git version-control

我试图找到一种方法来检查存储库当前分支中的最新提交。我认为这是微不足道的,我无法想出正确的命令化身。

更详细地描述我的问题。这就是我想要实现的目标。我想用服务器上的最新版本自动更新git存储库的工作目录,但是保留存储库现在的任何分支,我不关心本地更改。

首先,我运行 git fetch 来获取服务器的所有提交。 然后我会做 git checkout HEAD 进入最新提交甚至 git chekout -f HEAD ,因为我不关心本地更改。不幸的是,这告诉我:

  

你的分支是1个提交后面的'origin / master',可以   快进。 (使用“git pull”更新本地分支)

但我不想要拉,因为那会与当地的变化融合。 git reset --hard 也不起作用,因为它不会进入最新的提交。并且 git chechout master 也不起作用,因为我不知道这个存储库是在分支主服务器上还是在另一个存储库上。

所以我认为我正在寻找的命令是这样的:

git checkout -f`git show_lastest_commit_on_current_branch`

P.S:

在写这篇文章时,我想我想出了一个解决方案。首先运行 git reset --hard 以丢弃任何本地更改,然后我可以安全地运行 git pull ,因为没有更多可能会产生冲突。 这是正确的做法吗?

1 个答案:

答案 0 :(得分:2)

我可能不会首先这样做。我不确定您的设置是什么,但一般情况下,如果git reset --hard会消除任何内容,那么根本不应该使用自动脚本。如果您想进行自动部署,部署区域可能不应该首先以这种方式使用Git。 (也就是说,“根本不使用Git”或“使用Git,但将整个部署的分支视为非源代码控制的'构建工件'”将是此处的规则。)

那就是说,如果我这样做,我可能会选择the method ElpieKay outlined或类似的东西,例如git fetch && git reset --hard @{u}

查找当前分支

请注意,如果您想获取当前分支的 name ,有两种方法可以在shell(sh或bash)脚本中执行此操作:

branch=$(git symbolic-ref HEAD) || exit
branch=${branch#refs/heads/}

现在$branch例如是masterdeploy或其他。如果存储库位于"分离的HEAD"模式,打印到git symbolic-ref HEAD的调用:

fatal: ref HEAD is not a symbolic ref

到标准错误,然后|| exit子句使脚本退出。 (通过更改脚本根据需要调整行为;添加-q以将Git的消息抑制为stderr。)

可替换地:

ref=$(git rev-parse --symbolic --abbrev-ref HEAD)

现在$ref是,例如masterdeploy或其他什么,除非存储库位于"分离的HEAD"模式,在这种情况下$ref是文字字符串HEAD。 (这就是我使用名称ref而非branch。)

的原因

使用@{u}

@{u}语法是@{upstream}的缩写,在the gitrevisions documentation中有所描述。一般情况下,Git需要特定提交ID的任何地方,您可以使用任意数量的修订规范进行拼写。像master这样的分支名称只是转换为该分支上的提示提交。添加@{upstream}会将Git指向:

  • 找到当前分支(就像我们上面做的那样);
  • 查找branch.$branch.remote,例如,branch.master.remote可能是origin
  • 查找branch.$branch.merge,例如,branch.master.merge可能是refs/heads/master
  • 合并两个查找结果并应用remote.remote.fetch中的映射规则,例如,remote.origin.fetch可能是+refs/heads/*:refs/remotes/origin/*
  • 使用映射输出作为相应远程跟踪分支的符号名称,例如refs/remotes/origin/masterorigin/master的完整拼写

因此,git reset --hard @{u}"表示" git reset --hard origin/master如果您在分支master上,并且您的本地master设置为跟踪远程跟踪分支origin/master 1 请注意因为@{u}查找当前分支,如果你处于"分离的HEAD"它会立即失败。 mode:分离的HEAD不是命名分支 2 ,因此无法跟踪任何内容。

1 出现过多的单词" branch"和"追踪"在这方面,但是Git如何解释它:一个本地分支(按名称,如master)被允许跟踪另一个分支。它跟踪的另一个分支通常是远程跟踪分支,例如origin/master。所以:

  1. master是一个分支(或更确切地说,分支名称);
  2. master - 名称​​跟踪的内容;
  3. 它追踪的是另一个名字;
  4. 另一个名称是refs/remotes/origin/master,简称origin/master;和
  5. origin/master远程跟踪分支
  6. 当名为 B 的本地分支正在跟踪远程跟踪分支 RB 时,有问题的远程和/或该远程分支就是我们(和Git)调用上游

    2 实际上,分离的HEAD的行为就像一个分支,除了它没有名称 - 或者出于某些目的,它的名称为HEAD。但是,您无法设置branch.HEAD.remotebranch.HEAD.merge

    git fetch origingit fetch origin master

    之间的差异

    假设我们已按上述方式设置$branch。我们还设置了来自$remote的{​​{1}}:

    branch.$branch.remote

    (其中remote=$(git config --get branch.$branch.remote) || \ die "branch $branch has no remote" 显而易见)。

    我们对这两种选择之间的区别感兴趣:

    die

    如果你的Git不是1.8.4版本,那么这里只有一个区别:添加git fetch $remote $branch && git reset --hard FETCH_HEAD # alternative 1 git fetch && git reset --hard @{u} # alternative 2 - 让我们说$remote $branch用于讨论目的 - 告诉你的Git仅包含进入origin master的更新,而不是更新所有远程跟踪分支。

    也就是说,origin/master让您所有来自远程{{​​1}}的更新,而git fetch origin只会 更新到他们的origin。如果其他分支还有其他更新,则暂时跳过它们。 (您可能需要支付以后获得它们的费用,和/或任何此类费用通常都很小,无论如何都不重要。)

    如果您的Git版本非常老,那么还有一个区别:具体而言,早于1.8.4的Git版本无法更新git fetch origin master,只将新信息放入特殊master文件。 (origin/master文件主要用于FETCH_HEAD脚本。它为FETCH_HEAD目的记录git pull带来的所有内容。请记住git pull首先只运行git fetch,然后运行git pull,除非您指示它运行git fetch。合并或重组步骤使用git merge中保存的信息知道如何进行merge-or-rebase。)

    你应该使用哪一个?这取决于你。备选方案1避免获取额外分支,但需要设置变量git rebaseFETCH_HEAD。如果您不在任何分支上(如果您处于分离的HEAD模式),这反过来会迫使您事先决定该怎么做。备选方案2更容易编写,如果您处于分离的HEAD模式,则会自动失败。备选2更新所有你的远程跟踪分支(好的和坏的,考虑到提取的额外工作)和关于Git 1.7(1.8.4之前)和Git 2.10之间差异的论文(后1.8.3)。对这种差异的论述要么是中立的,要么是好的。

    $branch语法本身在Git 1.7版中是新的。据我所知,即使是最古老和最差的Linux发行版现在都带有Git版本1.7.1,所以可能没有必要担心仍然使用1.5或1.6的人。

    请注意$remote处理上游rebase

    任何使用运行@{upstream}的{​​{1}}的尝试都会导致您的上游执行rebase或删除提交时遇到麻烦。这是因为您的远程跟踪分支(reset或其他)正在以不仅仅添加新提交的方式移动。当发生这种情况时,Git通常会认为您的分支(您的git pull)的提交是所做的提交,他们永远不会有。 git merge步骤将合并"您的"提交最新的,有效的复活提交他们向memory hole发送的上游思想。

    如果您的上游从不这样做,那就不是问题了。