1

Something we could call a "Reset Request", because instead of requesting to merge the feature branch into master, we'd be requesting to reset master to the feature branch.

The use-cases for this would be for instance to clean up the git history (without any actual code changes), or to get updates from the original repo after a fork, via a rebase, into the master branch of the fork. You would do that on a separate (feature branch), then ask for a "Reset request" to master.

I am aware of the fact that rewriting history on a shared branch is a delicate thing to do. I am thinking of doing this for a repo of a small team, where you can control who has pulled the code locally and communicate whatever steps should be taken to continue development.

I'm looking for standard ways that these things get done. I couldn't find anything similar to the "Reset Request" I've described (neither on Gitlab nor on Github). The only way to do that that I can see right now is to force push to master ; but then how can you organize a review of the changes?

Seems like I'm missing a piece of the puzzle, unless these use-cases aren't as common as I'd imagined, so don't hesitate to correct any incorrect assumptions I made.

LoneCodeRanger
  • 413
  • 6
  • 18

1 Answers1

1

I'm pretty sure the answer is No, and I think that's true for all of the major tools. (GitHub, Azure DevOps, GitLab, Bitbucket, etc.)

Perhaps the two main reasons this functionality doesn't exist are both things you mentioned:

these use-cases aren't as common as I'd imagined

Force pushing shared branches should be a rare event.

The use-cases for this would be for instance to clean up the git history (without any actual code changes)...

Most code review tools are file-centric, and as you mentioned, even if there was a mechanism for code reviewing a reset, there actually wouldn't be any files to review. You'll still need to inspect the commits, but as mentioned below you can just do it manually on the machine that contains the new code.

As for your sub-question:

I'm looking for standard ways that these things get done.

I don't know of any (popular) standard for resetting shared branches, perhaps because it's odd to create a standard around something that is frowned upon and should be rare. That being said:

My preferred method for resetting a shared branch goes something like this:

  1. Decide if you really need to reset, or if a revert will suffice. (Usually the suggestion to reset is due to regretting merging in some code, and in that case a revert can undo it too. In your case, revert doesn't apply since your desire is to clean-up history. You'll have to reset, so you can skip this step, or, perhaps you need to decide if you really need to reset it.) If you decide not to reset, you're done here. (Reverts use the normal code review process.)

  2. Consider locking down the shared branch so no one adds more to it while you're re-writing it.

  3. Determine the best commit to reset to. For undoing regrettable merges, normally you reset backwards to a commit already in the history, perhaps just before the problem, but if you're rewriting history it's likely it won't be in the history at all. In the case of a rewrite you'll likely need to review your code outside of the normal review process. Typically, on someone's machine that contains the rewritten code, you compare the end states and make sure the only differences are whatever you wanted to strip out. Then you spot check specific commits to make sure the large files, passwords, etc, no longer exist anywhere in the history.

  4. If you haven't already, announce to your entire team that a shared branch is going to be re-written and provide instructions for how to rewrite their WIP branches. Make sure to include the previous tip commit ID of the branch getting rewritten, as well as the proper command(s) to run. Perhaps something like:

    git fetch
    # for each feature branch in progress:
    git rebase <old-tip-commit> my-feature-branch --onto <shared-branch-name>
    
  5. If you use protected branches, temporarily give someone (perhaps the person who has the rewritten history on their machine) permission to force push the shared branch.

  6. Force push the shared branch with the safety net, particularly if you didn't lock it as suggested above:

    git push --force-with-lease
    
  7. Remove the temporary permission to force push the shared branch.

  8. Announce to your team that it's done and that they can now rewrite all of their WIP branches.

TTT
  • 22,611
  • 8
  • 63
  • 69
  • 1
    Thank you so much for this very complete answer! I was worried this question would get closed, so thank you for taking it seriously and for taking the time to write down such a helpful answer! – LoneCodeRanger Nov 02 '22 at 17:17
  • "Consider locking down the shared branch so no one adds more to it while you're re-writing it". Good point, didn't think of that. – LoneCodeRanger Nov 02 '22 at 17:17
  • "`git push --force-with-lease`": didn't know about this option, thanks. [Here's some doc](https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegt) for anyone else wondering. – LoneCodeRanger Nov 02 '22 at 17:24
  • 1
    @AndreiToroplean It just occurred to me that there is a common workflow called [gitworfklow](https://git-scm.com/docs/gitworkflows) which is what the Git maintainers use. In this workflow there is typically an integration branch called `next` which is regularly reset to another shared branch, such as `main`. This is a little different than what you're trying to do, but I bring it up because it is a form of "resetting a shared branch" which happens regularly... so, resetting shared branches isn't always frowned upon. Hehe. – TTT Nov 02 '22 at 21:53
  • "Most code review tools are file-centric, and as you mentioned, even if there was a mechanism for code reviewing a reset, there actually wouldn't be any files to review." You are right there, but I would imagine some form of (non-file-centric) tooling could be useful there. – LoneCodeRanger Nov 03 '22 at 09:55
  • A use case I just had is for squashing two very old commits, the second of which I suspected was a fixup of a the first ; well I would have liked to see *how much* the diffs got simplified there, if that makes sense (before it looked like a deletion followed by an addition of files, after it just looked like a bunch of files moved). – LoneCodeRanger Nov 03 '22 at 09:59
  • @AndreiToroplean "I would have liked to see how much the diffs got simplified there" - note when you squash the end result diffs shouldn't change at all. For example, if you have commits A-B-C, and you then squash C into B so that you have A-B', the diff of A and C before the squash will be the same as the diff of A and B' after the squash. If you're diffing A and B, and also B and C, then yes, you can see the in-between differences as well, but obviously you'll lose the ability to see those in-between diffs with the squash, if that's what you meant. – TTT Nov 03 '22 at 14:24
  • @AndreiToroplean regarding you specific example of renames, note the concept of renames doesn't exist in a single commit (it's not saved anywhere). Renames are detected by Git when it compares two commits. When a file is simply moved it's fairly straight forward, but when it's moved and also modified there are settings you can use that change the strength of rename detection. – TTT Nov 03 '22 at 14:37
  • "you'll lose the ability to see those in-between diffs with the squash" that's indeed what I meant, specifically when those in-between diffs are the result of a mistake, so they're irrelevant, and they "dirty up" the git-blames. – LoneCodeRanger Nov 04 '22 at 10:34
  • But yes that was quite specific, you are right that in the general sense the global diff should stay the same after a squash (quite obviously). – LoneCodeRanger Nov 04 '22 at 10:35
  • 1
    @AndreiToroplean That makes sense. It's sort of funny that many people (myself included) will strongly recommend strict rules about clean commits on a branch before a PR/MR is completed, but if its merged anyway without clean commits, we just say "too late" and don't ever fix it up... – TTT Nov 04 '22 at 13:46