如何修改位于主分支的 git 提交,而不破坏分支历史记录?

huangapple go评论51阅读模式
英文:

How can I modify a git commit which is part of the master branch without breaking the branch history?

问题

以下是翻译好的部分:

有一个位于主分支上的提交,我需要进行一些更改。

以下是发生的历史:

  • 我正在处理一些代码,然后将其合并到主分支。
  • 我创建了一个新分支。
  • 其他人从主分支中分支出来,进行了更改,然后合并到主分支。
  • 这样做时,他们修改了不应该修改的代码的部分,这是问题的核心。
  • 他们提交的一部分工作应该在主分支上(事实上大部分都是如此),但是一些更改不应该被合并。
  • 我继续工作。
  • 现在:我不能自己合并到主分支,因为这样做不仅会导致我的代码出错,还会导致我的一些工作丢失,因为另一个人在此过程中撤销了我的一些工作。
  • 理论上,我可以合并到主分支,并通过将代码逐一比较以及检查他们提交期间所做的更改来手动还原他们的更改。
  • 但是,我认为可能有更好的方法。如果我能够编辑主分支的历史记录(出于显而易见的原因,我不能这样做,至少不能不惹怒很多人),那么我会执行交互式变基,专注于此提交。但我不能这样做。
  • “有罪的提交”现在位于主分支的提交堆栈中的几个提交之后,因为其他人在此之后提交了工作。

在这种情况下,最好的方法是什么?我以前从未遇到过这种情况,因为我从未在任何人都可以在未经批准的情况下提交工作的环境中工作过。

我当然知道,无论我在这里做什么,都必须进行一定程度的手动工作,以使所有新提交都能够编译。似乎我拖延解决这个问题,情况会变得越来越糟。

英文:

There is a commit on master branch which I need to make some changes to.

Here's some history of what happened:

  • I was working on some code, and merged this to master
  • I created a new branch
  • Someone else branched from master themselves, made changes and then merged to master
  • In doing so, they have modified parts of the code which they should not have done. This is the core of the problem.
  • Part of the work they committed should be on master (most of it in fact) however a small number of the changes should not have been merged.
  • I continued working
  • Now: I cannot merge to master myself, because not only will my code break in doing so, but some of my work will be lost, because the other person who has committed their changes has undone some of my work in the process.
  • In theory, I could merge to master, and manually revert their changes by comparing code side-by-side as it was before they committed, or by inspecting the changes made during their commit.
  • However, I believe there might be a better way. If I was able to edit the history of master (which for obvious reasons I cannot - at least not without upsetting a lot of people) then I would do an interactive rebase, focusing on this commit. But I can't do this.
  • The "guilty commit" is now several commits down in the commit stack on master, as other people have committed work since this time.

What is the best approach here? I have never been in this situation before because I never worked in an environment where anyone could commit work without having it approved first.

I am of course aware that whatever I do here, I will have to do some level of manual work to make all of the new commits compile. It seems the longer I leave the situation the worse it will be to fix.

答案1

得分: 1

我认为在这种情况下,你最好的选择是首先通过执行对有问题的提交进行部分还原来修复master。然后,你应该能够正确地合并你的特性分支。

注意,git revert 并没有什么特别之处,它基本上是一个便利功能,用于撤销提交带来的所有更改。所谓的 "部分" 还原只是一个你在提交之前修改的常规还原,通常是通过取消暂存你希望保留的原始提交部分来实现的。

至于从哪里开始,正如eftshift0建议的,你可以从master中有问题的提交中分支出去,或者你可以使用master的当前顶端(如果愿意,也可以在中间的任何位置)。除非你将遇到冲突,否则哪种方式都没有太大的区别。如果冲突是不可避免的,那么如果你从有问题的提交中分支出去,还原就不会有冲突,但合并到master时会有冲突。如果你从master开始,还原时会有冲突,但合并到master时则不会。选择你感到更舒适的方式。请注意,如果master受保护,你必须使用 PR 合并你的更改,那么我会从master开始,但在这里似乎不是这种情况。

英文:

I think your best bet in this situation is to first fix master by doing a partial revert of the offending commit. After that, you should be able to merge your feature branch in properly.

Note there isn't anything special about git revert, it's basically a convenience feature that reverses all the changes brought in by a commit. A "partial" revert is simply a regular revert that you modify before committing, typically by unstaging the portions of the original commit that you wish to keep.

As for where to start, as suggested by eftshift0 you could branch off of the offending commit in master, or you could use the current tip of master (and probably anywhere in between if you wish). It doesn't make much difference which of those you start from unless you will have conflicts. If conflicts are inevitable, then if you branch off of the offending commit, the revert won't have conflicts but the merge into master will. If you start from master, you'll have conflicts at the revert but not when you merge into master. Choose whichever you're more comfortable with. Note if master were protected and you must use a PR to merge in your change, I'd start from master, but that doesn't appear to be the case here.

答案2

得分: 0

我认为最好的方法是隔离修复,特别是考虑到较新的提交没有修改有问题的文件。流程大致如下:

  1. 从最新发布的主分支创建一个新分支。
  2. 使用 git revert 撤消 "有问题" 的提交。
  3. 如果这些提交中包括需要保留的更改,对于每个撤消的提交,只重做这些更改并创建新的提交。
  4. 测试一切,并修复由于撤消和重做可能导致的任何问题。
  5. 如果在上一步骤中已经添加了新工作所需的 "修复"(针对之前的步骤),可以将这些提交 cherry-pick 到此分支。使用 cherry-pick 将简化将来的合并或变基操作。
  6. 通知你的同事这个问题以及解决方案。
  7. 将此分支推送到主分支(不要强制推送)。

现在,对于任何较新的(未合并的)分支,可以将其变基到主分支上,将主分支合并到自身,或者按原样合并到主分支。如果新的工作修改了 "有问题的内容",那么只有在可能出现冲突的情况下才会出现问题,但这可能正是你想要的。另外,如果有保留当前主分支的实际原因,将其作为单独的分支会将任何判断与较新的、无关的工作隔离开来。

虽然这种方法应该能与大多数将来的 git 操作很好地配合(无论是变基还是合并),但它有一个主要缺点——基于 "有问题的内容" 的任何新工作都可能悄悄地中断(即没有合并冲突)。例如,假设你修改了一个函数以接受一个额外的参数,而 "有问题" 的代码将其修改回以删除该参数。基于原始函数参数的新代码对你的同事在本地通过,但合并到主分支时可能会中断。这就是为什么通知你的同事非常重要,至少让他们知道他们应该将他们的工作与最新的主分支合并/变基。

最后,由于你的使命是不惹恼很多人,我希望那个 "修改了不应该修改的东西" 的人是他们中的一员。我建议直接与这个人讨论这个问题,甚至让他们在修复分支上签署,或者与他们一起努力寻找新的解决方案。"撤销" 别人的工作可能会被视为冒犯(对你和对他们都是如此),而实际上可能有你不知道的很好的原因。沟通是健康合作的关键,并且从长远来看可能会非常有益。

英文:

I think that the best approach is to isolate the fix, especially considering that newer commits do not modify the problematic files. The flow would be something like this:

  1. Create a new branch from the latest published master.
  2. Use git revert to undo the the "guilty" commit(s).
  3. In case the commits include changes which should be kept, "redo" only these changes for each reverted commit with a new commit.
  4. Test everything, and fix anything that might have broken due to the reverts and redos.
  5. In case some required "fixes" (for the previous step) were already added to new work, you can cherry-pick these commits to this branch. Using cherry-pick will ease any future merge or rebase actions.
  6. Notify your colleagues of the issue, and this resolution.
  7. Push this branch to master (DO NOT force-push).

Now, for any newer (unmerged) branch, it can be rebased over master, have master merged into itself, or be merged to master as-is. Further conflicts should only be an issue in case newer work has modified the "guilty contents" (sounds like a song title by Eminem?, #sorry) - but that's what you probably want. Additionally, if there was a practical reason for keeping the current master, having this as a separate branch would isolate any judgement calls from affecting newer, unrelated work.

While this method should play nice with most future git actions (whether rebasing or merging), it has one major drawback - any new work based on the "guilty contents" is bound to silently break (i.e. no merge conflict). For example, say you modified a function to accept an additional argument, and the "guilty" code modified it back to remove that argument. Newer code which assumes the original function arguments will still pass locally for your colleagues, but may break when merged to master. This is why it is important to notify your colleagues, at the very least to let them know they should merge/rebase their work with the latest master.

Finally, as your mission is to not upset lots of people, I hope the person who "modified what they shouldn't have" is one of them. I suggest discussing this issue with that person directly, and perhaps even have them sign-off on the fixing branch, or work with them towards a new solution. "Undoing" someone else's work might be perceived as offensive (both for you and for them), and there could actually be a good reason for that you're not aware of. Communication is key for a healthy collaboration, and may prove extremely beneficial in the long run.

答案3

得分: -1

git merge和解决冲突。它不会偏向于对方的更改而覆盖你的;你只需查看并解决每个冲突。如果最终决定不想合并,git reset --hard HEAD将会把你带回合并前的状态。

英文:

git merge and resolve conflicts. It won't favor their changes over yours; you'll just have to look through it and resolve each conflict. If you decide you didn't want to merge after all, git reset --hard HEAD will will take you back just before you started merging.

huangapple
  • 本文由 发表于 2023年5月23日 01:22:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76308591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定