用于使一个分支像另一个分支的git命令

问题描述 投票:70回答:9

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

我也尝试过git merge各种策略,但是它们都不能撤消本地更改,即,如果我添加了一个文件,则合并可能会使其他文件恢复原状,但我仍然会拥有该文件上游没有。

我可以在上游创建一个新分支,但是我真的很想合并,就修订历史而言,所有更改都将应用到我的分支中,并使它再次与上游相同,以便我可以安全地推送改变而不会破坏历史。有这样的命令或一系列命令吗?

git github branching-and-merging
9个回答
94
投票

您可以使用自定义合并驱动程序“ keepTheirs”]将上游分支合并到dev分支:参见“ git merge -s theirs” needed — but I know it doesn't exist”。在您的情况下,只需要一个git merge -s theirs,并且需要一个.gitattributes脚本,例如:

keepTheirs

[mv -f $3 $2 exit 0 模拟#1

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

[git merge --strategy=theirs通过在上游(或从上游开始的临时分支)上合并您的工作,然后将分支快速转发到该合并的结果来提及(在注释中)Jefromi

merge -s ours

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

(编辑2011):

此工作流已在此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 中报告:

为什么我要再来一次?

只要我的存储库与公开版本无关,那很好,但是从现在起,我希望能够与其他团队成员和外部贡献者一起在WIP上进行合谋,我想确保我的公开分支对于其他人来说是可靠的分支和分支机构,即不再需要对我推送到远程备份的内容进行重新设置和重置,因为它已经在GitHub和Public上了。

所以这让我有了前进的方向。我的副本有99%的时间会进入上游母版,因此我想工作大部分时间并推入上游。但是每隔一段时间,blog post by the OP中的内容将因进入上游的内容而失效,并且我将放弃wip的某些部分。那时,我想使我的主服务器与上游保持同步,但不破坏公开推送的主服务器上的任何提交点。即我想要与上游合并,最后合并更改集,使我的副本与上游相同

。这就是wip应该执行的操作。

[git merge --strategy=theirs模拟#2

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

git merge --strategy=theirs提议)

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 模拟#3

git merge --strategy=theirs

blog post mentions

有时您确实想这样做,不是因为您的历史记录中有“废话”,而是也许是因为您想更改公共存储库中的开发基准,应避免重新设置基础]]。


[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 模拟#4

(同一篇博客文章)

或者,如果要使本地上游分支保持可快速转发,则可能的折衷办法是了解以下情况:对于sid / unstable,上游分支可以不时地进行重置/重新设置(基于最终超出了上游项目方面的控制范围)。这没什么大不了的,使用该假设意味着可以很容易地将本地上游分支保持在仅需要快速更新的状态。

git merge --strategy=theirs

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 模拟#5

([git merge --strategy=theirs提议):

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 模拟#6

(由相同的git merge --strategy=theirs提议:

[Michael Gebetsroither插话,声称我在“作弊”;)并给出了另一种使用低级管道命令的解决方案:

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

Michael Gebetsroither

[# 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 模拟#7

必要的步骤可以描述为:

  1. 用上游替换您的工作树
  2. 将更改应用于索引
  3. 添加上游作为第二父级
  4. 提交
  5. 命令git merge --strategy=theirs用另一棵树覆盖索引,从而完成第二步骤,并且具有更新工作树的标志,从而完成第一步

。提交时,git使用.git / MERGE_HEAD中的SHA1作为第二个父级,因此我们可以填充它以创建合并提交。因此,可以通过以下方法实现:
git read-tree

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

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

如果没有任何更改可推动上游,而您只是希望上游分支成为您的当前分支,则可以做到这一点。在本地进行此操作无害但是

您将丢失尚未推送到主服务器的任何本地更改**。

**实际上,如果您在本地提交更改,更改仍然存在,因为提交仍将保存在您的$ git reset --hard origin/master 中,通常至少30天。

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

git reflog

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

[C0的另一模拟:

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

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

git merge -s theirs ref-to-be-merged

还有一种几乎不需要管道命令的方法-恕我直言,最简单的方法。假设您要为2个分支案例模拟“他们的”:

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

这会使用其中之一的树(上面示例中的条形图,提供“他们的树”)合并任意数量的头(在上面的示例中为2),而不考虑任何差异/文件问题(commit-tree是低级命令,因此它不在乎那些)。请注意,head只能是1(因此等同于“ theirs”的“ pick-pick”)。

[请注意,首先指定哪个父级头会影响某些内容(例如,请参见git-log命令的--first-parent)-请记住这一点。

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

重手,但地狱,可能会出什么问题吗?

  • 签出要看起来像Y的分支X
  • cp -r .git / tmp
  • 签出分支Y
  • rm -rf .git && cp -r /tmp/.git。
  • 提交并推动任何差异
  • 完成。
  • 更改到远程上游分支,并在git diff --binary ref-to-be-merged | git apply -R --index 中将合并策略设置为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

    git merge

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

    使用git reset向后!

    您可以使用git checkout origin/master git merge dev --strategy=ours git commit ... git push 使分支看起来像任何其他提交,但必须以一种绕行方式进行。

    要使提交ours上的分支看起来像提交git reset,可以执行

    <old>

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

    然后做

    git reset --hard <new>
    

    将分支改回原始提交但将工作树留在

    <new>状态

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

    与直觉相反,要从<new>状态转换为<new>,您需要执行<old> from

    <new>to git reset。但是,使用选项<new>时,工作树保留在<old>处,并且分支指针设置为--mixed,以便在提交更改后,分支看起来像我们想要的。

    警告

    [不要忘记您的提交,例如<new>时忘记<old>是什么。

    我担任过这些角色:

    获取原点,从分支硬复位,然后从分支递归,然后强行推送到分支

    有您自己的风险

    <old>

    13
    投票

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


    12
    投票

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


    5
    投票

    [C0的另一模拟:


    3
    投票

    还有一种几乎不需要管道命令的方法-恕我直言,最简单的方法。假设您要为2个分支案例模拟“他们的”:


    2
    投票

    重手,但地狱,可能会出什么问题吗?


    1
    投票

    更改到远程上游分支,并在git diff --binary ref-to-be-merged | git apply -R --index 中将合并策略设置为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


    1
    投票

    使用git reset向后!


    0
    投票

    我担任过这些角色:

    © www.soinside.com 2019 - 2024. All rights reserved.