Workflow for Maintainers#

This page is for maintainers — those of us who merge our own or other peoples’ changes into the upstream repository.

Being a maintainer with write access, you are expected to be on top of the basic stuff in How to make a code contribution.

Integrating changes via the web interface#

Pull requests should always be merged via GitHub.

Make sure that pull requests do not contain a messy history with merges, etc. If this is the case and a simple Github ‘Squash and merge’ would do and you are comfortable with it, use it. Otherwise, you can work with the author, following instructions at Squash if necessary. If the author is not responsive or gives consent, you can also take over the pull request. If necessary, you may also request a rebase.

Github ‘Squash and merge’#


Before you use this button, first make sure the PR author has not opted out by checking the opt-out box that comes with the PR template!

Use of the GitHub ‘Squash and merge’ button is available to all maintainers. This will squash out all commits in the pull request into a single commit and auto-generate a commit message which can be edited.

You must be careful to clean up the final commit message before pushing the button:

  • Remove repetitive, irrelevant, or inappropriate commit messages. Merge commits, if any, do not have to be mentioned.

  • Fix typo, as needed.

  • Fill in details about the pull request, as needed.

  • Remove all the directives to skip CI ([ci skip] or [skip ci]).

  • Ensure co-authors are properly credited at the bottom of the final message.

  • Make sure it is the correct button! Your browser remembers a previous selection even from a different GitHub repository, which might or might not be the button you want to push.

Use of the ‘Squash and merge’ button is encouraged when you and the contributor agree that squashing to a single commit is desirable. Using the GitHub button instead of direct git commands can reduce overall effort, if done correctly.

You may use ‘Squash and merge’ in conjunction with Auto-merge.


If a pull request is ready for merge but only waiting CI to pass, you may use the Enable auto-merge option.

However, this feature should not be used in the following cases:

  • You should not enable auto-merge on your own pull request unless other maintainers are okay with it. There might be exceptions but they should be handled on a case-by-case basis.

  • If a pull request requires job(s) that is not required to pass branch protection rules (e.g., allowed to fail job, cron jobs) to pass to be acceptable (say, it touches remote data or has very big changes that need extra checks).

  • If a pull request requires approvals from multiple reviewers and not all the reviews are in but you are happy with it.

  • If you are unsure of all the implications of using this feature.

Taking over a pull request#

Remember that, if you take over a pull request, you will show up as co-author on the GitHub commit history. Furthermore, the author will need to know how to grab your changes back onto their local branch, which might be daunting for new contributors. If you are not sure the author would be okay with this, ask first.

If author is not okay with this or has disabled “edit by maintainers” option, you can still cherry-pick their commits onto a new branch of your own and create a new pull request off that, which would close out the original pull request.

But let’s say the author is okay with you taking over…

First, check out the astropy repository and Tell git where to look for changes in the development version of Astropy. Now, you need to point a remote to the pull request author’s fork. In this example, the author’s username is octocat and the pull request branch name is cool-feature that is tied to pull request number 99999:

git remote add octocat
git switch -c pr99999 --track octocat/cool-feature

Now you are on the branch with the changes to be incorporated upstream. The rest of this section assumes you are on this branch. You can now edit files and add commits as if it were your pull request, including How to rebase and How to squash.

Check the history#

Now, in either case, you should check that the history is sensible and you have the right commits:

git log --oneline --graph
git log -p astropy/main..

The first line above just shows the history in a compact way, with a text representation of the history graph. The second line shows the log of commits excluding those that can be reached from trunk (origin/main), and including those that can be reached from current HEAD (implied with the .. at the end). So, it shows the commits unique to this branch compared to trunk. The -p option shows the diff for these commits in patch form.

Push to back pull request#

When you are ready, you can push your changes to that pull request on GitHub:

git push octocat pr99999:cool-feature

If you have rewritten the history on the branch, you need to add a --force option.

After the push, you should look at the pull request history and diff again on GitHub to ensure nothing is amiss. If something is wrong and you have to undo a push, GitHub should show you the necessary hashes.

Fixing coding style issues#

Astropy now uses the bot to assist with maintaining the astropy coding style and fixing code style issues. The bot makes use of the pre-commit hook described in detail in Pre-commit.

By default the bot will run a code-style check on every push to a pull request with the results reported in the checks section of the pull request. The bot will skip running its check if a commit message contains [skip ci], [ci skip], [skip], or [ skip].

One can control the bot by making comments on the pull request:

  • To trigger a re-run of the code-style check, comment on the PR with: run
  • To have the bot push a commit to the PR fixing the code-style issues (the ones that can be fixed by automated tools), comment on the PR with: autofix


These comments must appear in the comment on a single line by themselves.


If you wish to run the pre-commit check first in CI without running Actions, use [skip actions] or [actions skip] in your commit message.


If a pull request explicitly deals with a performance improvement, maintainers should use the benchmark label to run a comparative benchmark on the pull request. This will run a benchmark comparing the HEAD commit of the pull request branch with the main branch. The logs are uploaded as a action artifact and can be viewed in the Actions tab. This workflow uses the benchmarks from astropy-benchmarks.

Maintainers should also run the benchmark if they suspect the code change might have performance implications, but do note that benchmark action takes significantly longer than regular CI to complete.

It is important to note that the benchmarking on Github Actions will be flaky and should only be used as a general guide.

Using Milestones and Labels#

General guidelines for milestones:

  • 100% of pull requests should have a milestone

  • Issues are not milestoned unless they block a given release

  • Only the following criteria should result in a pull request being closed without a milestone:

    • Invalid (user error, etc.)

    • Duplicate of an existing pull request

    • A pull request superseded by a new pull request providing an alternate implementation

  • In general there should be the following open milestones:

    • The next bug fix releases for any still-supported version lines; for example if 0.4 is in development and 0.2.x and 0.3.x are still supported there should be milestones for the next 0.2.x and 0.3.x releases.

    • The next X.Y release, i.e. the next minor release; this is generally the next release that all development in main is aimed toward.

    • The next X.Y release +1; for example if 0.3 is the next release, there should also be a milestone for 0.4 for issues that are important, but that we know won’t be resolved in the next release.

  • We have Rolling reminder: update wcslib and cfitsio and leap second/IERS B table to the latest version. The milestone for this issue should be updated as part of the release procedures.

General guidelines for labels:

  • Issues: Maintainer should be proactive in labeling issues as they come in. At the very least, label the subpackage(s) involved and whether the issue is a bug.

  • Pull requests: We have GitHub Actions to automatically apply labels using some simple rules when a pull request is opened. Once that is done, a maintainer can then manually apply any other labels that apply.

Updating and Maintaining the Changelog#

The Astropy “changelog” is managed with towncrier, which is used to generate the CHANGES.rst file at the root of the repository. The changelog fragment files should be added with each PR as described in docs/changes/README.rst. The purpose of this file is to give a technical, but still user (and developer) oriented overview of what changes were made to Astropy between each public release. The idea is that it’s a little more to the point and easier to follow than trying to read through full git log. It lists all new features added between versions, so that a user can easily find out from reading the changelog when a feature was added. Likewise it lists any features or APIs that were changed (and how they were changed) or removed. It also lists all bug fixes. Affiliated packages are encouraged to maintain a similar changelog.

Stale Policies#

The astropy GitHub repository has the following stale policies, which are enforced by action-astropy-stalebot in .github/workflows/stalebot.yml that runs on a schedule. Hereafter, we refer to this automated enforcer as stale-bot.

All the timing mentioned depends on a successful stale-bot run. GitHub API limits, spam protection, or server maintenance could affect the run. The former might especially be relevant when there is a significant backlog of stale issues and pull requests accumulated.

If you notice unintended stale-bot behaviors, please report them to the Astropy maintainers.


A maintainer applies the “Closed?” label to mark an issue as stale, otherwise it stays open until someone manually closes it. Once marked as stale, a warning will be issued.

A maintainer can apply “keep-open” label or remove “Closed?” label to remove the stale status. Otherwise, stale-bot will close the issue after about a week and apply a “closed-by-bot” label.

When both “keep-open” and “Close?” labels exist, the former will take precedence and the latter will be removed from the issue.

Pull Requests#

A pull request becomes stale after about 4-5 months since the last commit (stale-bot counts in seconds and naively assumes 30 days per month). When this happens, stale-bot applies the “Close?” label to it. A maintainer can also fast-track its staleness by manually applying the “Close?” label. Once marked as stale, a warning will be issued.

A maintainer can apply “keep-open” label or remove “Closed?” label to remove the stale status. The pull request author (or maintainer) can reset the stale timer by pushing out a commit (e.g., by rebasing). Otherwise, stale-bot will close the pull request after about a month and apply a “closed-by-bot” label.


The “keep-open” label should be used very sparingly, only for pull requests that must be kept open. For example, a pull request that has been completed but cannot be merged until a blocker is removed can use this label. An abandoned or incomplete pull request should not use this label as it can be re-opened later when the author has a renewed interest to wrap it up.

When both “keep-open” and “Close?” labels exist, the former will take precedence and the latter will be removed from the pull request. If maintainer removes “Close?” without applying “keep-open” or pushing a new commit, stale-bot will mark it as stale again in the next run.

If a new commit is pushed but the “Close?” label remains, stale-bot will close it without another warning after another 4-5 months.

In short, to truly reset the stale timer for a pull request, it is recommended that a new commit be pushed and the “Close?” label be removed.