Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Configure github (enterprise) repo to only allow fast forward commits / PR merges?

Coming from gerrit to github, there's a major feature I'm missing, namely allowing only fast forward merges. Essentially, in my opinion any kind of "CI build sign off" is useless if you're signing off on your change on a stale master branch.

I was wondering if there's any way how this can be configured in (enterprise) github? Is there any setting or other trick that would not allow users to press the "merge pull request" button in github unless the branch was rebased properly?

Preferably, I even would like to add that it should also check whether all commits in the PR were squashed (and the PR can't be merge unless it contains only one commit).

So, perfect solution: Allow only PR merges that have a single commit and were rebased previously.

like image 962
mac Avatar asked May 16 '16 19:05

mac


People also ask

How do I enable squash merge in GitHub?

On GitHub.com, navigate to the main page of the repository. Under your repository name, click Settings. Under "Pull Requests", select Allow squash merging. This allows contributors to merge a pull request by squashing all commits into a single commit.

How do I turn off fast forward in git?

Disables the default fast forwarding on merge commits. Use git config --add merge. ff false to disable fast-forward merging for all branches, even if it is possible.


1 Answers

There are a few parts to this question...

To require that a PR branch be up to date with the target branch before merging, you can add a branch protection rule (go to the repository "Settings" -> "Branches") and use the "Require branches to be up to date before merging" option. Currently, this option is only available if the branch protection rule has at least one required status check; it sounds like there may a status check you want to require anyway (your CI), but you can always write a dummy status check that always passes (I have not researched whether anyone has code for this that you can reuse). This option is available at least on github.com, but I have not tested that it behaves as documented, nor have I looked for the option on GitHub Enterprise.

It's probably worth mentioning that on a busy project, requiring every PR to be tested against the latest position of the target branch may become a bottleneck and you may wish to consider a different compromise between velocity and avoiding CI failures on the target branch, as discussed in the later part of this thread.

The default merge method ("Create a merge commit" in the drop-down menu of the "Merge pull request" button, which is available only if "Allow merge commits" is on in the repository settings) always creates a merge commit even if the target branch is an ancestor of the PR branch. This can be helpful in that the merge commit records the PR number and title and the user and timestamp of the merge while preserving the original commit(s) from the PR branch. So in combination with the "Require branches to be up to date before merging" option, this is not technically a "fast-forward merge" but could be called a "dummy merge commit based on a fast-forward branch". Here is more discussion of this issue. The "Rebase and merge" option would perform a true fast-forward merge, but I haven't tested whether it's smart enough to skip the rebase (preserving the original commit IDs and committer information) if the PR branch is already up to date with the target branch.

If you want to ensure that the PR branch has only a single commit on top of the target branch, you'd have to use a custom status check; I haven't researched whether someone has already written one. Then if you want to merge this commit without an additional merge commit, you would use either the "Squash and merge" option or the "Rebase and merge" option in the "Merge pull request" drop-down menu (corresponding to "Allow squash merging" and "Allow rebase merging" in the repository settings). In the case that the PR contains only one commit, I believe the only difference between these two options is that the "Rebase" option uses the commit as-is, while the "Squash" option uses a new commit with the same diff but (i) a message containing only the PR number and title and (ii) author information (user and timestamp) based on the click of the "Merge" button, discarding the original message and author information. (If you want to keep all of the information at the expense of a more complex history, use the "Create a merge commit" option.) You still need the "Require branches to be up to date before merging" option, otherwise GitHub will happily put stale commit(s) on top of the target branch without prompting you to perform the testing you want.

The "Require linear history" option in a branch protection rule is documented to "Prevent merge commits from being pushed to matching branches". But other than that, I haven't researched whether GitHub blocks manual pushes (e.g., from the command line) of a PR merge in a form that corresponds to a "Merge" button option that is disabled in the repository settings.

If anyone knows the answer to any of the things I said I don't know (or for that matter, has any other corrections or important related points to this answer), please edit the answer!

like image 58
Matt McCutchen Avatar answered Sep 22 '22 09:09

Matt McCutchen