简体   繁体   English

在Git中,如何从远程存储库中签出或更新到最新版本?

[英]In Git, how can I checkout or update to the latest revision from a remote repository?

I'd like to create a simple script that clones a Github repository, updates the repository's working directory to the latest revision whichever branch it may be on , and then runs its tests. 我想创建一个简单的脚本来克隆Github存储库,将存储库的工作目录更新到最新版本, 无论它在哪个分支上 ,然后运行其测试。

To do this in Mercurial, I could use the following steps: 要在Mercurial中做到这一点,我可以使用以下步骤:

hg clone https://hghub.com/user/my-repo my-repo
cd my-repo
hg update tip

What is the Git equivalent to hg update tip ? 什么是Git等同于hg update tip

There isn't one. 没有一个。 In Mercurial, the "tip" is simply the highest numbered revision (using the relative rev numbers, which works there because commits are always "added to the pile", as it were). 在Mercurial中,“提示”只是编号最高的修订版(使用相对的修订版号,该修订版在此起作用,因为提交总是像以前那样“添加到堆中”)。

(That is, there's an absolute numbering of commits in any given repo . However, when two different repos that had diverged, are re-synchronized, the relative numbers of particular commits may not match up. For instance, suppose Joe and I start by each "hg clone"-ing a repo with 6 commits. I commit a change as rev 7, and it's ready to go out, but before I push, Joe commits a change as his rev 7 and pushes to our shared central repo. Now I pull his change, which is my rev 8; I merge my 7 and 8 and make commit 9; I push my 7-and-9 to the central repo, where they become revs 8 and 9 respectively. [Nothing happens with my rev 8, which the central repo already has as commit 7.] I now have as my rev 8, the changeset that is Joe's-and-central-repo's rev 7; and I have rev 9 as the merge. If he now pulls my change and merge, he has my change as his rev 8, and the merge as 9. So the relative numbers don't match any more at this point. But when you make your initial clone, this does not matter: yo (也就是说, 任何给定的回购中都有绝对数量的提交。但是,当两个不同的回购已重新同步时,特定提交的相对数量可能不匹配。例如,假设Joe和我以每个“ hg克隆”-提交一个带有6次提交的存储库。我提交了一个修订,即rev 7,它已经准备好发布了,但是在我推送之前,Joe提交了一个更改,即他的 rev 7,并推送到了我们共享的中央仓库。我拉了他的零钱,这是我的修订版8;我合并了我的7和8,并提交了9;将我的7和9推到了中央仓库,它们分别成为修订版8和9。 8,中央仓库已经具有提交7。]现在,我的修订集是乔8的修订集,即Joe's-and-central-repo的修订7;我将9合并为合并。然后合并,他的更改是我的rev 8,合并是9。所以相对数字在此不再匹配,但是当您进行初始克隆时,这无关紧要:哟 u're copying the other repo, and in the process you copy its numbering too.) 您正在复制另一个仓库,在此过程中,您也要复制其编号。)

If you can get hold of the other side's git reflogs (in this case, the branch history on github), you could look at which branch was most recently stepped-forward. 如果您可以掌握另一方的git reflog(在本例中为github上的分支历史记录),则可以查看哪个分支最近被转发了。 That would represent the latest commit. 那将代表最新的提交。 Or, it's possible that github tracks these things and allows everyone access to them (I don't know enough about github to say). 或者,github可能会跟踪这些东西并允许所有人访问它们(我对github的了解还不够多)。

(You could also look at commit time stamps, but again they're not necessarily in the order that commits were added to the repository.) (您也可以查看提交时间戳,但同样,它们不一定按提交添加到存储库的顺序排列。)

As torek said, there isn't a built-in way, because that's not how git works. 正如torek所说,没有内置的方法,因为git并不是这样工作的。

However, you can roll your own method, somewhat, though it's a bit involved. 但是,您可以滚动自己的方法,尽管有些复杂。

You could go with a naive approach, which lists all commits in <commit time> <full hash> style, sorts them numerically ( %ct is commit times in Unix epoch format, which is number of seconds since the start of 1970, so they sort nicely), takes the last one, cuts out just the hash, and checks that out: 您可以采用幼稚的方法,该方法以<commit time> <full hash>样式列出所有提交,并对它们进行数字排序( %ct是Unix时期格式的提交时间,这是自1970年初以来的秒数,因此它们排序得很好),取最后一个,仅切出哈希,然后检查一下:

$ git checkout `git log --all --format='%ct %H' | sort -n | tail -1 | cut -d' ' -f2`

However, that leaves you in a detached head state, because you're checking out by hash, and not by reference. 但是,这使您处于独立状态,因为您是通过哈希而不是引用进行检出的。

A slightly less naive, and longer approach would be to get all the known branches, which is to say the branch heads, and run those through a similar process, cutting out the branch ref at the end and checking that out: 一种不太天真,耗时较长的方法是获取所有已知分支,即分支头,并通过类似的过程来运行这些分支,最后切掉分支引用并进行检查:

$ git checkout $(for b in `git br | sed 's/..//'`; do echo `git log -1 $b --format='%ct %H'` $b; done | sort -n | tail -1 | cut -d' ' -f3)

There could be edge cases, but I don't know them. 可能会有一些极端情况,但我不知道。 The commit times should be in a good order, because everything that creates a commit, be it commit , cherry-pick , rebase , commit --amend , etc., all update the commit time of the commit they're copying. 提交时间应该井井有条,因为创建提交的所有内容(无论是commitcherry-pickrebasecommit --amend等)都将更新他们正在复制的提交的提交时间。 In other words, you can't insert an out-of-order date into the middle of a branch. 换句话说,您不能在分支的中间插入乱序日期。 If you cherry-pick something onto a branch, it goes on top with the latest commit time. 如果您将某些内容挑选到分支上,它将以最新的提交时间排在最前面。 If you rebase, each commit is made in sequence from the bottom up, so they'll also be in order. 如果您重新设置基准,则每次提交都是从下至上按顺序进行的,因此它们也将井井有条。

That said, rebase operations often create commits at a greater than 1-per-second intervals, in which case you'll have commits with exactly the same commit time, and it doesn't get any more fine-grained than that (I sometimes wish it did), so it's quite possible that the sort operation here will mix up the order of commits with matching timestamps. 也就是说,rebase操作通常会以大于每秒1的间隔创建提交,在这种情况下,您将使用完全相同的提交时间进行提交,并且没有比此更细粒度的了(我有时希望如此),因此这里的排序操作很有可能会将匹配时间戳的提交顺序混合在一起。 You could try to use author times at that point to help work things out, but that starts to become a more complicated function, and no longer a fairly straightforward shell pipeline. 您可以尝试在此时使用作者时间来帮助解决问题,但这开始变得更加复杂,并且不再是相当简单的shell管道。 Also, I'm not sure how correct that would always be. 另外,我不确定那将永远是正确的。 There could be crazy edge cases. 可能会有疯狂的边缘案例。

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

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