git 命令使一个分支像另一个分支一样
我正在尝试对一个进行更改的分支并将其恢复到与它所分歧的上游相同。这些更改都是本地的,并且已推送到 github,因此 git reset
或 git rebase
都不是真正可行的,因为它们更改了历史记录,这对于分支来说是一件坏事那已经被推动了。
我还尝试过使用各种策略进行 git merge ,但它们都没有撤消本地更改,即如果我添加了一个文件,合并可能会使其他文件恢复一致,但我仍然会拥有上游没有的文件。
我可以在上游创建一个新分支,但我真的想要一个合并,就修订历史记录而言,应用所有更改来获取我的分支并使其再次与上游相同,以便我可以安全地推送该更改没有破坏历史。有这样的命令或一系列命令吗?
I'm trying to take a branch with changes and bring it back to be identical to the upstream it diverged from. The changes are both local and have been pushed to github, so neither git reset
or git rebase
are really viable, since they change history, which is a bad thing with a branch that's already been pushed.
I've also tried git merge
with various strategies but none of them undo the local changes, i.e. if I'd added a file, a merge might bring other files back in line, but I'll still have that file that the upstream doesn't have.
I could just create a new branch off the upstream, but i'd really like a merge that in terms of revision history applies all the changes to take my branch and make it identical to the upstream again, so that I can safely push that change without clobbering history. Is there such a command or series of commands?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您可以使用自定义合并驱动程序“keepTheirs”将上游分支合并到
dev
分支:请参阅““
git merge -s 他们的
”需要 - 但我知道它不存在”。在您的情况下,只需要一个
.gitattributes
和一个keepTheirs
脚本,例如:git merge --strategy=theirs
模拟 #1< strong>显示为合并,上游作为第一个父级。
Jefromi 提到(在评论中)
merge -s ours
,通过合并上游(或从上游开始的临时分支)上的工作,然后将分支快进到合并的结果:2023 年更新:例如,如果您希望
main
准确反映dev
是什么:(2011 年编辑):
此工作流程已在此 OP 的博客文章:
git merge --strategy=theirs
模拟 #2显示为合并,我们的作为第一个父级。
(由 jcwenger)
git merge --strategy=theirs
模拟#3这个博客文章提及:
git merge --strategy=theirs
模拟#4(同一篇博文)
git merge --strategy=theirs
模拟 #5(由 提出) Barak A. Pearlmutter):
git merge --strategy=theirs
模拟#6(由同一Michael Gebetsroither):
git merge --strategy=theirs 模拟#7
Git 2.44(2024 年第 1 季度)还提出了一种自定义合并驱动程序方法(我在“
git merge -s 他们的
需要,但它不存在”)。自定义合并驱动程序需要访问它们正在处理的修订的名称,以便它们引入的合并冲突标记可以引用这些修订。
用于共同祖先、本地头和其他头的冲突标签可以通过使用占位符“
%S
”、“%X
”和“%Y' 分别。
You could merge your upstream branch to your
dev
branch, with a custom merge driver, "keepTheirs":See "“
git merge -s theirs
” needed — but I know it doesn't exist".In your case, only one
.gitattributes
would be required, and akeepTheirs
script like:git merge --strategy=theirs
Simulation #1Shows as a merge, with upstream as the first parent.
Jefromi mentions (in the comments) the
merge -s ours
, by merging your work on the upstream (or on a temp branch starting from upstream), and then fast-forwarding your branch to the result of that merge:Update 2023: for instance, if you want
main
to reflect exactly whatdev
is:(Edit 2011):
This workflow has been reported in this blog post by the OP:
git merge --strategy=theirs
Simulation #2Shows as a merge, with ours as the first parent.
(proposed by jcwenger)
git merge --strategy=theirs
Simulation #3This blog post mentions:
git merge --strategy=theirs
Simulation #4(same blog post)
git merge --strategy=theirs
Simulation #5(proposed by Barak A. Pearlmutter):
git merge --strategy=theirs
Simulation #6(proposed by the same Michael Gebetsroither):
git merge --strategy=theirs
Simulation #7Git 2.44 (Q1 2024) also proposes a custom merge driver approach (that I illustrate in "
git merge -s theirs
needed, but it does not exist").Custom merge drivers need access to the names of the revisions they are working on, so that the merge conflict markers they introduce can refer to those revisions.
The conflict labels to be used for the common ancestor, local head and other head can be passed by using the placeholders '
%S
', '%X
' and '%Y
' respectively.在我看来,您只需要这样做:
如果没有任何更改可以推送到上游,并且您只是希望上游分支成为您当前的分支,那么就可以做到这一点。在本地执行此操作没有什么害处但是您将丢失任何尚未推送到 master 的本地更改**。
** 实际上,如果您在本地提交了更改,这些更改仍然存在,因为提交仍将保留在您的
git reflog
中,通常至少保留 30 天。It sounds to me like you just need to do:
If there is no change to push upstream, and you simply want the upstream branch to be your current branch, this will do that. It is not harmful to do this locally but you will lose any local changes** that haven't been pushed to master.
** Actually the changes are still around if you have committed them locally, as the commits will still be in your
git reflog
, usually for at least 30 days.您现在可以相当轻松地做到这一点:
这使您的本地存储库与源同步,并保留历史记录。
You can do this rather easily now:
This gets your local repo in-sync with the origin, and preserves the history.
git merge -s theirs ref-to-be-merged 的另一个模拟:
双重重置的替代方法是应用反向补丁:
Another simulation for
git merge -s theirs ref-to-be-merged
:An alternative to the double reset would be applying the reverse patch:
还有一种几乎不需要管道命令帮助的方法 - 恕我直言,这是最直接的方法。假设您想模拟 2 个分支的“他们的”情况:
这使用其中一个分支的树(上例中的栏,提供“他们的”树)合并任意数量的头(上例中为 2 个),忽略任何差异/文件问题(commit-tree 是低级命令,因此它不关心这些)。请注意,head 可以仅为 1(因此相当于用“theirs”进行樱桃挑选)。
请注意,首先指定哪个父头可能会影响某些内容(请参见例如 git-log 命令的 --first-parent ) - 因此请记住这一点。
除了 git-show 之外,还可以使用任何其他能够输出树和提交哈希的东西 - 无论哪个用于解析(cat-file、rev-list,...)。您可以使用 git commit --amend 来跟踪所有内容,以交互方式美化提交消息。
There's also a way with little help of plumbing command - IMHO the most straightforward. Say you want to emulate "theirs" for 2 branches case:
This merges arbitrary number of heads (2 in the example above) using tree of one of them (bar in the example above, providing 'theirs' tree), disregarding any diff/file issues (commit-tree is low level command, so it doesn't care about those). Note that head can be just 1 (so equivalent of cherry-pick with "theirs").
Note, that which parent head is specified first, can influence some stuff (see e.g. --first-parent of git-log command) - so keep that in mind.
Instead of git-show, anything else capable of outputting tree and commit hashes can be used - whatever one's is used to parsing (cat-file, rev-list, ...). You can follow everything with git commit --amend to interactively beautify commit message.
虽然很严厉,但是见鬼,可能会出什么问题呢?
cp -r .git /tmp
git checkout y
rm -rf .git & & cp -r /tmp/.git
。Heavy handed, but hell, what can possibly go wrong?
cp -r .git /tmp
git checkout y
rm -rf .git && cp -r /tmp/.git
.更改为远程上游分支并执行
git merge
,并将合并策略设置为ours
。所有历史记录仍然存在,但您将有一个额外的合并提交。这里重要的是从您想要的版本开始,并将我们的版本与 github 实际所在的分支合并。
change to the remote upstream branch and do a
git merge
with the merge strategy set toours
.All the history will still be present, but you'll have an extra merge commit. The important thing here is to start from the version you want to be at and merge
ours
with the branch github is actually at.向后使用 git reset !
您可以使用 git reset 使分支看起来像任何其他提交,但您必须以迂回的方式进行。
要使提交
上的分支看起来像提交
,您可以执行以下操作:
> 工作树的内容。然后将
分支更改回原始提交但将工作树保留在
状态。然后您可以添加并提交更改,以使您的分支与
提交的内容完全匹配。这是违反直觉的,要从
状态转移到
,您需要执行git Reset
从<新>
到<旧>
。然而,使用选项--mixed
,工作树保留在
,分支指针设置为
,所以当提交更改时,分支看起来就像我们想要的那样。警告
不要忘记您的提交,例如在执行
git reset --hard
时忘记
是什么。Use git reset BACKWARDS!
You can make a branch look like any other commit with
git reset
, but you have to do it in a round-about way.To make a branch on commit
<old>
look like a commit<new>
, you can doin order to make
<new>
the contents of the working tree.Then do
to change the branch back to the original commit but leaving working tree in the
<new>
state.Then you can add and commit the changes, in order to make your branch exactly match the contents of the
<new>
commit.It's counter-intuitive that to move from the
<old>
state to the<new>
you need to do agit reset
from<new>
to<old>
. However with the option--mixed
the working tree is left at<new>
and the branch pointer set to<old>
, so that when the changes are committed the branch looks how we want.Warning
Don't lose track of your commits, e.g. forget what
<old>
is when doinggit reset --hard <new>
.我遵循这些角色:
从分支获取、硬重置,然后从他们的分支递归,然后强制推送到分支
自行承担风险
I followed those roles:
Fetching, reset hard from the branch then recursive from theirs and then forced push to the branch
ON YOUR OWN RISK