Summary: Add support for creating merge commits locally in self-hosted instances of Bors. This feature will never be enabled on the free public instance of Bors.
I allow this RFC document to be modified and redistributed under the terms of the Apache-2.0 license, or the CC-BY-NC-SA 3.0 license, at your option.
Motivation
Currently, Bors uses GitHub's Git Database API to create merge commits. This approach results in relatively inexpensive disk storage requirements and is sufficient for most purposes.
However, there are several important features that are not possible when creating merge commits with the Git Database API. For example:
-
Merge commits created using the Git Database API are not automatically GPG-signed (issue #647).
-
Merges performed using the Git Database API do not respect the merge strategies specified in any
.gitattributes
files (issue #512).
Guide-level explanation
An instance of Bors can be configured either to perform all merges using the Git Database API or to perform all merges locally using local git
. This is a server-wide setting; the same setting will apply to all repositories on the Bors server. The default setting is to perform all merges using the Git Database API.
If you manage an instance of Bors, you can enable local git
merges by setting the perform_git_merges_locally
configuration setting to true
in the config.exs
file. The default value of perform_git_merges_locally
is false
.
# General application configuration
config :bors, BorsNG,
command_trigger: {:system, :string, "COMMAND_TRIGGER", "bors"},
home_url: "https://bors.tech/",
allow_private_repos: {:system, :boolean, "ALLOW_PRIVATE_REPOS", false},
perform_git_merges_locally: {:system, :boolean, "PERFORM_GIT_MERGES_LOCALLY", true},
dashboard_header_html: {:system, :string, "DASHBOARD_HEADER_HTML", """
<a class=header-link href="https://bors.tech">Home</a>
<a class=header-link href="https://forum.bors.tech">Forum</a>
<a class=header-link href="https://bors.tech/documentation/getting-started/">Docs</a>
<b class=header-link>Dashboard</b>
"""},
dashboard_footer_html: {:system, :string, "DASHBOARD_FOOTER_HTML", """
This service is provided for free on a best-effort basis.
"""}
By default, Bors will look for an executable named git
in the PATH. To customize the location of the git
executable, set the value of the git_command
configuration setting. The default value of git_command
is git
.
# General application configuration
config :bors, BorsNG,
command_trigger: {:system, :string, "COMMAND_TRIGGER", "bors"},
home_url: "https://bors.tech/",
allow_private_repos: {:system, :boolean, "ALLOW_PRIVATE_REPOS", false},
perform_git_merges_locally: {:system, :boolean, "PERFORM_GIT_MERGES_LOCALLY", true},
git_command: {:system, :string, "GIT_COMMAND", "/bin/git"},
dashboard_header_html: {:system, :string, "DASHBOARD_HEADER_HTML", """
<a class=header-link href="https://bors.tech">Home</a>
<a class=header-link href="https://forum.bors.tech">Forum</a>
<a class=header-link href="https://bors.tech/documentation/getting-started/">Docs</a>
<b class=header-link>Dashboard</b>
"""},
dashboard_footer_html: {:system, :string, "DASHBOARD_FOOTER_HTML", """
This service is provided for free on a best-effort basis.
"""}
This RFC does not deprecate or break any existing features. Maintainers of Bors servers will always have the option to perform all merges using the Git Database API.
Reference-level explanation
If you were to perform the merge yourself, here are the steps you would follow. Suppose that we have a repository located at https://github.com/someusername/somerepository.git
, and we want to merge pull requests #10
, #15
, and #20
into the target branch sometargetbranch
.
git clone https://x-access-token:<token>@github.com/someusername/somerepository.git
cd somerepository
git checkout sometargetbranch
git fetch origin pull/10/head:randomlygeneratedstring-10
git checkout randomlygeneratedstring-10
git fetch origin pull/10/head:randomlygeneratedstring-15
git checkout randomlygeneratedstring-15
git fetch origin pull/10/head:randomlygeneratedstring-20
git checkout randomlygeneratedstring-20
git checkout sometargetbranch
git branch --force staging
git checkout staging
git merge randomlygeneratedstring-10 randomlygeneratedstring-15 randomlygeneratedstring-20
git push --force origin staging
cd ..
rm -rf somerepository
In order to implement this in Bors, we'll likely need to write additional versions of the start_attempt
method in attemptor.ex and the start_waiting_batch
and start_waiting_merged_batch
methods in batcher.ex. Then, we'll add logic that calls the appropriate methods based on the value of the perform_git_merges_locally
configuration option.
Drawbacks
In order for Bors to perform a merge locally, the server on which Bors is running will need to have sufficient disk space for git
to be able to clone repositories locally. Thus, any Bors server maintainer that is considering setting perform_git_merges_locally
to true
should make sure that they will have enough disk space.
Let N
denote the number of repositories on which Bors is installed, and let M
denote the size on disk of the largest repository. Since each repository could have both bors r+
and bors try
commands running simultaneously, a conservative estimate for the disk space requirement for cloning repositories is 2MN
.
Rationale and alternatives
The alternative will be to continue using the Git Database API for creating merge commits. This is a great option for most users, and it will continue to be the only option available on the free public instance of Bors. However, as described above, there are certain features that will never be available through the Git Database API, and for those, a Bors administrator will need to use local merges.
Prior art
The following apps implement the NRSROSE and have the option to create the merge commit locally:
Unresolved questions
- How do we implement tests for this feature?
Future possibilities
Next steps for maintainers of Bors servers after this feature is implemented
GPG-signing all merge commits
If you run a Bors server and you want to enable GPG-signing of all merge commits, you first need to set perform_git_merges_locally
to true
. Then, you should log in to the server as the same user that Bors runs as and run the following commands:
git config --global user.signingkey your_gpg_key_id
git config --global commit.gpgsign true
Using specific merge strategies for certain files
If you use a Bors server with perform_git_merges_locally
set to true
, and you want to use a specific merge strategy for certain files in one of your repositories, you only need to create an appropriate .gitattributes
file and commit it in your repository. The command-line git
will use the .gitattributes
file automatically.
Future work in Bors
Once the ability to create merge commits locally has been implemented, future work might include the implementation of a git_squash = true
option in bors.toml
that would pass the --squash
flag to the git merge
command. This could potentially help us close issue #138 and/or issue #194.
But this would be an advanced feature, and we should not implement it as part of this first RFC. The best plan is to first implement the ability simply to create merge commits locally. Once we have implemented that, we can consider opening a second RFC for discussion specifically of a git_squash = true
option for passing the --squash
flag to the git merge
command, or something similar.
Change history
- 2019-07-15: initial version posted