简体   繁体   English

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

[英]git checkout to latest commit on current branch

I try to find a way to checkout to the latest commit in the current branch of a repository. 我试图找到一种方法来检出存储库当前分支中的最新提交。 I think this is trivial, I just can't come up with the right incarnation of commands. 我认为这很简单,我只是无法提出正确的命令形式。

To describe my problem a bit more in detail. 为了更详细地描述我的问题。 This is what I want to achive. 这就是我要达到的目标。 I want to automatically update the working directory of a git repository with the latest version from server but keeping whatever branch the repository is on right now and I don't care about local changes. 我想用服务器上的最新版本自动更新git仓库的工作目录,但是要保留该仓库现在位于的任何分支,并且我不在乎本地更改。

So first I run git fetch to get all commits from server. 所以首先我运行git fetch从服务器获取所有提交。 Then I would do git checkout HEAD to advance to the latest commit or even git chekout -f HEAD since I don't care about local changes. 然后,我将执行git checkout HEAD进行最新提交,甚至执行git chekout -f HEAD,因为我不在乎本地更改。 Unfortunately this tells me: 不幸的是,这告诉我:

Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded. 您的分支在1次提交后位于“起源/主”之后,并且可以快速转发。 (use "git pull" to update your local branch) (使用“ git pull”更新您的本地分支)

But I do not want a pull since that would merge with local changes imho. 但是我不想拉,因为那样会与本地更改合并。 A git reset --hard also does not work since it would not advance to the latest commit. git reset --hard也不起作用,因为它不会前进到最新的提交。 And a git chechout master also does not work since I don't know if this repository is on branch master or a different one. git chechout master也无法正常工作,因为我不知道此存储库是在分支master还是其他分支上。

So I think the command I am looking for would be something like this: 所以我认为我正在寻找的命令将是这样的:

git checkout -f `git show_lastest_commit_on_current_branch` git checkout -f`git show_lastest_commit_on_current_branch`

Ps: 附:

While writing this I think I came up with a solution. 在撰写本文时,我想我想出了一个解决方案。 First run a git reset --hard to throw away any local changes and then I can safely run git pull since there is nothing more which could create a conflict. 首先运行git reset-很难丢弃任何本地更改,然后我可以安全地运行git pull,因为没有其他可能导致冲突的内容。 Is this the right thing to do? 这是正确的做法吗?

I probably would not do this in the first place. 首先,我可能不会这样做。 I'm not sure what your setup is, but in general, if there's anything that git reset --hard would obliterate, no automated script should be doing that at all. 我不确定您的设置是什么,但是总的来说,如果git reset --hard会消失,那么任何自动化脚本都不会这样做。 If you want to have automated deployment, the deployment area probably should not be using Git this way in the first place. 如果要进行自动部署,则部署区域可能首先不应该使用Git。 (That is, “don't use Git at all” or “use Git, but treat the entire deployed branch as 'build artifacts' that are not source-controlled” would be the rule here.) (即,“根本不使用Git”或“使用Git,而是将整个部署的分支视为不受源代码控制的'构建工件'”)。

That said, if I had to do this, I'd probably go for the method ElpieKay outlined , or something equivalent, such as git fetch && git reset --hard @{u} . 就是说,如果我必须这样做,我可能会选择ElpieKay概述的方法 ,或类似的方法 ,例如git fetch && git reset --hard @{u}

Finding the current branch 查找当前分支

Note that if you want to get the name of the current branch, there are two ways to do this in a shell (sh or bash) script: 请注意,如果要获取当前分支的名称 ,可以使用两种方法在Shell(sh或bash)脚本中执行此操作:

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

Now $branch is, eg, master or deploy or whatever. 现在$branch是,例如masterdeploy或其他。 If the repository is in "detached HEAD" mode, the call to git symbolic-ref HEAD printed: 如果存储库处于“分离式HEAD”模式,那么对git symbolic-ref HEAD的调用将被打印:

fatal: ref HEAD is not a symbolic ref

to standard error, and then the || exit 到标准错误,然后|| exit || exit clause made the script quit. || exit子句使脚本退出。 (Adjust behavior as desired by changing the script; add -q to suppress Git's message to stderr.) (通过更改脚本来根据需要调整行为;添加-q以禁止Git向stderr发送消息。)

Alternatively: 或者:

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

Now $ref is, eg, master or deploy or whatever, unless the repository is in "detached HEAD" mode, in which case $ref is the literal string HEAD . 现在$ref是例如masterdeploy或其他东西,除非存储库处于“分离式HEAD”模式,在这种情况下$ref是文字字符串HEAD (This is why I used the name ref rather than branch .) (这就是为什么我使用名称ref而不是branch 。)

Using @{u} 使用@{u}

The @{u} syntax is short for @{upstream} and is described in the gitrevisions documentation . @{u}语法是@{upstream}缩写,并在gitrevisions文档中进行描述。 In General, any place where Git needs a particular commit ID, you may spell it with any number of revision specifications. 通常,在Git需要特定提交ID的任何地方,您都可以使用任何数量的修订规范对其进行拼写。 A branch name like master simply translates to the tip commit on that branch. master这样的分支名称只是转换为该分支上的尖端提交。 Adding @{upstream} directs Git to: 添加@{upstream}会将Git定向到:

  • find the current branch (much as we did above); 查找当前分支(与上面的操作大致相同);
  • look up branch. $branch .remote 查找branch. $branch .remote branch. $branch .remote , eg, branch.master.remote is probably origin branch. $branch .remote ,例如branch.master.remote可能是origin
  • look up branch. $branch .merge 查找branch. $branch .merge branch. $branch .merge , eg, branch.master.merge is probably refs/heads/master branch. $branch .merge ,例如branch.master.merge可能是refs/heads/master
  • combine the two lookup-results and apply the mapping rules in remote. remote .fetch 结合两个查找结果,并在remote. remote .fetch应用映射规则remote. remote .fetch remote. remote .fetch , eg, remote.origin.fetch is probably +refs/heads/*:refs/remotes/origin/* remote. remote .fetch ,例如remote.origin.fetch可能是+refs/heads/*:refs/remotes/origin/*
  • use the mapping output as a symbolic name for the appropriate remote-tracking branch, eg, refs/remotes/origin/master is the full spelling for origin/master 使用映射输出作为符号名称为相应的远程跟踪分支,例如, refs/remotes/origin/master为完整拼写origin/master

Thus, git reset --hard @{u} "means" git reset --hard origin/master if you're on branch master and your local master is set to track remote-tracking branch origin/master . 因此, git reset --hard @{u} “意味着” git reset --hard origin/master如果您在分支master并且本地master设置为跟踪远程跟踪分支origin/master 1 Note that because @{u} looks up the current branch, it fails immediately if you are in "detached HEAD" mode: a detached HEAD is not a named branch 2 and hence cannot be tracking anything. 1请注意,因为@{u}查找当前分支,所以如果您处于“分离头”模式,它将立即失败:分离头不是命名分支2 ,因此无法跟踪任何内容。


1 There are too many occurrences of the words "branch" and "track" in this, but that's how Git spells it out: a local branch (by name, such as master ) is allowed to track one other branch. 1其中出现了太多的“ branch”和“ track”字样,但这就是Git拼写出来的方式:允许一个本地分支(按名称,例如master跟踪另一个分支。 The other branch that it tracks is usually a remote-tracking branch such as origin/master . 它跟踪的另一个分支通常是一个远程跟踪分支,例如origin/master So: 所以:

  1. master is a branch (or more precisely, a branch name ); master是一个分支(或更确切地说是一个分支名称 );
  2. master -the-name tracks something; master -the-name 跟踪某些内容;
  3. the thing it tracks is another name; 它追踪的东西是另一个名字;
  4. the other name is refs/remotes/origin/master , or origin/master for short; 其他名称是refs/remotes/origin/master ,或简称origin/master and
  5. origin/master is a remote-tracking branch . origin/master是一个远程跟踪分支

When the local branch named B is tracking a remote-tracking branch RB , the remote in question, and/or that branch on that remote, is what we (and Git) call the upstream . 当名为B的本地分支正在跟踪远程跟踪分支RB时 ,所讨论的远程和/或该远程上的那个分支就是我们(和Git)称为上游的

2 In fact, a detached HEAD behaves just like a branch, except that it has no name—or, for some purposes, it has the name HEAD . 2实际上,一个分离的HEAD的行为就像一个分支,只是它没有名称,或者出于某种目的,它的名称是HEAD You cannot set branch.HEAD.remote and branch.HEAD.merge , though. 但是,您无法设置branch.HEAD.remotebranch.HEAD.merge


The difference between git fetch origin and git fetch origin master git fetch origingit fetch origin master之间的区别

Assume we've set $branch as above. 假设我们如上所述设置$branch Let's also set up $remote from branch.$branch.remote : 我们还从branch.$branch.remote设置$remote

remote=$(git config --get branch.$branch.remote) || \
    die "branch $branch has no remote"

(where die does the obvious thing). die是显而易见的事情)。

We are interested in the difference between these two alternatives: 我们对这两种选择之间的区别感兴趣:

git fetch $remote $branch && git reset --hard FETCH_HEAD  # alternative 1
git fetch && git reset --hard @{u}                        # alternative 2

If your Git is not older than version 1.8.4, there is only one difference here: adding $remote $branch —let's say this is origin master for discussion purposes—tells your Git to bring over only the updates that go into your origin/master , rather than updating all of your remote-tracking branches. 如果您的Git版本不低于1.8.4,则这里只有一个区别:添加$remote $branch (假设这是出于讨论目的的origin master ,告诉您的Git仅带入origin/master ,而不是更新所有的远程跟踪分支。

That is, git fetch origin gets you all the updates from remote origin , while git fetch origin master gets you only the updates to their master . 也就是说, git fetch origin可以让你从远程所有的更新origin ,而git fetch origin master让你更新自己的master If there are other updates to other branches, you skip them for now. 如果其他分支还有其他更新,则暂时跳过它们。 (You may have to pay the cost to get them later, and/or any such costs are typically tiny enough not to matter anyway.) (您可能必须支付费用才能稍后获得它们,和/或任何这样的费用通常很小,无论如何都无所谓。)

If your Git version is very old, though, there is one more difference: specifically, Git versions predating 1.8.4 fail to update origin/master , putting the new information only in the special FETCH_HEAD file. 但是,如果您的Git版本太旧了,那就还有另外一个区别:具体地说,早于1.8.4的Git版本无法更新origin/master将新信息放入特殊的FETCH_HEAD文件中。 (The FETCH_HEAD file is mainly meant for the git pull script to use. It records, for git pull 's purposes, everything that git fetch brought over. Remember that git pull simply runs git fetch first, then runs git merge unless you direct it to run git rebase instead. The merge-or-rebase step uses the information saved in FETCH_HEAD to know how to do the merge-or-rebase.) FETCH_HEAD文件主要供git pull脚本使用。出于git pull的目的,它记录git fetch带来的所有内容。请记住git pull只是先运行git fetch ,然后运行git merge除非您对其进行定向改为运行git rebase FETCH_HEAD -or-rebase步骤使用保存在FETCH_HEAD的信息来了解如何执行merge-or-rebase。)

Which one should you use? 您应该使用哪一个? That's up to you. 随你(由你决定。 Alternative 1 avoids fetching extra branches but requires setting up variables $branch and $remote . 备选方案1避免获取额外的分支,但需要设置变量$branch$remote This in turn forces you to decide up front what to do if you're not on any branch (if you're in detached HEAD mode). 反过来,这会迫使您预先决定如果您不在任何分支上(如果处于分离的HEAD模式)该怎么办。 Alternative 2 is easier to write, and simply fails automatically if you're in detached HEAD mode. 备选方案2更易于编写,并且如果处于分离式HEAD模式,则只会自动失败。 Alternative 2 updates all your remote-tracking branches (both good and bad, considering the extra work in fetching) and papers over the difference between Git 1.7 (pre-1.8.4) and Git 2.10 (post-1.8.3). 备选方案2更新您的所有远程跟踪分支(无论是好是坏,考虑到获取时的额外工作),并针对Git 1.7(1.8.4之前的版本)和Git 2.10(1.8.3之后的版本)之间的差异进行了论文更新。 Papering over this difference is either neutral or good. 消除这种差异是中立的还是好的。

The @{upstream} syntax itself was new in Git version 1.7. @{upstream}语法本身在Git版本1.7中是新的。 As far as I know, even the oldest-and-worst Linux distributions come with Git version 1.7.1 now, so there is probably no need to worry about someone still using 1.5 or 1.6. 据我所知,即使最老旧的Linux发行版现在都随Git 1.7.1一起提供,因此可能不必担心有人仍在使用1.5或1.6。

Note that reset handles upstream rebases 请注意, reset处理上游基准

Any attempt to use git pull , which runs git merge , can cause you trouble if your upstream does a rebase, or strips out commits. 如果尝试使用运行git merge git pull ,则可能会给您带来麻烦,如果您的上游进行了重新设置或删除了提交。 This is because your remote-tracking branch ( origin/master or whatever) is moving in a way that does not simply add new commits. 这是因为您的远程跟踪分支( origin/master或其他)正在以一种不仅仅添加新提交的方式移动。 When that happens, Git will generally consider commits on your branch (your master ) to be commits that you made, that they never had. 当发生这种情况,Git会普遍认为承诺在你的分支(你的master )是所做的提交,他们从未有过。 The git merge step will merge "your" commits with their latest, effectively resurrecting commits your upstream thought they had sent down the memory hole . git merge步骤会将“您的”提交与他们最新的,有效的复活的提交合并,上游认为您的提交已经沿着内存孔发送了。

If your upstream never does this, it is not a problem. 如果您的上游从未这样做,那不是问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM