88

我正在尝试采用更改的分支并将其恢复为与它分歧的上游相同。这些更改都是本地的并且已被推送到 github,因此既不可行,git reset也不git rebase真正可行,因为它们更改了历史记录,这对于已经推送的分支来说是一件坏事。

我也尝试git merge过各种策略,但它们都没有撤消本地更改,即如果我添加了一个文件,合并可能会使其他文件重新排列,但我仍然会拥有上游没有的那个文件有。

我可以从上游创建一个新分支,但我真的很想要一个合并,在修订历史方面应用所有更改以获取我的分支并再次使其与上游相同,以便我可以安全地推送该更改没有破坏历史。是否有这样的命令或一系列命令?

4

9 回答 9

119

您可以使用自定义合并驱动程序“keepTheirs”将上游分支合并到您的dev分支: 请参阅“需要“<code>git merge -s theirs” - 但我知道它不存在”。 在您的情况下,只需要一个,并且脚本如下:

.gitattributeskeepTheirs

mv -f $3 $2
exit 0

git merge --strategy=theirs模拟#1

显示为合并,上游为第一个父级。

Jefromi提到(在评论中)merge -s ours,通过合并您在上游(或从上游开始的临时分支)上的工作,然后将您的分支快速转发到该合并的结果:

git checkout -b tmp origin/upstream
git merge -s ours downstream         # ignoring all changes from downstream
git checkout downstream
git merge tmp                        # fast-forward to tmp HEAD
git branch -D tmp                    # deleting tmp

这样做的好处是将上游祖先记录为第一个父级,因此合并意味着“吸收这个过时的主题分支”而不是“销毁这个主题分支并用上游替换它”

(2011 年编辑):

OP在此博客文章中报告了此工作流程:

为什么我又想要这个?

只要我的 repo 与公共版本无关,这一切都很好,但是现在我希望能够与其他团队成员和外部贡献者在 WIP 上进行协作,我想确保我的公共分支是对于其他人来说是可靠的分支和拉取,即不再对我推送到远程备份的内容进行变基和重置,因为它现在在 GitHub 和公共上。

所以这让我知道我应该如何进行。
99% 的时间我的副本会进入上游 master,所以我想在大部分时间工作我的 master 并推送到上游。
但是每隔一段时间,我所拥有的wip就会被上游的东西失效,我会放弃我的wip.
那时我想让我的主服务器与上游同步,但不破坏我公开推送的主服务器上的任何提交点。即我想要与上游合并,最终得到使我的副本与上游相同的变更集
这就是git merge --strategy=theirs应该做的。


git merge --strategy=theirs模拟#2

显示为合并,我们的作为第一个父项。

(由jcwenger提议)

git checkout -b tmp upstream
git merge -s ours thebranch         # ignoring all changes from downstream
git checkout downstream
git merge --squash tmp               # apply changes from tmp but not as merge.
git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head
git commit -m "rebaselined thebranch from upstream" # make the commit.
git branch -D tmp                    # deleting tmp

git merge --strategy=theirs模拟#3

这篇博文提到

git merge -s ours ref-to-be-merged
git diff --binary ref-to-be-merged | git apply -R --index
git commit -F .git/COMMIT_EDITMSG --amend

有时您确实想要这样做,并不是因为您的历史记录中有“废话”,而是可能是因为您想更改公共存储库中的开发基线,应该避免变基


git merge --strategy=theirs模拟#4

(同一篇博文)

或者,如果您想保持本地上游分支可快速转发,一个潜在的折衷方案是理解对于 sid/unstable,上游分支可以不时重置/重新设置(基于最终退出的事件)您对上游项目的控制权)。
这没什么大不了的,使用这个假设意味着很容易将本地上游分支保持在只需要快速更新的状态。

git branch -m upstream-unstable upstream-unstable-save
git branch upstream-unstable upstream-remote/master
git merge -s ours upstream-unstable
git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*"
git commit -F .git/COMMIT_EDITMSG --amend

git merge --strategy=theirs模拟#5

(由Barak A. Pearlmutter 提议):

git checkout MINE
git merge --no-commit -s ours HERS
git rm -rf .
git checkout HERS -- .
git checkout MINE -- debian # or whatever, as appropriate
git gui # edit commit message & click commit button

git merge --strategy=theirs模拟#6

(由同一个Michael Gebetsroither提出):

Michael Gebetsroither 插话,声称我在“作弊”;)并给出了另一个解决方案,其中包含较低级别的管道命令:

(如果仅使用 git 命令无法实现,那它就不是 git,git 中带有 diff/patch/apply 的所有内容都不是真正的解决方案;)。

# get the contents of another branch
git read-tree -u --reset <ID>
# selectivly merge subdirectories
# e.g superseed upstream source with that from another branch
git merge -s ours --no-commit other_upstream
git read-tree --reset -u other_upstream     # or use --prefix=foo/
git checkout HEAD -- debian/
git checkout HEAD -- .gitignore
git commit -m 'superseed upstream source' -a

git merge --strategy=theirs模拟#7

必要的步骤可以描述为:

  1. 用上游替换你的工作树
  2. 将更改应用到索引
  3. 添加上游作为第二个父级
  4. 犯罪

该命令git read-tree用不同的树覆盖索引,完成第二步,并具有更新工作树的标志,完成第一步。提交时,git 使用 .git/MERGE_HEAD 中的 SHA1 作为第二个父级,因此我们可以填充它来创建合并提交。因此,这可以通过以下方式完成:

git read-tree -u --reset upstream                 # update files and stage changes
git rev-parse upstream > .git/MERGE_HEAD          # setup merge commit
git commit -m "Merge branch 'upstream' into mine" # commit
于 2011-02-06T08:03:35.410 回答
13

在我看来,您只需要这样做:

$ git reset --hard origin/master

如果推送上游没有任何变化,而您只是希望上游分支成为您的当前分支,则可以这样做。在本地执行此操作无害,您将丢失任何尚未推送到 master 的本地更改**。

** 实际上,如果您已在本地提交更改,这些更改仍然存在,因为提交仍将在您的 中git reflog,通常至少 30 天。

于 2011-02-06T08:13:27.287 回答
13

你现在可以很容易地做到这一点:

$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs

这会使您的本地存储库与源同步,并保留历史记录。

于 2012-11-16T04:30:58.767 回答
7

另一个模拟git merge -s theirs ref-to-be-merged

git merge --no-ff -s ours ref-to-be-merged         # enforce a merge commit; content is still wrong
git reset --hard HEAD^2; git reset --soft HEAD@{1} # fix the content
git commit --amend

双重重置的替代方法是应用反向补丁:

git diff --binary ref-to-be-merged | git apply -R --index
于 2014-02-01T13:27:52.693 回答
4

还有一种方法几乎没有管道命令的帮助 - 恕我直言,最直接的。假设您想为 2 个分支案例模拟“他们的”:

head1=$(git show --pretty=format:"%H" -s foo)
head2=$(git show --pretty=format:"%H" -s bar)
tree=$(git show --pretty=format:"%T" -s bar)
newhead=$(git commit-tree $tree -p $head1 -p $head2 <<<"merge commit message")
git reset --hard $newhead

这使用其中一个的树(上例中的 bar,提供“他们的”树)合并任意数量的头(上例中的 2 个),忽略任何差异/文件问题(提交树是低级命令,所以它不在乎那些)。请注意,head 可以仅为 1(因此相当于带有“theirs”的cherry-pick)。

请注意,首先指定哪个父头会影响一些东西(例如,请参阅 git-log 命令的 --first-parent ) - 所以请记住这一点。

可以使用任何其他能够输出树和提交哈希的东西来代替 git-show - 任何用于解析的东西(cat-file,rev-list,...)。您可以使用 git commit --amend 跟踪所有内容,以交互美化提交消息。

于 2012-09-06T13:22:35.617 回答
2

重手,但见鬼,有什么可能出问题的?

  • 查看你想要看起来像 Y 的分支 X
  • cp -r .git /tmp
  • 检查分支 Ygit checkout y
  • rm -rf .git && cp -r /tmp/.git.
  • 提交并推动任何差异
  • 完毕。
于 2017-03-06T12:40:48.160 回答
1

更改到远程上游分支并执行git merge合并策略设置为ours.

git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push

所有历史记录仍将存在,但您将有一个额外的合并提交。这里重要的是从你想要的版本开始,并ours与 github 实际所在的分支合并。

于 2011-02-06T05:41:56.657 回答
1

使用 git reset BACKWARDS!

您可以使用 使分支看起来像任何其他提交git reset,但您必须以一种迂回的方式进行。

要使提交时的分支<old>看起来像提交<new>,您可以这样做

git reset --hard <new>

为了制作<new>工作树的内容。

然后做

git reset --mixed <old> 

将分支更改回原始提交,但将工作树保持在 <new> 状态

然后您可以添加并提交更改,以使您的分支与<new>提交的内容完全匹配。

<old>state 移动到 the<new>你需要执行git reset from <new> to <old>是违反直觉的。但是,使用该选项--mixed,工作树将保留在<new>,并将分支指针设置为<old>,以便在提交更改时,分支看起来像我们想要的那样。

警告

不要忘记你的提交,例如忘记<old>做什么git reset --hard <new>

于 2018-10-31T10:12:36.670 回答
0

我遵循了这些角色:

获取原点,从分支硬重置,然后从他们的递归,然后强制推送到分支

风险自负

git fetch origin
git reset --hard origin/<branch>
git merge origin/<branch> -s recursive -Xtheirs
git push -f <remote> <branch>
于 2019-02-12T10:35:23.490 回答