git命令使一个分支像另一个分支

w8ntj3qf  于 2023-04-10  发布在  Git
关注(0)|答案(9)|浏览(174)

我尝试将一个有变化的分支恢复到与它的上游分支相同。这些变化都是本地的,并且已经被推送到github,所以git resetgit rebase都不是真正可行的,因为它们改变了历史,这对于已经被推送到github的分支来说是一件坏事。
我也尝试过git merge的各种策略,但没有一个撤消本地更改,即如果我添加了一个文件,合并可能会使其他文件回到行中,但我仍然有上游没有的文件。
我可以在上游创建一个新的分支,但是我真的很想一个合并,在修订历史方面应用所有的更改来获取我的分支,并使其再次与上游相同,这样我就可以安全地推送更改而不破坏历史。有这样的命令或命令系列吗?

aiazj4mn

aiazj4mn1#

您可以使用**自定义合并驱动“keepTheirs”**将上游分支合并到dev分支:
请参阅“需要git merge -s theirs-但我知道它不存在”。
在您的例子中,只需要一个.gitattributes,以及一个keepTheirs脚本,如下所示:

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

这样做的好处是将上游祖先记录为第一个父分支,因此合并意味着“吸收这个过时的主题分支”,而不是“销毁这个主题分支并用上游替换它”
2023年更新:例如,如果你想让main准确地反映dev是什么:

git switch -c tmp dev
git merge -s ours main   # ignoring all changes from main
git switch main
git merge tmp            # fast-forward to tmp HEAD, which is dev
git branch -D tmp        # deleting tmp

(Edit 2011年):
此工作流已在此blog post by the OP中报告:
为什么我又想要这个?
只要我的repo与公共版本无关,这一切都很好,但因为现在我希望能够与其他团队成员和外部贡献者在WIP上进行校对,我想确保我的公共分支对于其他人来说是可靠的,可以从分支中提取,即不再对我推到远程备份的东西进行rebase和重置,因为它现在在GitHub上并且是公共的。
所以剩下的就是我该怎么做了。
99%的情况下,我的副本会进入上游母版,所以我想在大部分时间里工作我的母版并推进到上游。
但是每隔一段时间,我在wip中的内容就会被进入上游的内容无效,我将放弃我的wip的一部分。

此时,我希望将master恢复到与upstream同步,但不破坏我的公开推送master上的任何提交点。即,我希望与upstream合并,最终合并的变更集使我的副本与upstream相同

这就是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

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

有时候你确实想这么做,并不是因为你的历史中有“垃圾”,而是也许是因为你想改变公共存储库中的开发基线,而在公共存储库中应该避免rebase

git merge --strategy=theirs模拟#4

(same博客文章)
或者,如果你想保持本地上游分支的快速转发,一个潜在的妥协是理解对于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插话,声称我在“作弊”;),并给出了另一个使用较低级别的管道命令的解决方案:
(it如果git only命令不可能实现,那就不是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.用upstream替换你的工作树
1.将更改应用于索引
1.将上游添加为第二个父级
1.提交
命令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
qacovj5a

qacovj5a2#

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

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

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

1tuwyuhd

1tuwyuhd3#

听起来你只需要做:

$ git reset --hard origin/master

如果没有要向上游推送的更改,而你只是想让上游分支成为你的当前分支,这将做到这一点。在本地做这件事并没有害处但是你将丢失任何尚未推送到master的本地更改**。

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

qhhrdooz

qhhrdooz4#

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
5ssjco0h

5ssjco0h5#

还有一种方法,几乎没有管道命令的帮助-恕我直言,最直接的。说你想模仿“他们的”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

这会合并任意数量的head(在上面的例子中为2),使用其中一个head的tree(在上面的例子中bar,提供'their' tree),忽略任何diff/file问题(commit-tree是低级命令,所以它不关心这些)。注意head可以是1(所以相当于cherry-pick with“their”)。
请注意,首先指定哪个父头会影响一些东西(例如,请参阅git-log命令的--first-parent)-因此请记住这一点。
除了git-show,任何能够输出树和提交哈希的东西都可以使用-无论是用来解析的(cat-file,rev-list,...)。你可以使用git commit --amend来交互地美化提交消息。

5uzkadbs

5uzkadbs6#

严厉的,但地狱,什么可能出错?

  • 检查出分支X你想看起来像Y
  • cp -r .git /tmp
  • checkout 分支Y git checkout y
  • rm -rf .git && cp -r /tmp/.git
  • 承诺并推动任何差异
  • 完成。
yqyhoc1h

yqyhoc1h7#

切换到远程上游分支并执行git merge,合并策略设置为ours

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

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

mctunoxg

mctunoxg8#

使用git reset BACKWARDS!

你可以用git reset使一个分支看起来像任何其他的提交,但是你必须以一种迂回的方式来做。
要使提交<old>上的分支看起来像提交<new>,可以执行以下操作

git reset --hard <new>

以使<new>成为工作树的内容。
那就做吧

git reset --mixed <old>

将分支更改回原始提交**,但将工作树保留在**<new>状态
然后,您可以添加并提交更改,以使您的分支与<new>提交的内容完全匹配。
<old>状态转移到<new>状态,需要执行git resetfrom<new>to<old>,这是违反直觉的。然而,使用--mixed选项,工作树留在<new>,分支指针设置为<old>,因此当提交更改时,分支看起来像我们想要的那样。

警告

不要忘记你的提交,例如,在执行git reset --hard <new>时忘记<old>是什么。

zpf6vheq

zpf6vheq9#

我扮演了这些角色:
从分支中获取,硬重置,然后从他们的分支中递归,然后强制推送到分支

风险自负

git fetch
git reset --hard <branch>
git merge <branch> -s recursive -X theirs
git push -f <remote> <branch>

相关问题