【问题标题】:git - revert branch to look like master?git - 恢复分支看起来像主人?
【发布时间】:2016-11-02 03:08:09
【问题描述】:

我有两个分支developmaster。开发中有很多提交不在master 中。虽然我需要让develop 分支看起来与master 完全相同。为了保留发生在develop 中的所有更改,我将从develop 创建新分支,这样所有这些更改都不会丢失。

但是在“复制”develop 之后,我怎样才能安全地重置或恢复为 master 的样子?

我看到了这个:Git: reset/revert a whole branch to another branches state?

所以要重置,我可以这样做:

git checkout develop
git reset --hard master

但问题是develop 分支已经被推送到远程,还有其他人已经拉了develop

也许有更安全的方法可以使用 revert 或其他方式来做到这一点?但我想以一种可以恢复到 master 状态的方式恢复(如果可能),而不是手动选择每个提交,因为一些最新的提交需要保存在 develop 中,因为它们来自主服务器(修补程序)。

所以develop 上的提交历史看起来像这样(最上面的意思是按日期的最新提交):

commit hotfix2 - in both develop and master
some other commits that are only in develop
commit hotfix1 - in both develop and master
some commits that are only in develop
all commits that came when develop was created from master

【问题讨论】:

  • 那么,您要做的是撤消所有仅在开发中完成的提交? (例如,撤消历史记录中的“一些提交”和“一些其他提交”)
  • @poke 好吧,是的,但是有没有比完成所有提交并选择我需要撤消的提交更简单的方法?这只是一个示例,在实际情况下,有很多提交需要撤消,并且中间有一些提交需要保留。使用reset,很简单,我只需指定分支,它就会重置为与master 完全一样。

标签: git branch git-reset git-revert


【解决方案1】:

以非破坏性方式撤消提交的标准过程是使用git revert。该命令基本上采用目标提交的反转差异并尝试应用它。因此,您将获得一个撤消所有更改的新提交。

为了一次撤消多个提交,您还可以指定一个提交范围。鉴于您只有两个要撤消的范围(位于这些修补程序之间的范围),这实际上是可以管理的。

您也可以使用标志--no-commit-n自动创建提交。这允许您一个接一个地链接多个git revert -n <commit> 命令,而无需为每个命令创建还原提交。然后,当您选择完所有要撤消的提交或提交范围后,您可以进行一次合并所有提交的提交。

在您的情况下,由于您有另一个具有您想要将 develop 分支放入的确切(工作目录)状态的分支,因此执行此操作要容易得多。您所要做的就是将master 的工作树检出到您的develop 分支并将该状态提交到develop 分支。您可以使用git checkout master -- . 执行此操作。不幸的是,这不适用于master 分支未知的路径。因此,如果您在 develop 分支中添加了新文件,这些文件将被保留,您必须单独删除它们。

相反,我们从master 开始一个新分支(然后具有完全相同的内容),并重置该分支,使其改为基于develop。这样,我们将工作目录状态从master 保留下来,但提交将遵循develop。之后,我们可以快进develop 那一次提交:

# checkout a new branch off master
git checkout -b new-develop master

# make a soft reset to develop
git reset --soft develop

# commit the changes
git commit

# get back to develop and fast forward
git checkout develop
git merge --ff-only new-develop
git branch -d new-develop

这将导致与git revert -ndevelop 独有的所有提交链接所获得的结果相同。还有其他几种方法可以达到这种状态,但这确实是最简单的。

无论您使用哪种方式达到此状态,您都应该考虑在之后进行合并。合并实际上不会做任何事情(因为两个分支具有相同的内容),但它将合并历史中的分支,因此您会看到它们实际上是收敛的。

所以假设历史最初看起来是这样的:

                       master
                         ↓
* ------------ h1 ------ h2
 \              \         \
  * -- * -- * -- * -- * -- *
                           ↑
                         develop

你想把它变成这样:

                                master
                                  ↓
* ------------ h1 ------ h2 ----- M
 \              \         \      /  ↖
  * -- * -- * -- * -- * -- * -- F   develop

F 是我们在上面创建的修复提交。这假设您希望将 develop 合并到 mastergit merge develop 而在 master)然后快进 developgit merge master 而在 develop)以重新开始开发工作那一点。当然,如果你愿意,你也可以朝另一个方向做。

或者,我们也可以在一个步骤中合并M 和修复F。您将有效地将develop 合并到master 中,并以您最终得到master 的内容的方式合并所有内容。这看起来像这样:

                                master
                                  ↓
* ------------ h1 ------ h2 ---- FM
 \              \         \      /  ↖
  * -- * -- * -- * -- * -- * ---/   develop

你可以像这样手动到达那里:

# since we merge into master, we start there
git checkout master

# start the merge, but don’t attempt to fast-forward and do not
# commit the merge automatically (since we want to change it)
git merge --no-ff --no-commit develop

# reset the index that was prepared during the merge
git reset

# now checkout the files from master and commit the merge
git checkout master -- .
git add .
git commit

实际上,这是一个非常常见的场景,git merge 附带了一个可以完全做到这一点的合并策略。因此,我们可以使用ours 合并策略代替上面的方法,并丢弃我们合并到当前分支中的任何内容:

git checkout master
git merge -s ours develop

【讨论】:

  • 嗯,我试过了,但似乎无法撤消develop。它只撤消在masterdevelop 中更改的文件。但是有很多文件只添加到develop,而不是master。这些都被保留了。因此,当我检查完develop,然后当我将develop 合并到master 中时,它实际上会将所有这些文件添加到master 中。我在这里错过了什么吗?我需要手动删除所有这些文件并提交吗?
  • 您尝试了哪种解决方案?最后一个(使用ours 合并策略)肯定可以工作;对于其他人,您可能需要在git checkout master -- . 之前使用git reset(我忘记了)。合并后,git diff <original-master> 应该什么都不返回,git diff <original-develop> 应该显示许多不再在当前分支上的更改。
  • 这很奇怪,应该可以(假设我对你的历史有正确的认识)。你可以试试最后一个选项吗?如果这不起作用,您可以打开一个chat room 我们可以继续吗?
  • 还有第三个选项 git merge ours 的第三个选项,不要对develop 做任何事情,当我转到master 时,我看到来自develop 的提交,但没有来自开发的文件。这不应该为develop 而不是master 完成吗?在我看来,只有第一个选项才能发挥作用
  • 是的,最后一个选项将develop 合并到master 中,同时放弃任何更改。这样,您可以收敛历史记录,但保留来自 develop 的所有更改(不保留内容)。这会更新master,因此之后您需要将develop 快进到master (git merge master)。
【解决方案2】:

下面的命令将从 origin/master 获取所有文件(当前分支中添加的新文件除外)

git checkout origin/master .

然后,可以使用 git rm 删除新文件例如

git rm newfile

【讨论】:

    猜你喜欢
    • 2020-06-25
    • 1970-01-01
    • 2011-06-21
    • 2021-10-24
    • 1970-01-01
    • 2011-11-08
    • 2017-12-26
    • 2012-07-06
    • 2013-12-27
    相关资源
    最近更新 更多