Python-maint
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Changes in Python packaging guidelines These are changes between the [current (“201x-era”) Python packaging guidelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/Python/) and the [proposal as of 2021-03-03](https://fedoraproject.org/wiki/Changes/PythonPackagingGuidelines202x). All **MUST** and **SHOULD** items from both versions are covered. (For the old guidelines I added more, where I feel they should have been marked SHOULD.) If you have comments or reservations, please *read the whole section* of the new guidelines. Direct your comments to the [Python SIG mailing list](python-devel@lists.fedoraproject.org). (Comments on HackMD are hard to manage.) <details> <summary>Minor changes are hidden in *details* tags like this. To open one, click the summary.</summary> (Now you can see these details.) </details>   I tried to list the most important changes first. ## Rationales and explanations The new guidelines give rationales and explanations where applicable. In many cases these changed. This list of changes generally doesn't list these “soft” changes. ## PyPI Parity The most profound change is synchronization of Python project names with the Python Package Index, allowing Python-level metadata across the ecosystem. > **NEW:** Every Python package in Fedora **SHOULD** also be available > on [the Python Package Index](https://pypi.org) (PyPI). > > The command `pip install PROJECTNAME` **MUST** install the same package > (possibly in a different version), install nothing, > or fail with a reasonable error message. > > If this is not the case, the packager **SHOULD** contact upstream about this. > The goal is to get the project name registered or blocked on PyPI, > or to otherwise ensure the rule is followed. As a reminder: if you want to comment, please read the [relevant section](https://hackmd.io/XzJe-sHUQvWK7cSrEH_aKg?both#PyPI-parity) for details. ## Upstream metadata The second major paradigm shift is that package metadata is primarily taken from upstream, since upstream “dist-info” metadata is now standardized and shareable with other distributors (be it Linux distros or others). Packagers are expected to treat metadata bugs as any other bugs, (ideally, patch them and present the patches upstream). > NEW: Packagers **SHOULD** be prepared to get involved with upstream projects to establish best practices as outlined here. We wish to improve both Fedora and the wider Python ecosystem. ## Beta period (before the guidelines are approved) The new guidelines are “beta” period where they can be used instead of the old ones, but ask for increased cooperation from packagers who opt in to use them. > NEW: These Guidelines represent a major rewrite and paradigm shift, and not all packages are updated to reflect this. Older guidelines are still being kept up to date, and existing packages **MAY** use them instead of this document > NEW: While these guidelines are in Beta, each Python package **MUST** have `BuildRequires: pyproject-rpm-macros` to access the beta macros. ## Python 3 Python 2 has been deprecated for a while now; using it requires a FESCo exception. Text related to the py2/py3 split is generally removed or simplified. > NEW: Fedora packages **MUST NOT** depend on other versions of the CPython interpreter than the current `python3`. > [...] > Packages such as `pip` or `tox`, which enable setting up isolated environments and installing third-party packages into them, **MAY**, as an exception to the rule above, use these interpreters as long as this is coordinated with the maintainers of the relevant Python interpreter. > OLD: If a piece of software supports `python3`, it MUST be packaged for `python3`. Software using `python2` MUST NOT be newly packaged into Fedora without FESCo exception. The following redundant note was put in the guidelines to address pushing "remove of python2 package" changes to stable branches. Since not many python2 packages are left, the note is not necessary any more: > OLD: Mirroring the policy for regular packages, the Python-version-specific subpackages of your package MUST NOT be removed in a release branch of Fedora. ## Dependency Generator The dep generator is now mandatory (i.e. upstream metadata must be used/patched): > NEW: Packages **MUST** use the automatic Python run-time dependency generator. Packages **SHOULD** use the opt-in build-dependency generator if possible. he packager **MUST** inspect the generated requires for correctness. All dependencies **MUST** be resolvable within the targeted Fedora version.” Any necessary changes **MUST** be done by patches or modifying the source (e.g. with `sed`), rather than disabling the generator. The resulting change **SHOULD** be offered to upstream. As an exception, [filtering](https://docs.fedoraproject.org/en-US/packaging-guidelines/AutoProvidesAndRequiresFiltering/) **MAY** be used for temporary workarounds and bootstrapping. Dependencies covered by the generators **SHOULD NOT** be repeated in the `.spec` file. (For example, if the generator finds a `requests` dependency, then `Requires: python3-requests` is redundant.) > OLD: This generator is enabled by default in Fedora. If a packager wishes to explicitly opt out of the generator because the upstream metadata are not applicable, a packager SHOULD opt out explicitly by adding: `%{?python_disable_dependency_generator}` > OLD: [if using dependency generator] The packager MUST inspect the generated requires for correctness. All dependencies MUST be resolvable within the targeted Fedora version. ## Applicability New clarification: > NEW: Except for the two "Distro-wide guidelines", these Guidelines do not apply to simple one-file scripts or utilities[...]. > However, if [you need] a more complex Python library, the library **SHOULD** be packaged as an importable library under these guidelines. ## Naming <details> <summary>Clarified wording on General naming:</summary> > NEW: A built (i.e. non-SRPM) package for a *Python library* **MUST** be named with the prefix `python3-`. > > A source package containing primarily a *Python library* **MUST** be named with the prefix `python-`. > OLD: The source package for a Python library MUST be named with the `python-` prefix. > OLD (in [Naming guidelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/#_python_modules)): Python2 binary packages MUST be named using a `python2-` prefix. > Python3 binary packages MUST be named with a prefix of `python3-`. </details> <details> <summary>Clarified wording on `python3-` provides for importable modules:</summary> > NEW: For any module intended to be used in Python 3 with `import MODNAME`, the package that includes it **SHOULD** provide `python3-MODNAME`, with underscores (`_`) replaced by dashes (`-`). > OLD: For any module foo intended to be used in Python 3 with `import foo`, the package that includes it should provide `python3-foo` </details> <details> <summary>Clarified wording on `python-`/`python3-`/`python3.X-` provides:</summary> > NEW: For any `FOO`, a package that provides `python3-FOO` **SHOULD** use `%py_provides` or an automatic generator to also provide `python-FOO` and `python3.X-FOO`, where `X` is the minor version of the interpreter. The provide **SHOULD NOT** be added manually: if a generator or macro is not used, do not add the `python-FOO` / `python3.X-FOO` provides at all. > OLD: All packages that provide `python3-...` (for any `...`) SHOULD also provide `python-...` and `python3.X-...`. > OLD: Any manually added virtual provides of `python3-...` SHOULD be done via the `%py_provides macro`. </details> Removed ban on `python-` Requires, since the `python-` prefix now refers to Python 3: > OLD: Packages MUST NOT have dependencies (either build-time or runtime) on packages named with the unversioned `python-` prefix. Dependencies on Python packages instead MUST use names beginning with `python3-`. Best practices (SHOULDs): > NEW: If the importable module name and the project name do not match, users frequently end up confused. In this case, packagers **SHOULD** ensure that upstream is aware of the problem and (especially for new packages where renaming is feasible) strive to get the package renamed. The Python SIG is available for assistance. > NEW: The Fedora package's name **SHOULD** contain the *canonical project name*. If possible, the project name **SHOULD** be the same as the name of the main importable module, with underscores (`_`) replaced by dashes (`-`). > NEW: Packages that primarily provide applications, services or any kind of executables **SHOULD** be named according to the general [Fedora naming guidelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/) (e.g. `ansible`). > OLD (in [Naming guidelines](https://docs.fedoraproject.org/en-US/packaging-guidelines/Naming/#_python_modules)): The package name SHOULD reflect the upstream name of the Python module, and SHOULD generally take into account the name of the module used when importing it in Python scripts. This name will be prefixed depending on the type of the package. Removed rules on removing `%py_provides` (which is documented as being for cases where the generator doesn't work) and `%python_provide` (which is listed in Deprecated macros): > OLD: Packagers SHOULD try to remove explicit `%py_provides` calls for package names, but MAY preserve them if they aim for compatibility with older releases or packages without files. > OLD (note): Historically, there was `%python_provide` macro with similar but different semantics. It still works for compatibility reasons but it is deprecated and SHOULD NOT be used and packagers SHOULD replace is with appropriate %py_provides call. ### Naming Extras Slight addition on including devel extras (diff emphasized): > NEW: Python packages **SHOULD** have Provides for all extras the upstream project specifies, except: those that are not useful for other packages (for example build/development requirements, commonly named `dev`, `doc` or `test`), **and those that have requirements that are not packaged in Fedora.** > OLD: Python packages SHOULD have `Provides` for all extras the upstream project specifies, except those that are not useful for other packages (for example build/development requirements, commonly named `dev`, `doc` or `test`). New best practice re. removing extras: > NEW: If an existing extra is removed from an upstream project, the Fedora maintainer **SHOULD** try to convince upstream to re-introduce it. If that fails, the extra **SHOULD** be Obsoleted from either the main package or another extras subpackage. <details> <summary>Reworded text on <code>+</code>; same meaning</summary> > NEW: The character `+` in names of built packages (i.e. non-SRPM) > that include `.dist-info` or `.egg-info` directories > is reserved for *extras* > and **MUST NOT** be used for any other purpose. > As an exception, `+` characters **MAY** appear at the *end* of such names. > OLD: The character `+` in names of built packages (i.e. non-SRPM) that include `.dist-info` or `.egg-info` directories is reserved for Python Extras and MUST NOT be used for any other purpose. > As an exception, + characters are permitted at the end of the name. > NEW: A package that provides a Python extra **MUST** provide `python3dist(DISTNAME[EXTRA])` **and** `python3.Xdist(DISTNAME[EXTRA])`, where `X` is the minor version of the interpreter, `DISTNAME` is the [canonical project name](#Canonical-project-name), and `EXTRA` is the name of a single extra. For example, `python3.9dist(requests[security])`. > These requirements **SHOULD** be generated using the automatic dependency generator. > OLD: A package that provides a Python extra MUST provide `python3dist(…[…])` and `python3.Xdist(…[…])`, for example, `python3.9dist(requests[security])`. These requirements SHOULD be generated using the automatic dependency generator. </details> <details> <summary>Unchanged guidelines</summary> > NEW: A package that provides a Python extra **MUST** require the extra's main package with exact NEVR. > OLD: A package that provides a Python extra MUST require the extra’s main package with exact NEVR. > NEW: A subpackage that primarily provides one Python extra **SHOULD** be named by appending "+" and the extra name to the main package name. For example, `python3-requests+security`. > OLD: A subpackage that primarily provides one Python extra SHOULD be named by appending `+` and the extra name to the main package name. For example, `python3-requests+security`. </details> ## Files to include More detailed rules on what to include (and where): > NEW: Packages **MUST** include the source file (`*.py`) > **AND** the bytecode cache (`*.pyc`) > for each pure-Python importable module. > The source files **MUST** be included in the same package as the bytecode cache. > NEW: Each Python package **MUST** include *Package Distribution Metadata* conforming to [PyPA specifications](https://packaging.python.org/specifications/) (specifically, [Recording installed distributons](https://packaging.python.org/specifications/recording-installed-packages/)). The metadata **SHOULD** be included in the same subpackage as the main importable module, if there is one. [...] As an exception, the Python standard library **MAY** ship without this metadata. > OLD: When packaging Python modules, several types of files are included: `*.py source files`[,] `*.pyc byte compiled files`[,] `*.egg-info` or `*.dist-info` files or directories. [technically, there is no MUST here] > > The source files MUST be included in the same package as the byte compiled versions. New best practice: not byte-compiling scripts: > NEW: Scripts that are not importable (typically ones in `%{_bindir}` or `%{_libexecdir}`) **SHOULD NOT** be byte-compiled. <details> <summary>Consolidated rules on content in shared directories</summary> > NEW: Packages **MUST NOT** own shared directories owned by Python itself, such as the top-level `__pycache__` directories (`%{python3_sitelib}/__pycache__`, `%{python3_sitearch}/__pycache__`). > NEW: Packagers **SHOULD NOT** simply glob everything under a shared directory. > In particular, the following **SHOULD NOT** be used: `%{python3_sitelib}/*`, `%{python3_sitearch}/*`, `%{python_sitelib}/*`, `%{python_sitearch}/*`, `%{_bindir}/*`, `%pyproject_save_files '*'`, `%pyproject_save_files +auto`. > OLD: Packagers SHOULD NOT simply glob everything under the sitelib or sitearch directories. The following SHOULD NOT be used: `%{python3_sitelib}/*`, `%{python3_sitearch}/*`, `%{python_sitelib}/*`, `%{python_sitearch}/*`. And packages MUST NOT include the top-level `__pycache__` directory (see below). > > OLD: You MUST NOT include the directories `%{python3_sitearch}/__pycache__` or `%{python3_sitelib}/__pycache__` because they are already owned by the `python3-libs` package. </details> ## Mandatory Requires / Provides > NEW: **Every** package that uses Python (at runtime and/or build time), and/or installs Python modules **MUST** explicitly include `BuildRequires: python3-devel` in its `.spec` file, even if Python is not actually invoked during build time. If the package uses an alternate Python interpreter instead of `python3` (e.g. `pypy`, `jython`, `python2.7`), it **MAY** instead require the corresponding `*-devel` package. > NEW: As mentioned above, each Python package **MUST** explicitly BuildRequire `python3-devel`. Packages **MUST NOT** have dependencies (either build-time or runtime) with the unversioned prefix `python-` if the corresponding `python3-` dependency can be used instead. Packages **SHOULD NOT** have explicit dependencies (either build-time or runtime) with a minor-version prefix such as `python3.8-` or `python3.8dist(`. Such dependencies **SHOULD** instead be automatically generated or a macro should be used to get the version. Packages **SHOULD NOT** have an explicit runtime dependency on `python3`. > NEW: Every Python package **MUST** provide `python3dist(DISTNAME)` **and** `python3.Xdist(DISTNAME)`, where `X` is the minor version of the interpreter and `DISTNAME` is the *canonical project name* corresponding to the *dist-info metadata*. For example, `python3-django` would provide `python3dist(django)` and `python3.9dist(django)`. This is generated automatically from the dist-info metadata. The provide **SHOULD NOT** be added manually: if the generator fails to add it, the metadata **MUST** be fixed. ## Tests Running upstream tests is mandatory; linters are discouraged > NEW: If a test suite exists upstream, it **MUST** be run in the `%check` section and/or in Fedora CI. You **MAY** exclude specific failing tests. You **MUST NOT** disable the entire testsuite or ignore the result to solve a build failure. As an exception, you **MAY** disable tests with an appropriate `%if` conditional (e.g. bcond) when [bootstrapping](https://docs.fedoraproject.org/en-US/packaging-guidelines/#bootstrapping). XXX The above was changed to SHOULD after this document was created > NEW: In `%check`, packages **SHOULD NOT** run “linters”: code style checkers, test coverage checkers and other tools that check code quality rather than functionality. ## Shebangs & Mandatory macros The rule regarding `/usr/bin/python` has been generalized to mandatory use of some macros, and rules on shebangs were split off and made stricter. > NEW: The following macros **MUST** be used where applicable. `%{python3}`, `%{python3_version}`, `%{python3_version_nodots}`, `%{python3_sitelib}`, `%{python3_sitearch}`. > NEW: Shebang lines to invoke Python **MUST** use `%{python3}` as the interpreter. > NEW: Shebang lines to invoke Python **SHOULD** be `#!%{python3} -%{py3_shebang_flags}` and it **MAY** include extra flags. If the default flags from `%{py3_shebang_flags}` are not desirable, packages **SHOULD** explicitly redefine the macro to remove them. > OLD: Packages in Fedora MUST NOT use `/usr/bin/python`. Instead packages for Python 3 MUST use `/usr/bin/python3` (even if upstream supports both Python 2 and 3). As a result of that `/usr/bin/python` (as well as `/usr/bin/env python` and similar) MUST NOT be used in shebang lines or as a dependency of a package. All uses of unversioned python executables in shebang lines will fail the build. These shebangs MUST be fixed (for example by using the `%py3_shebang_fix` macro in the spec file). ## PyPI sources PyPI archives that omit tests/docs are discouraged: > NEW: Packages **MAY** use sources from PyPI. However, packages **SHOULD NOT** use an archive that omits test suites, licences and/or documentation present in other source archives. ## Specific macros Redefining `%python3_pkgversion` is banned: > NEW: Packages in Fedora **MAY** use [`%{python3_pkgversion}`] (e.g. in package names: `python%{python3_pkgversion}-requests`), but **MUST NOT** redefine it. <details> <summary>Note on `%pyproject_save_files` features unsuitable for Fedora</summary> > NEW: Note that README and licence files are not included. Also, while the macro allows including executable and other files (using the `+auto` flag), this feature **MUST NOT** be used in Fedora. </details> ## Cython <details> <summary>Clarification; same meaning</summary> > NEW: Tightening the [general Fedora policy](https://docs.fedoraproject.org/en-US/packaging-guidelines/what-can-be-packaged/#_pregenerated_code), packages **MUST NOT** use files pre-generated by Cython. These **MUST** be deleted in `%prep` and regenerated during the build. As an exception, these sources **MAY** be used temporarily to prevent build time circular dependencies by following the [bootstrapping](https://docs.fedoraproject.org/en-US/packaging-guidelines/#bootstrapping) guidelines. > OLD: Tightening the general Fedora policy, packages MUST NOT use pre-generated Cython sources. They MUST be deleted in %prep and regenerated during the build. Any exception to this rule should be considered a bootstrapping. </details> ## Best practices New note on when to prefer `python3 -m tool`: > NEW: Every executable `TOOL` for which the current version of Python matters **SHOULD** also be invokable by `python3 -m TOOL`. If the software doesn't provide this functionality, packagers **SHOULD** ask the upstream to add it.

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully