git reset
和git rebase
不太可行,因为它们会改变历史记录,而分支已经被推送,这是不好的。我还尝试了
git merge
的各种策略,但都无法撤消本地更改。例如,如果我添加了一个文件,合并可能会使其他文件回到原来的状态,但我仍将具有该上游没有的文件。我可以只创建一个新分支,但我真的希望有一种合并方式,可以将所有更改应用于我的分支,使其与上游分支完全相同,以便我可以安全地推送该更改,而不会覆盖历史记录。是否有这样的命令或一系列命令?
git reset
和git rebase
不太可行,因为它们会改变历史记录,而分支已经被推送,这是不好的。git merge
的各种策略,但都无法撤消本地更改。例如,如果我添加了一个文件,合并可能会使其他文件回到原来的状态,但我仍将具有该上游没有的文件。您可以使用自定义合并驱动程序“keepTheirs”将上游分支合并到您的dev
分支中:
请参见 "“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 在评论中提到了 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
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
(编辑于2011年):
这个工作流程已经在OP的博客文章中报道:
为什么我需要这个呢?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中进行差异/补丁/应用程序的所有内容都不是真正的解决方案;)
# 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必要的步骤如下:
- 用上游代码替换你的工作目录
- 将更改应用到索引中
- 将上游代码添加为第二个父级
- 提交
命令
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
git checkout upstream; git merge -s ours downstream; git checkout downstream; git merge upstream
。这种做法的好处是记录了上游祖先作为第一父节点,这样合并的含义就是“吸收这个过时的主题分支”,而不是“销毁这个主题分支并用上游替换它”。 - Cascabel-s theirs
(合并策略)仍不存在。这与合并策略选项-X theirs
(如https://dev59.com/yHrZa4cB1Zd3GeqP57n_#20827745中所述)不同,后者仅用于冲突。 - VonC现在你可以相对容易地做到这一点:
$ git fetch origin
$ git merge origin/master -s recursive -Xtheirs
这将使您的本地仓库与源代码同步,并保留历史记录。
git merge -s recursive -Xtheirs
不会自动合并二进制文件,所以你最终会陷入冲突状态,需要手动解决。而基于git merge -s ours
的工作流则不会遇到这个问题。 - Stefaangit show
仅显示冲突解决方案,如果使用 -Xtheirs
则没有冲突解决方案,这是显而易见的。 - Robin Green我觉得你只需要执行以下操作:
$ git reset --hard origin/master
如果没有需要推送到上游的更改,而您只是想让上游分支成为当前分支,这将实现该目的。在本地执行此操作并不会有害,但您将会失去任何尚未推送到主分支的本地更改;实际上,如果您已经在本地提交了更改,这些更改仍将存在于您的git reflog中,通常至少30天。以下是“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
HEAD^2
)。补丁方法确实起作用了。 - user247702git reset --hard HEAD^^2; git reset --soft HEAD@{1}
- Joshua Walsh还有一种简单的方法,只需使用一些plumbing命令即可 - 在我看来这是最直接的方法。假设您想要模拟两个分支情况下的“theirs”:
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,提供“theirs”树)的树来合并任意数量的头(在上面的示例中为2),忽略任何差异/文件问题(commit-tree是低级命令,因此不关心这些问题)。请注意,头可以只有1个(因此等同于使用“theirs”的cherry-pick)。
请注意,指定哪个父头先指定可能会影响某些内容(例如git-log命令的--first-parent选项)-请记住这一点。
可以使用任何能够输出树和提交哈希的工具(例如cat-file、rev-list等)而不是git-show。您可以跟随git commit --amend以交互式地美化提交消息。
虽然有些粗暴,但是,那又能出什么问题呢?
cp -r .git /tmp
git checkout y
rm -rf .git && cp -r /tmp/.git
.你可以使用 git reset
让一个分支看起来像任何其他提交,但你需要用一种迂回的方式来实现。
要让基于提交 <old>
的分支看起来像提交 <new>
,你可以执行以下操作:
git reset --hard <new>
<new>
变成工作树的内容。git reset --mixed <old>
将分支更改回原始提交,但保留工作树处于<new>
状态。
然后,您可以添加和提交更改,以使您的分支与<new>
提交的内容完全匹配。
令人困惑的是,要从<old>
状态移动到<new>
,您需要在<new>
到<old>
执行git reset
。但是,使用选项--mixed
会将工作树保留在<new>
状态,并将分支指针设置为<old>
,因此当更改被提交时,分支看起来符合我们的要求。
不要失去对提交的跟踪,例如在执行git reset --hard <new>
时忘记<old>
是什么。
git fetch
git reset --hard <branch>
git merge <branch> -s recursive -X theirs
git push -f <remote> <branch>
切换到远程上游分支,并使用合并策略设置为 ours
进行 git merge
。
git checkout origin/master
git merge dev --strategy=ours
git commit ...
git push
所有的历史记录仍将存在,但您将有一个额外的合并提交。这里重要的是从您想要到达的版本开始,并将 ours
与 github 实际所在的分支合并。
--strategy=theirs
,但最接近的 --strategy=recursive -X=theirs
并不能完全做到这一点。 - Arne Claassen--strategy=theirs
这个选项,这就是问题所在。最接近的选项是 --strategy=recursive -X theirs
,但它并不完全相反,因为如果本地更改不冲突,则不会删除多余的本地更改。 - Arne Claassengit checkout dev; git merge origin/master --strategy=ours
和 git checkout origin/master; git merge dev --strategy=ours
。 - wuputahours
策略的存在使得使用theirs
策略完全可行。 - Cascabelours
来模拟 theirs
。我之前不知道我们的合并是一个临时分支,然后我还需要将其合并回我的开发分支。 - Arne Claassen