Git:将存储库更新为某个版本
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17942396/
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
Git: update a repository to certain revision
提问by Sébastien Dawans
Say I have a repository that has a revision number A. And I would like to update it to revision B, while the latest revision is C. (revision A is earlier than B, and B is earlier than C). I'm new to git so I did some research, and found this, which inspires me a solution:
假设我有一个版本号为 A 的存储库。我想将其更新为版本 B,而最新版本是 C。(版本 A 早于 B,而 B 早于 C)。我是 git 的新手,所以我做了一些研究,发现了这个,这启发了我一个解决方案:
git pull # update from A to the latest revision C
git reset --hard B
That does work. But since I can't git reset --hard B
from A directly, the precedent update to latest is still too heavy, I wonder there might be some one-line command to match my need. Any hints please?
那确实有效。但是因为不能git reset --hard B
直接从A,先例更新到latest还是太重了,不知道有没有什么单行命令可以满足我的需求。请问有什么提示吗?
回答by Sébastien Dawans
There is no "updating a repository to a certain version". You repository has all the versions, that's what git fetch
/ git pull
does.
没有“将存储库更新到某个版本”。您的存储库拥有所有版本,这就是git fetch
/ 的git pull
作用。
If you want put a specific revision of the repo in your current working tree locally, there are several ways you could do that. The closest to your questions is:
如果您想在本地将 repo 的特定修订版放入当前的工作树中,有几种方法可以做到这一点。最接近你的问题是:
update your local repository:
更新您的本地存储库:
git fetch origin
create a new branch (from whatever branch you are currently on, we will reset hard later so it doesn't matter):
创建一个新分支(从您当前所在的任何分支开始,我们稍后将对其进行硬重置,因此无关紧要):
git branch yourbranchname
git checkout yourbranchname
The above 2 operations can be abbreviated into one (the current HEAD is assumed as source of the branch):
以上2个操作可以简写为一个(假设当前的HEAD是分支的源头):
git checkout -b yourbranchname
then place the pointer of that branch to the commit you need (B
):
然后将该分支的指针指向您需要的提交 ( B
):
git reset --hard sha1-of-B
git reset --hard will always work, it doesn't depend on your branch's history, the only condition for it to work is that commit B is in you local object base (i.e. B must exist and must have been fetched from a remote repo is it is not your work).
git reset --hard 将始终有效,它不依赖于您的分支的历史记录,它起作用的唯一条件是提交 B 在您的本地对象库中(即 B 必须存在并且必须从远程仓库中获取是不是你的工作)。
As @Hasturkun points out, you can also branch directly from any arbitrary hash with an extra argument:
正如@Hasturkun 指出的那样,您还可以使用额外的参数直接从任意散列中分支:
git checkout -b yourbranchname SHA-1
回答by jbr
You need to use git checkout
for this. Just do:
您需要为此使用git checkout
。做就是了:
git checkout B
git 结帐 B
and you'll have that revision.
你会得到那个修订版。
回答by cmaster - reinstate monica
Your approach is entirely wrong. You are modifying something that you don't want to modify: Your current branch (presumably master
).
你的做法是完全错误的。您正在修改您不想修改的内容:您当前的分支(大概是master
)。
A simple, linear git repository is a chain of commits like this
一个简单的线性 git 存储库是一个像这样的提交链
*---A---*---*---B---*---*---C
^ ^
| |
master origin/master
^
|
HEAD
That is the state of your repository after you have called git fetch
. Note that the entire history with all its intermediate steps is right there on your local hard drive. It's just that you only have the state at commit A
checked out (HEAD
points to master
which points to A
), so the files that you see belong to that state.
这是您调用后存储库的状态git fetch
。请注意,整个历史及其所有中间步骤都在您的本地硬盘上。只是您只A
检查了提交时的状态(HEAD
指向master
哪个指向A
),因此您看到的文件属于该状态。
Now, if you just want to look at the state that was committed as B
, you can just check out that commit with git checkout B
. This updates the files that you see to the state of B
, and points HEAD
at that commit:
现在,如果您只想查看作为 提交的状态B
,您可以使用git checkout B
. 这会将您看到的文件更新为B
,并指向HEAD
该提交:
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master HEAD origin/master
HEAD
always references the commit/branch that git
thinks you are on, and to which it will compare your work directory when you call git status
.
HEAD
始终引用git
认为您所在的提交/分支,并且在您调用git status
.
The simple git checkout B
is sufficient, if you just want to look at that commit. If you actually want to make changes that you commit and want to preserve, you should introduce a new branch to record those changes. This is achieved by a simple git checkout -b newBranch
after the git checkout B
. This will give you the state
git checkout B
如果您只想查看该提交,那么简单就足够了。如果您确实想要进行您提交并想要保留的更改,您应该引入一个新分支来记录这些更改。这是通过一个简单git checkout -b newBranch
的git checkout B
. 这会给你状态
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master newBranch origin/master
^
|
HEAD
This just gives a name to commit B
other than its hash value. After some more commits, your state would look like this:
这只是给出了一个提交的名称,B
而不是它的哈希值。再提交几次后,您的状态将如下所示:
*---A---*---*---B---*---*---C
^ | ^
| | |
master \ origin/master
\
*---*---D
^
|
newBranch
^
|
HEAD
The point is, that, after checking out some other branch/commit with git checkout ...
, you can always easily return to commit D
by calling git checkout newBranch
, and the permanent reference stops git
from garbage collecting commit D
.
关键是,在使用 检出其他分支/提交后git checkout ...
,您始终可以D
通过调用轻松返回到提交git checkout newBranch
,并且永久引用停止git
垃圾收集提交D
。
Now, why is using git reset --hard
bad? First of all, it clobbers all your local changes that you have not committed yet without further notice. Second, it may loose you history if you are not careful with it.
现在,为什么使用git reset --hard
不好?首先,它会破坏您尚未提交的所有本地更改,恕不另行通知。其次,如果您不小心,它可能会丢失您的历史记录。
Consider, for example, the case that you have made some changes after you last pushed to your upstream repository, and want to take a look at some historic commit B
. (Somewhat the opposite of the case in your question.) The history looks like this:
例如,考虑这样一种情况,您在上次推送到上游存储库后进行了一些更改,并希望查看一些历史提交B
。(与您问题中的情况有些相反。)历史看起来像这样:
*---A---*---*---B---*---*---C
^ ^
| |
origin/master master
^
|
HEAD
With git reset --hard B
, you get this state:
使用git reset --hard B
,您将获得以下状态:
*---A---*---*---B-(-*---*---C )
^ ^
| |
origin/master master
^
|
HEAD
The commits in parentheses are not referenced directly or indirectly by any branch anymore, and may be garbage collected any time. git
may not be very aggressive with garbage collecting, but if it does garbage collect while you are in this state, there is no way for you to get commit C
back, it will be lost forever. You don't want this to happen, so it's not a good idea to get into the habit of using git reset --hard
lightly.
括号中的提交不再被任何分支直接或间接引用,并且可能随时被垃圾收集。git
垃圾收集可能不是很激进,但是如果它在您处于这种状态时进行垃圾收集,则您无法C
恢复提交,它将永远丢失。您不希望这种情况发生,因此养成git reset --hard
轻率使用的习惯并不是一个好主意。
Had you used git checkout
instead, the branch master
would still be pointing at C
, and you would still be able to get back to it with a simple git checkout master
.
如果您git checkout
改用,分支master
仍将指向C
,并且您仍然可以使用简单的git checkout master
.