[英]Git: How do you replace your current working directory with a previous commit without branching or git revert?
Is there an easy way to the following with git? 有什么简单的方法可以使用git吗?
Basically I want to create a new commit at the top of my commit history that is equivalent to a previous commit from my history (eg to restore a project to a previous state). 基本上,我想在提交历史记录的顶部创建一个新的提交,它等同于历史记录中的先前提交(例如,将项目还原到先前的状态)。
I don't want to use branches because I'm teaching this to people who have never used git before, and I want to keep things as “linear” as possible. 我不想使用分支,因为我正在向从未使用过git的人讲授此内容,并且我想使事情尽可能“线性”。 (Most of my audience just needs to back stuff up, review project history, and restore a project to a previous state if necessary, but nothing else remotely fancy.)
(我的大多数听众只需要备份内容,查看项目历史记录,并在必要时将项目还原到以前的状态即可,但没有别的选择。)
I don't want to use git revert --no-commit 49a732c..HEAD
because this gives an error message if there does happen to be a merge after 49a732c
(which I admit is unlikely in my audience, but it does sometimes happen through frantic attempts to make error messages go away). 我不想使用
git revert --no-commit 49a732c..HEAD
因为如果49a732c
之后确实发生合并,这会给出错误消息(我承认我的听众不太可能,但是有时确实会发生使错误消息消失的疯狂尝试)。
I also don't want to delete/rewrite history. 我也不想删除/重写历史记录。
Essentially, is there a simpler way to do this? 本质上,有没有更简单的方法可以做到这一点?
# make sure on master and working directory clean
me@laptop:~/Desktop/proj$ git status
On branch master
nothing to commit, working directory clean
# check out commit to restore
me@laptop:~/Desktop/proj$ git checkout 49a732c
Note: checking out '49a732c'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b <new-branch-name>
HEAD is now at 49a732c... Fix bugs.
# copy project checked out at 49a732c to temp folder
me@laptop:~/Desktop/proj$ cp -r . ../temp
# check out master again
me@laptop:~/Desktop/proj$ git checkout master
Previous HEAD position was 49a732c... Fix bugs.
Switched to branch 'master'
# remove everything except .git
me@laptop:~/Desktop/proj$ rm -rfv !(".git")
rm: refusing to remove '.' or '..' directory: skipping '.'
rm: refusing to remove '.' or '..' directory: skipping '..'
removed 'file_1.py'
removed 'file_2.py'
# copy everything except .git from temp (checked out at 49a732c) into working directory
# (so working directory is identical to project at commit 49a732c)
me@laptop:~/Desktop/proj$ cp -nr ../temp/* ./
# make new commit identical to project state at 49a732c
me@laptop:~/Desktop/proj$ git add *
me@laptop:~/Desktop/proj$ git add -u
me@laptop:~/Desktop/proj$ git commit -m “Restore project to commit 49a732c.”
[master 2b6416c] Restore project to commit 49a732c.
3 files changed, 18 deletions(-)
# remove temp
me@laptop:~/Desktop/proj$ rm -rf ../temp
# new commit 2b6416c is now identical to 49a732c
Alternatively, if branching is the best way to do this, is there a sequence of commands that will always work and won't yield any merge conflicts or tell you to use git stash (assuming current working directory is clean)? 或者,如果分支是执行此操作的最佳方法,是否有一系列命令将始终有效并且不会产生任何合并冲突或告诉您使用git stash(假设当前工作目录是干净的)?
To create a new commit, restoring the content of an old commit, you can: 要创建新的提交,还原旧提交的内容,您可以:
First, mark the current HEAD of your branch (assuming master
here): we will need to move that HEAD without modifying master
, so let's create a new temporary branch called ' tmp
' where master
is. 首先,标记您分支的当前HEAD(此处为
master
):我们将需要移动该HEAD 而不修改master
,因此让我们在master
所在的位置创建一个名为“ tmp
”的新临时分支。
git checkout master git checkout -b tmp
(yes, that is against the "without branching" of the question, but you will delete that tmp branch soon) (是的,这与问题的“无分支”相反,但是您将很快删除该tmp分支)
Then we go back to an older commit with the right content. 然后,我们返回内容正确的旧提交。
git reset --hard <old_commit>
That resets the index (and working tree) to the right content, but that also moves HEAD. 这会将索引(和工作树)重置为正确的内容,但同时也会移动HEAD。 However, that moves
tmp
HEAD, not master
HEAD. 但是,这会移动
tmp
HEAD,而不是master
HEAD。
move back tmp
HEAD to where master
is, but without modifying the index or the working tree (which are representing what we need for a new commit) 将
tmp
HEAD移回master
所在的位置,但不修改索引或工作树(这表示我们需要进行新的提交)
git reset --soft master
make a new commit, on top of master
/ tmp
HEAD, which represents the right content (the old commit). 在
master
/ tmp
HEAD顶部进行一次新提交,代表正确的内容(旧提交)。
git commit -m "new commit, image of an old one"
Finally, force master
to be where tmp
is: one new commit later. 最后,迫使
master
成为tmp
所在的位置:稍后再进行一次新提交。
git branch -M tmp master git checkout master git branch -d tmp
Now a regular git push
is enough, any collaborator can simply pull as usual, and still get the old reset content. 现在,常规的
git push
就足够了,任何协作者都可以像往常一样简单地进行拉动,并且仍然可以获取旧的重置内容。
git push
In situation when you want to return to some state you do following: 在要返回某种状态的情况下,请执行以下操作:
git reset --hard 49a732c
This step put your master
branch into desired state. 此步骤将您的
master
分支置于所需状态。 If you want to save you previous branch state: 如果要保存以前的分支状态:
git checkout 48ah14s -b archive/my-unrecognized-experiments
You still can do it after reset because reset doesn't delete commits. 重置后您仍然可以执行此操作,因为重置不会删除提交。
PS Branching is essential part of git. PS分支是git必不可少的部分。 It is better to teach branching then teach such complicated (in git) things as you pictured.
最好先讲授分支,然后再讲授您所想象的复杂(以git为单位)的事物。
EDIT If you want your master
to stay consistent with remotes: 编辑如果您希望您的
master
与遥控器保持一致:
git reset 49a732c # move HEAD back, all changes still in working tree
git commit -am "My unrecognized experiments" # save all changes as one commit
git reset --hard 48ah14s # restore master HEAD
git revert <hash of my unrecognized experiments> # apply reverted changes to master
Assuming you start from a clean worktree, you could do: 假设您从干净的工作树开始,则可以执行以下操作:
cd <root_directory_of_your_repo>
git checkout master
git checkout 49a732c -- .
When you specify a file (in this case .
(the root directory of your repo)) as an argument to git checkout
, the checkout will not switch branch (the repo HEAD
will remain the same). 当您指定一个文件(在这种情况下是
.
(仓库的根目录))作为git checkout
的参数时,结帐不会切换分支(仓库HEAD
将保持不变)。 It will just update the index to make that file match the version of that file from the specified commit. 它只会更新索引,以使该文件与指定提交中的文件版本相匹配。 Since you specified the root directory of the repo, all files in the index will be updated to match the specified commit
49a732c
由于您已指定存储库的根目录,因此索引中的所有文件都将更新以匹配指定的提交
49a732c
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.