我正在尝试采取一个更改的分支,并将其恢复为与其分离的上游相同。这些更改都是本地的,并且已被推送到github,因此git reset
或git rebase
都不可行,因为它们会更改历史记录,这对于已经被推送的分支来说是一件坏事。
我也尝试了git merge
各种策略,但没有一个撤消本地更改,即如果我添加了文件,合并可能会使其他文件重新排队,但我仍然会上游没有的文件。
我可以在上游创建一个新的分支,但我真的很喜欢合并,在修订历史方面应用所有更改来获取我的分支并使其与上游相同,以便我可以安全在不破坏历史的情况下推动这一变革。是否有这样的命令或一系列命令?
答案 0 :(得分:90)
您可以将上游分支合并到dev
分支,并使用自定义合并驱动程序“keepTheirs”:
请参阅““git merge -s theirs
” needed — but I know it doesn't exist”
在您的情况下,只需要一个.gitattributes
和一个keepTheirs
脚本,如:
mv -f $3 $2
exit 0
git merge --strategy=theirs
模拟#1 显示为合并,上游为第一个父级。
Jefromi提及(在评论中){{1}},将您的工作合并到上游(或从上游开始的临时分支),然后将您的分支快速转发到结果合并:
merge -s ours
这有利于将上游祖先记录为第一个父级,因此合并意味着“吸收这个过时的主题分支”而不是“销毁此主题分支并将其替换为上游”< /强>
(编辑2011):
此工作流程已在此blog post by the OP中报告:
为什么我又想要这个?
只要我的回购与公共版本无关,这一切都很好,但从现在开始我想要与其他团队成员和外部贡献者一起使用WIP,我想确保我的公共分支对于其他人来说是可靠的分支和拉动,即不再对我推送到远程备份的东西进行重新设置和重置,因为它现在已经在GitHub上公开了。
这样我就可以继续了。
99%的时间我的副本将进入上游主人,所以我想工作我的主人并在大多数时间进入上游。
但每隔一段时间,我在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
的某些部分。 此时我想让我的主人与上游同步,但不会破坏我公开推送的主人的任何提交点。即我希望与上游合并,最后使用变更集,使我的副本与上游相同 这就是wip
应该做的事情。
git merge --strategy=theirs
模拟#2 显示为合并,将我们作为第一个父级。
(由jcwenger提议)
git merge --strategy=theirs
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
有时候你确实想要这样做,而不是因为你的历史记录中有“废话”,但可能是因为你想在公共存储库中更改开发基线而应该避免重新定位
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 (由Barak A. Pearlmutter提议):
git merge --strategy=theirs
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 (由同一Michael Gebetsroither提出):
Michael Gebetsroither插话说声称我在“作弊”;并且给出了另一个低层管道命令的解决方案:(如果使用git only命令无法实现git,那么使用diff / patch / apply的git中的所有内容都不是真正的解决方案;)。
git merge --strategy=theirs
答案 1 :(得分:12)
听起来像你只需要这样做:
$ git reset --hard origin/master
如果上游没有变化,你只想让上游分支成为你当前的分支,那么就可以做到这一点。在本地执行此操作无害但您将丢失尚未被推送到主人的任何本地更改**。
**实际上,如果您已在本地提交更改,则更改仍然存在,因为提交仍将在您的git reflog
中,通常至少30天。
答案 2 :(得分:12)
你现在可以很容易地做到这一点:
$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs
这会使您的本地仓库与原点同步,并保留历史记录。
答案 3 :(得分:5)
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
答案 4 :(得分:3)
还有一种方法几乎没有管道命令的帮助 - 恕我直言最直截了当。假设你想模仿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
这使用其中一个的树(上例中的栏,提供'他们的'树)合并任意数量的头(上例中为2),忽略任何差异/文件问题(commit-tree是低级命令) ,所以它不关心那些)。请注意,头部可以只有1个(相当于樱桃挑选“他们的”)。
注意,首先指定哪个父头会影响某些内容(例如参见git-log命令的--first-parent) - 所以请记住这一点。
除了git-show之外,还可以使用任何其他能够输出树和提交哈希的东西 - 无论用什么用于解析(cat-file,rev-list,...)。您可以使用git commit --amend来跟踪所有内容,以交互方式美化提交消息。
答案 5 :(得分:1)
更改为远程上游分支并执行git merge
并将合并策略设置为ours
。
git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push
所有历史记录仍然存在,但您将有额外的合并提交。这里重要的是从你想要的版本开始,并将ours
与分支github实际合并。
答案 6 :(得分:1)
重手,但地狱,可能会出错?
答案 7 :(得分:1)
您可以使用git reset
使分支看起来像任何其他提交一样,但是必须以一种绕行方式进行。
要使提交<old>
上的分支看起来像提交<new>
,您可以
git reset --hard <new>
以使<new>
成为工作树的内容。
然后做
git reset --mixed <old>
将分支更改回原始提交,但将工作树保留在 <new>
状态中。
然后,您可以添加并提交更改,以使您的分支与<new>
提交的内容完全匹配。
要从<old>
状态转到<new>
,这是违反直觉的,您需要从{strong> git reset
开始执行<new>
>转到 <old>
。但是,使用选项--mixed
时,工作树保留在<new>
处,并且分支指针设置为<old>
,因此,在提交更改后,分支将显示我们想要的样子。
不要忘记您的提交,例如忘记<old>
是什么git reset --hard <new>
。
答案 8 :(得分:0)
我遵循这些角色:
获取原点,从分支上进行硬重置,然后从分支上递归,然后强制推送到分支
风险自负
git fetch origin
git reset --hard origin/<branch>
git merge origin/<branch> -s recursive -Xtheirs
git push -f <remote> <branch>