【问题标题】:Git: update a repository to certain revisionGit:将存储库更新到某个版本
【发布时间】:2013-07-30 08:51:09
【问题描述】:

假设我有一个版本号为 A 的存储库。我想将其更新为版本 B,而最新版本是 C。(版本 A 早于 B,B 早于 C)。我是 git 新手,所以我做了一些研究,发现了 this,这启发了我一个解决方案:

git pull # update from A to the latest revision C
git reset --hard B

确实有效。但是由于我不能直接从Agit reset --hard B,所以先更新到最新的还是太重了,不知道可能有一些单行命令来满足我的需要。请问有什么提示吗?

【问题讨论】:

    标签: git


    【解决方案1】:

    没有“将存储库更新到某个版本”。您的存储库包含所有版本,这就是 git fetch / git pull 所做的。

    如果您想在本地当前工作树中放置特定版本的 repo,您​​可以通过多种方式来做到这一点。最接近您的问题的是:

    更新您的本地存储库:

    git fetch origin
    

    创建一个新分支(从您当前所在的任何分支,我们稍后会硬重置,所以没关系):

    git branch yourbranchname
    git checkout yourbranchname
    

    以上2个操作可以简写为一个(假设当前HEAD为分支源):

    git checkout -b yourbranchname
    

    然后将该分支的指针指向您需要的提交 (B):

    git reset --hard sha1-of-B
    

    git reset --hard 将始终有效,它不依赖于您的分支的历史记录,它有效的唯一条件是提交 B 在您的本地对象库中(即 B 必须存在并且必须从远程仓库不是你的工作)。

    正如@Hasturkun 指出的那样,您还可以使用额外的参数直接从任意散列分支:

    git checkout -b yourbranchname SHA-1
    

    【讨论】:

    • 您实际上并不需要重置分支,因为您可以简单地创建它,起点位于您想要的位置,即。 git branch newbranch SHA1-of-B,或git checkout -b newbranch SHA1-of-B
    • @Sébastien 感谢您向我介绍一些基本概念。
    • @Hasturkun 是的,我不想列举所有可能的方式,并认为鉴于 OP 专门询问了reset --hard,这可能是最容易理解的。我可以根据您的意见调整答案。谢谢
    • 我发现这个答案有些误导:git reset 既不是 OP 需要使用的,也不是他应该使用的。正确的做法是结合git checkoutgit branch如果没有必要,不应推荐像 git reset hard 这样可能具有破坏性的命令。
    • 这是一个如此艰难的过程,只是为了进行修订。对于 Mercurial,它只是 hg update -r REV。而且您不会丢失任何顶部的提交。
    【解决方案2】:

    你的方法是完全错误的。您正在修改您不想修改的内容:您当前的分支(大概是master)。

    一个简单的线性 git 存储库是一个这样的提交链

    *---A---*---*---B---*---*---C
        ^                       ^
        |                       |
      master              origin/master
        ^
        |
       HEAD
    

    这是您调用git fetch 后存储库的状态。请注意,包含所有中间步骤的整个历史记录都在您的本地硬盘上。只是你只有提交时的状态A 签出(HEAD 指向master 指向A),所以你看到的文件属于那个状态。

    现在,如果您只想查看以B 提交的状态,您可以使用git checkout B 查看该提交。这会将您看到的文件更新为B 的状态,并将HEAD 指向该提交:

    *---A---*---*---B---*---*---C
        ^           ^           ^
        |           |           |
      master       HEAD   origin/master
    

    HEAD 始终引用git 认为您所在的提交/分支,并且当您调用git status 时它将与您的工作目录进行比较。

    如果您只想查看该提交,简单的git checkout B 就足够了。如果您确实想要做出您提交并想要保留的更改,您应该引入一个新分支来记录这些更改。这是通过在git checkout B 之后的简单git checkout -b newBranch 实现的。这会给你状态

    *---A---*---*---B---*---*---C
        ^           ^           ^
        |           |           |
      master    newBranch origin/master
                    ^
                    |
                   HEAD
    

    这只是为提交B 提供了一个名称,而不是它的哈希值。在更多提交之后,您的状态将如下所示:

    *---A---*---*---B---*---*---C
        ^           |           ^
        |           |           |
      master         \    origin/master
                       \
                        *---*---D
                                ^
                                |
                            newBranch
                                ^
                                |
                               HEAD
    

    关键是,在使用git checkout ... 签出其他分支/提交后,您始终可以通过调用git checkout newBranch 轻松返回到提交D,并且永久引用停止git 垃圾收集提交D.


    现在,为什么使用 git reset --hard 不好?首先,它会破坏您尚未提交的所有本地更改,恕不另行通知。其次,如果您不小心,它可能会丢失您的历史记录。

    例如,假设您在上次推送到上游存储库后进行了一些更改,并想查看一些历史提交 B。 (与您的问题中的情况有些相反。)历史看起来像这样:

      *---A---*---*---B---*---*---C
          ^                       ^
          |                       |
    origin/master               master
                                  ^
                                  |
                                 HEAD
    

    使用git reset --hard B,你会得到这个状态:

      *---A---*---*---B-(-*---*---C )
          ^           ^
          |           |
    origin/master   master
                      ^
                      |
                     HEAD
    

    括号中的提交不再被任何分支直接或间接引用,并且可能随时被垃圾收集。 git 对垃圾收集可能不是很激进,但如果它在你处于这种状态时进行垃圾收集,你将无法获得提交 C,它将永远丢失。您不希望这种情况发生,因此养成轻率使用git reset --hard 的习惯并不是一个好主意。

    如果您改用git checkout,分支master 仍将指向C,您仍然可以使用简单的git checkout master 回到它。

    【讨论】:

      【解决方案3】:

      您需要为此使用git checkout。做吧:

      git 结帐 B

      您将获得该修订版。

      【讨论】:

      • 谢谢,但我在使用 git checkout: reference is not a tree 时遇到了错误。
      • 我认为 Hasturkun 在 Sébastien Dawans 的回答中的评论会为你解决这个问题。
      • 确实,帮助给了你: git checkout [OPTIONS] 它需要一个分支,而不是一个提交!
      猜你喜欢
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 2014-09-06
      • 2020-12-04
      • 2023-04-06
      • 2014-08-22
      • 1970-01-01
      • 2010-10-27
      相关资源
      最近更新 更多