在Git中切换分支,但不改变工作区文件

5
这与我的另一个问题类似(在不更改工作区文件的情况下切换到另一个分支),但之前可行的解决方案现在已经不适用了。
我需要删除一些变更,这些变更很久以前就被推到了远程主干。所以我不想从主干中删除提交,但我想像这些变更被还原一样更改文件。所以我这样做了:
  1. 在主干上,git branch limits
  2. git checkout limits
  3. git rebase --interactive <要删除的提交之前的提交>
  4. 在交互式控制台中删除我想还原的变更提交
所以现在在limits分支上,我有了像主干中一样的代码。如何将它“移动”到主干分支?使用来自limits的代码,我想更改为master分支,但不更改工作区中的任何文件,以便随后将更改提交为master的新更改。

3
这种情况不是git revert的用法吗? - Carl Norum
是的,我不知道。学习新东西总是好的。尽管如此,我仍然希望我的问题得到回答 :) - amorfis
@CarlNorum,“git revert”是正确的答案,如果您发布该答案,我会点赞。交互式变基会改变历史记录,这是没有必要的,我们都知道更改已推送的历史记录不是一个好主意。 - KurzedMetal
当我发表那个评论时,我正在使用我的iPad;我很乐意将声誉让给那些有时间和精力写更好答案的人。 - Carl Norum
4个回答

6
你所提出的问题的答案是:
$ git checkout master             # switch to master branch

$ git reset --hard limits         # hard-reset it to the limits commit
$ git reset --soft master@{1}     # move the reference back to where it was, but
                                  #  don't modify the working tree or index

这将使你的工作树和索引看起来就像你已经检出了limits一样,但你会停留在原始位置的master分支。
然而,做这样事情的正确方式是撤销每个你想要恢复的更改,使用git revert命令。

5

与其使用交互式变基,您可以只撤销不需要的每个提交。当您使用git revert <object-name-of-commit>时,Git会引入一个新的提交,以撤消您指定的提交所引入的更改。因此,假设您要删除的提交是abc123def456,您只需执行以下操作:

git checkout master
git revert abc123
git revert def456

然而,如果查找这些提交需要很多工作,并且您对limits的最新状态感到满意,您可以在master上创建一个新的提交,其中包含了该状态下的树形结构。首先,确保git status是干净的,因为您将使用git reset --hard,它会清除未提交的更改:
git checkout master
git reset --hard limits
git reset --soft HEAD@{1}
git commit -m "Reverting unwanted commits"

这个配方是此问题中一个变化的版本:


谢谢。HEAD@{1} 是什么意思? - amorfis
1
Git 通过 "reflog" 记录每个引用的历史记录 - foo@{n} 大致意思是 "引用 foon 次更改之前的位置"。如果您想查看 HEAD 的 reflog,只需执行 git reflog 即可了解其情况。请注意,跟踪特定引用的位置完全与提交图所表示的历史记录无关,而这些引用指向提交图。 - Mark Longair
仅供参考:如果我没记错的话,激烈的 HEAD 移动也会在 ORIG_HEAD 引用中保存原始状态,因此可能可以使用它来代替 HEAD@{1} - kostix

1

这是要求使用 revert 命令的 :-)

我会回到主分支,然后使用 git-revert 命令来取消应用你想要撤销的每个提交。 这将为每个提交创建一个“取消应用”提交 - 因此不会更改历史记录,但你会得到想要的效果。


0

移动分支指针

如果你实际上想要做的是在复杂的变基或合并后移动主分支的分支指针到另一个分支,你可以通过多种方式来实现。例如,为了强制移动某个中间分支使其成为新的主分支,你可以执行以下操作之一:

# Use git porcelain to move the branch over top of one that already
# exists.
git branch -M limits master

# Explicitly move the branch pointer to wherever the head for limits
# is pointing.
git reset --hard refs/heads/limits

还有其他方法可以执行各种管道命令,但这并不意味着要详尽无遗地讲解。这应该足以让您朝着正确的方向前进。

撤销提交

正如其他帖子和评论所指出的那样,如果您想要做的只是从主分支中撤销特定的提交,则可以使用git-revert(1)。请注意,这会在您的历史记录中保留原始提交和撤销提交;这通常是您想要的。

此外,请注意,git-revert可能会导致冲突或不良更改,您将不得不手动解决,特别是如果您要撤销的提交不是小型原子更改。将git-revert视为反向补丁(从根本上讲,它就是这样),您就可以看到可能会出现冲突的地方。

您的情况肯定会有所不同。


我知道stash,但它是为未提交的更改而设计的。我没有任何未提交的更改。 - amorfis
1
他想基本上抛弃master并用limits替换其内容,而不仅仅是应用更改。 - Shahbaz
@Shahbaz,从原始问题中并不清楚。按照提出的问题仍然是关于将一个已经变基的分支移动到主分支上,所以我会保留我的答案,但我认为git-revert根本目标的正确解决方案。 - Todd A. Jacobs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接