python / core-workflow

Issue tracker for CPython's workflow
https://mail.python.org/mailman/listinfo/core-workflow
Apache License 2.0
94 stars 59 forks source link

Recommend a procedure for branch management #475

Closed jaraco closed 2 years ago

jaraco commented 2 years ago

I discord, @ambv made a simple request:

can you use your own fork for PRs in the future instead of adding branches to python/cpython

And at face value, it sounds like a small request to tweak one's approach in a single project, when in fact the situation is much more complicated.

@jaraco responded

There are advantages to using the canonical repo. One is that I end up with one fewer repos to manage and keep synced. I already have two machines across which I periodically need to sync multiple branches (main, 3.11, ...). Adding a fork in Github means having yet another code location to manage. Another advantage is that Github will automatically re-point PRs from an intermediate branch to the main branch when merged. I'm not sure it will do this across forks. That is, I don't think I can create a PR in the canonical repo that targets a branch in a fork and then have that PR re-point to the canonical main once the targeted branch is merged into the canonical repo. That said, I'd be happy to devise an approach that doesn't cause this consternation. Can you tell me more about the harm experienced by getting those branches? Is it the increased latency due to the extra revisions downloaded or the noise of branch names in the UI output or the cognitive overhead of ignoring those branches or the fact that if everyone adopted this approach it would be unscalable or some combination of those? I'd like to understand the problem better as I'd like to devise a solution that addresses those concerns and my own (or at least capture the concerns for potential future innovation). I plan to explore creating (once again) a fork in Github, but I would appreciate some advice/guidance on how to keep that fork and the forks of that fork up to date. The current developer guide only goes as far as to say "make forks of forks" without much about how to maintain those forks. In particular, how should I configure the client (how many remotes, how to name those remotes, how to configure those remotes (push/pull)), and how can I automate keeping the upstream branches in sync? Do you have any suggestions on how to manage dependent PRs? Perhaps since this issue isn't a simple choice, we should track the issues in core-workflow?

This is that issue.

See https://github.com/python/cpython/pull/94528 for an example of a dependent PR (no longer currently dependent).

jaraco commented 2 years ago

Additional points were discussed but omitted for privacy.

jaraco commented 2 years ago

Problems

I'll try to elaborate on the problems I see with the forks-of-forks methodology:

lack of guidance, divergent approaches

Although some developers have an intuition for how to manage changes from a private fork, it's also a convention. There's no default practice to follow, as is evidenced by a commiter prefacing their workflow with "My local checkout...". Especially if it's a recommended procedure, it would be nice if the developer documentation provided explicit guidance on a methodology that one could follow. It would include terminology ("origin", "upstream") that could be re-used in discussions to reason about it. A developer could adopt a different workflow, but at least someone following the guidance wouldn't have to make these decisions about concerns that haven't affected them.

dependent PR tracking

Github has a feature that allows one PR to target the branch of another PR on which it depends, and when that PR is merged, the dependent PR is re-targeted to the merge target of the original PR, allowing for the creation of series of changes that depend on each other but which should be merged separately. This feature is particularly valuable when introducing a deprecation, where the deprecation step and the removal step are necessarily separated by time between releases.

It's not obvious if Github supports repointing a PR from one org to another based on dependencies. In fact, I'm not even sure that would make sense, because the dependent PR couldn't be created in the origin project.

continuous integration missing

When pushing changes to one's private fork, there's no CI, so one must necessarily create a PR in order to get some confidence in the viability of the code. When pushing to a canonical repo, the CI is run automatically.

It appears it's just a matter of enabling the workflows in the private fork to enable CI.

UI navigation is more difficult

Something of a nitpick, when working on a change, one needs to navigate to the fork. However, when using gh browse, it takes me to the canonical repo, where there's no quick way to navigate to the fork. One must manually override the URL with the user's name or follow the dropdown to "your existing forks" (two additional clicks). In other words, even Github's own cli treats the "upstream" as primary even a fork exists as "origin".

custody of changes

By my recollection, if a PR is submitted from a fork and that fork is deleted, the PR is closed and the changes are lost. It becomes the responsibility of the fork owner to maintain a dependent relationship of their repo on the upstream repo.

It seems risky for a project to potentially lose a contribution because the contributor pulled their fork.

Consider for example python/cpython#94528, which because it's marked DO-NOT-MERGE until Python 3.14, will be around for some time. Do we want to rely on the contributor to maintain their fork for that duration, even if they may not be around to update it when it's ready to be merged?

stale main

It's always the case that clones of the repo will be stale as soon as new commits are accepted to upstream/main. By introducing an intermediate fork, it exacerbates this problem. Even if one sync's main to a local checkout, the intermediate fork is always stale unless one takes action to keep it up to date. The same applies for other official branches (3.x).

Maybe it's okay for the intermediate forks to always be stale, but I personally find it annoying that it exists, especially when not in use.

mistaken PRs

I've more than once run into an issue where I'll attempt to submit a PR for a change I've made and accidentally submit the PR to the fork, introducing noise and toil. Those failed PRs get linked to issues and send notifications, magnifying the mistake.

deviation from workflows in other projects

Many projects follow a more simple methodology, simply cloning the canonical repo and pushing branches to it. There's one remote and none of the problems included herein. If a developer works on one of those projects and cpython, they need to maintain mental models of both forms and determine which form is in use for a given project. It adds to the cognitive burden of switching between projects, or they must adopt the CPython methodology across all projects and the additional overhead/burden that brings. And for self-hosted projects, it's not possible to create a fork (e.g. I can't fork jaraco/keyring).

shared development

Something we don't do enough of is pair programming or shared development, and the private fork model is an impediment to pair development. Users typically don't grant access of their private fork to other individuals, and even if they did, it's an asymmetric relationship, with one person having custody of the code. The Github PR mechanism does help in this regard - if one is at the stage of a review, the PR workflow might grant others access to push additional changes.

For branches in the canonical repo, however, it's straightforward and a symmetric relationship, with developers having a simple relationship to any branch on which they may share development work.

branch proliferation (non-problem)

At first, I thought that the use of multiple forks would exacerbate branch proliferation, but in practice, I don't think it does, and indeed, private forks may help alleviate the problem of branch proliferation by grouping branches by contributor (thereby hiding irrelevant changes across contributors).

jaraco commented 2 years ago

Basically all workflows going outside the norm wind up in [a bad state]. It has features, most don't know about them and those that do may not really won't understand how to use them or know when their understanding is inaccurate. So my advice is: KISS principal: stay away.

If we're following the KISS principle, the simplest solution is one with the least proliferation of forks, where everyone shares the same remote and there's one remote repo to reason about. For someone just getting familiar with version control, a single remote is the only workflow. For smaller projects with a few developers, pushing to a single repo is the norm. Even some large companies have a single monorepo with branches right off that repo. The Mercurial project uses Heptapod and all contributors push branches direct to the main repo (no private forks).

I understand that for CPython, and many large Github projects, the private fork (fork of forks) model is the norm, but that doesn't mean it has to be the case.

dependent PRs (aka PR chains) are a feature GitHub simply lacks.

This is demonstrably false. As observed in python/cpython#94528, when merging the PR on which that one depended, it automatically repointed the target:

image

I stumbled on this feature earlier this year and was pleased to see that it was a feature that Github was working on. Here's a blog describing in detail how one might use it. That blog and other resources acknowledge that the functionality exposes some ambiguity and has room for improvement. It may be the case that this feature only works if the developer is pushing branches to the canonical repo. If the methodology that CPython uses prohibits or discourages this type of workflow, it's a major disadvantage to everything but the most simple contributions.

jaraco commented 2 years ago

To better understand the motivation for a private-fork recommendation, I'd still like to see answers to these questions:

Can you tell me more about the harm experienced by getting those branches? Is it the increased latency due to the extra revisions downloaded or the noise of branch names in the UI output or the cognitive overhead of ignoring those branches or the fact that if everyone adopted this approach it would be unscalable or some combination of those?

In particular, what is the harm if a handful of developers push direct to the canonical repo? What is the harm if everyone does it?

ambv commented 2 years ago

what is the harm if a handful of developers push direct to the canonical repo? What is the harm if everyone does it?

The harm is that it's noise. When you clone the repo, you're not getting any of my in-flight changes because I keep them in my fork. Unless you go and look for an open PR, those changes don't get in the way of your own work.

They do get in the way because now you're sharing a flat namespace for branches with random other developers. There is no convention for naming PR branches and even if we put one in the devguide, automation will ignore it, the Github UI will ignore it, and -- guaranteed! -- some core developers will ignore it.

All branches on the main repository for a project with >100 committers look official and long-living. This is not true for branches only created out of convenience by a handful of core developers. They aren't official, they aren't long-living projects, as we require PRs for every change (besides some release management shenanigans).

There is already a pre-existing recommendation against pushing to the main repository:

Screen Shot 2022-08-20 at 17 47 31

As such, this issue here isn't about choosing a recommendation, it's about whether we want to change the existing recommendation to allow for branches littering the main repository. I'm -1 to such a change.

jaraco commented 2 years ago

There is already a pre-existing recommendation against pushing to the main repository.

Thanks for this reference. I'd missed it when explicitly looking for it. It may be worth linking this recommendation from other locations so it's more prominent.

Thanks also for articulating the harm. That's helpful for making tradeoffs between that and other concerns.

I'm -1 to such a change.

It feels to me like you're weighting the concern of noise far greater than any of the concerns raised above (or discounting them entirely), including concerns that have no feasible solution in a fork-only scenario. In one sentence, you've declared "wontfix" on a whole suite of problems. Was that your intention?

serhiy-storchaka commented 2 years ago
$ git branch | wc -l
331

Do you want to get all these branches on your local computer? And there are 20-30 other active core developers.

gpshead commented 2 years ago

To summarize: GitHub sucks for serious development practices. We knew that going in. It still beat what we had by a long shot and enabled new contributors - https://peps.python.org/pep-0512/.

An issue isn't a good place for these conversations. Use discuss.python.org.

This narrow scope issue looks to me like one merely to clarify our existing defacto "don't push branches on purpose" community standard in whatever committer dev guide docs we have if needed.

Nobody is debating that GH lacks productivity features many of us take for granted in professional environments. But this isn't the place for it. That can't be planned enumerated and resolved in an issue tracker.

gpshead commented 2 years ago

Also: you quoted people from a private chat. Sure, you later edited that to "remove" the content. But it was already too late - it was sent out in emails and remained available in the edit history on the comment. I've deleted the old revisions of the comment edit history that I found as GH happens to let me. (But all of that has been sent via email to anyone watching the full firehose of the repo or live scraping).

In the future please don't paste conversation snippets from a private forum into another access level one without explicit permission from everyone first.

ezio-melotti commented 2 years ago

lack of guidance, divergent approaches

[...] Especially if it's a recommended procedure, it would be nice if the developer documentation provided explicit guidance on a methodology that one could follow. It would include terminology ("origin", "upstream") that could be re-used in discussions to reason about it. [...]

These are documented and used throughout the docs:

dependent PR tracking

Github has a feature that allows one PR to target the branch of another PR on which it depends, and when that PR is merged, the dependent PR is re-targeted to the merge target of the original PR, [...]

It would be interesting to figure out how to handle such workflow and document it in the devguide. Locally you would usually create a branch A from main, and then a branch B from A, but once you push these branches, there are a few more variables involved:

continuous integration missing

[...] It appears it's just a matter of enabling the workflows in the private fork to enable CI.

There is a related discussion here: https://github.com/python/bedevere/pull/461#issuecomment-1141271952

custody of changes

By my recollection, if a PR is submitted from a fork and that fork is deleted, the PR is closed and the changes are lost. It becomes the responsibility of the fork owner to maintain a dependent relationship of their repo on the upstream repo.

I haven't found anything official in the GitHub docs (there is an article about what happens to the forks when upstream is deleted, but not what happens to PRs when the fork is deleted.

I give it a try in https://github.com/zware/test/pull/7 and even though deleting my fork closed the PR, the changes still seem visible and there is a "Reopen" button.

[...] Do we want to rely on the contributor to maintain their fork for that duration, even if they may not be around to update it when it's ready to be merged?

If they allow maintainers to push changes to the branch, then this might not be an issue (even though I'm not sure if it's possible after the fork is deleted). I guess another option would be to create a new branch off of the one created by the OP.

stale main

[...] Maybe it's okay for the intermediate forks to always be stale, but I personally find it annoying that it exists, especially when not in use.

Other than the annoyance this might cause, this is generally not an issue. Locally I pull main from upstream, make changes in a new branch, push the branch on my fork, and create the PR. The status of the main branch of my fork is inconsequential. It's also possible to update it with just a click from the GitHub UI, if you want to update it every once in a while.

mistaken PRs

I've more than once run into an issue where I'll attempt to submit a PR for a change I've made and accidentally submit the PR to the fork, introducing noise and toil. Those failed PRs get linked to issues and send notifications, magnifying the mistake.

This used to happened to me too occasionally, but not anymore. When you push the branch to your fork, it shows you a link that you can follow to create the PR upstream. Alternatively you can go to the main page of the upstream repo, and a green button at the top will let you create a PR from the branch you just pushed to the fork. Both these solutions already have the target branch set automatically to the upstream main, so you don't have to fiddle with it.

deviation from workflows in other projects

[...] If a developer works on one of those projects and cpython, they need to maintain mental models of both forms and determine which form is in use for a given project.

This is true, but expected. I work on a number of projects, some of which I have access to (and I can push branches/commit to main, even if I don't always do), and many where I'm merely an external contributor with no write access and I have to go through my fork. If anything, going through the fork would be the solution that works for all cases, regardless of permissions.

ambv commented 2 years ago

Nobody is debating that GH lacks productivity features many of us take for granted in professional environments. But this isn't the place for it. That can't be planned enumerated and resolved in an issue tracker.

Definitely not on a Github issue tracker 😂

hugovk commented 2 years ago

In particular, what is the harm if a handful of developers push direct to the canonical repo? What is the harm if everyone does it?

CI resources are limited per org or user account where the repo is (e.g. 20 concurrent jobs).

If everyone pushed branches directly to the upstream repo, the CI would get backed up and it would take longer to get feedback from tests, for them and all other PR authors.

jaraco commented 2 years ago

Thanks for all the tips. I'm working on migrating my workflows to align with the recommendations.

One thing I noticed when following the current guidance is that the main branch doesn't track upstream, but instead tracks origin, so git pull leaves main stale:

``` draft $ git clone gh://jaraco/cpython Cloning into 'cpython'... remote: Enumerating objects: 908778, done. remote: Total 908778 (delta 0), reused 0 (delta 0), pack-reused 908778 Receiving objects: 100% (908778/908778), 492.95 MiB | 4.64 MiB/s, done. Resolving deltas: 100% (720624/720624), done. draft $ cd cpython cpython main $ git remote add upstream gh://python/cpython cpython main $ git pull Already up to date. cpython main $ git pull upstream remote: Enumerating objects: 1574, done. remote: Counting objects: 100% (966/966), done. remote: Compressing objects: 100% (90/90), done. remote: Total 1574 (delta 899), reused 923 (delta 876), pack-reused 608 Receiving objects: 100% (1574/1574), 2.18 MiB | 10.00 MiB/s, done. Resolving deltas: 100% (1123/1123), completed with 385 local objects. From https://github.com/python/cpython * [new branch] 3.10 -> upstream/3.10 * [new branch] 3.11 -> upstream/3.11 * [new branch] 3.7 -> upstream/3.7 * [new branch] 3.8 -> upstream/3.8 * [new branch] 3.9 -> upstream/3.9 * [new branch] add-to-asyncio-proj -> upstream/add-to-asyncio-proj * [new branch] gh-93963/remove-importlib-resources-abcs -> upstream/gh-93963/remove-importlib-resources-abcs * [new branch] main -> upstream/main * [new branch] refactor-wait_for -> upstream/refactor-wait_for * [new branch] shared-testcase -> upstream/shared-testcase You asked to pull from the remote 'upstream', but did not specify a branch. Because this is not the default configured remote for your current branch, you must specify a branch on the command line. ```

I think there's a step missing to set branch.main.remote=upstream. That got configured when I ran gh repo fork to create the fork and allowed it to configure the remotes.

``` cpython main $ git config --local branch.main.remote upstream cpython main $ git pull Updating e0d54a4a79..e860e521ec Fast-forward .github/CODEOWNERS | 4 +- .gitignore | 2 + Doc/c-api/init.rst | 24 + Doc/c-api/typeobj.rst | 6 +- Doc/data/refcounts.dat | 8 + Doc/howto/logging-cookbook.rst | 82 ++++ Doc/includes/sqlite3/rowclass.py | 14 - Doc/library/asyncio-task.rst | 2 +- Doc/library/bisect.rst | 2 +- Doc/library/csv.rst | 4 + Doc/library/functions.rst | 4 + Doc/library/io.rst | 8 +- Doc/library/itertools.rst | 19 + Doc/library/json.rst | 43 ++ Doc/library/logging.handlers.rst | 6 + Doc/library/multiprocessing.rst | 10 + Doc/library/pathlib.rst | 2 +- Doc/library/sqlite3.rst | 251 +++++----- Doc/library/threading.rst | 32 +- Doc/reference/lexical_analysis.rst | 33 +- Doc/tutorial/datastructures.rst | 2 +- Doc/using/configure.rst | 2 +- Include/cpython/ceval.h | 2 + Include/internal/pycore_ceval.h | 3 + Include/internal/pycore_compile.h | 5 + Include/internal/pycore_frame.h | 4 +- Include/internal/pycore_global_objects.h | 2 + Include/internal/pycore_global_strings.h | 2 + Include/internal/pycore_pystate.h | 7 +- Include/internal/pycore_runtime_init_generated.h | 14 + Lib/argparse.py | 4 +- Lib/asyncio/streams.py | 4 +- Lib/csv.py | 4 + Lib/inspect.py | 6 +- Lib/json/__init__.py | 52 +- Lib/logging/__init__.py | 2 +- Lib/logging/handlers.py | 21 +- Lib/test/support/bytecode_helper.py | 93 ++++ Lib/test/test_argparse.py | 7 + Lib/test/test_builtin.py | 5 + Lib/test/test_capi.py | 15 + Lib/test/test_compile.py | 5 +- Lib/test/test_coroutines.py | 24 + Lib/test/test_csv.py | 28 ++ Lib/test/test_imp.py | 6 +- Lib/test/test_importlib/test_abc.py | 4 +- Lib/test/test_json/__init__.py | 1 + Lib/test/test_json/test_attrdict.py | 145 ++++++ Lib/test/test_launcher.py | 8 +- Lib/test/test_logging.py | 8 + Lib/test/test_minidom.py | 16 +- Lib/test/test_peepholer.py | 78 ++- Lib/test/test_socket.py | 15 +- Lib/test/test_source_encoding.py | 105 ++-- Lib/test/test_threading.py | 59 +++ Lib/test/test_unicodedata.py | 20 +- Lib/test/test_unittest/test_async_case.py | 9 +- Lib/threading.py | 27 +- Lib/xml/dom/minidom.py | 2 + Makefile.pre.in | 51 +- Misc/ACKS | 3 + Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst | 2 + Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst | 3 + Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst | 7 + Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst | 1 + Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst | 4 + Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst | 2 + Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst | 5 + Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst | 3 + Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst | 1 + Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst | 3 + Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst | 1 + Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst | 1 + Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst | 1 + Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst | 3 + Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst | 2 + Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst | 3 + Modules/_testinternalcapi.c | 30 +- Modules/atexitmodule.c | 2 +- Modules/clinic/_testinternalcapi.c.h | 68 +++ Modules/makesetup | 2 +- Modules/unicodedata_db.h | 1107 +++++++++++++++++++++-------------------- Objects/codeobject.c | 2 +- Objects/frameobject.c | 8 +- Objects/object_layout.md | 82 ++++ Objects/object_layout_312.gv | 50 ++ Objects/object_layout_312.png | Bin 0 -> 30688 bytes Objects/object_layout_full_312.gv | 25 + Objects/object_layout_full_312.png | Bin 0 -> 17092 bytes Objects/typeobject.c | 35 +- Objects/unicodeobject.c | 39 +- PCbuild/_freeze_module.vcxproj | 1 + PCbuild/_freeze_module.vcxproj.filters | 3 + PCbuild/pythoncore.vcxproj | 2 +- PCbuild/pythoncore.vcxproj.filters | 6 +- Python/ceval.c | 701 +++----------------------- Python/ceval_gil.c | 986 +++++++++++++++++++++++++++++++++++++ Python/ceval_gil.h | 333 ------------- Python/clinic/sysmodule.c.h | 26 +- Python/compile.c | 319 +++++++++--- Python/frame.c | 4 +- Python/sysmodule.c | 61 +++ Tools/c-analyzer/c_parser/info.py | 1 + Tools/c-analyzer/cpython/_analyzer.py | 72 +++ Tools/c-analyzer/cpython/_parser.py | 1 - Tools/c-analyzer/cpython/globals-to-fix.tsv | 4 +- Tools/c-analyzer/cpython/ignored.tsv | 1541 +--------------------------------------------------------- Tools/gdb/libpython.py | 2 +- Tools/msi/build.bat | 19 +- Tools/msi/buildrelease.bat | 43 +- Tools/unicode/makeunicodedata.py | 32 +- configure | 86 +++- configure.ac | 33 +- 113 files changed, 3726 insertions(+), 3468 deletions(-) delete mode 100644 Doc/includes/sqlite3/rowclass.py create mode 100644 Lib/test/test_json/test_attrdict.py create mode 100644 Misc/NEWS.d/next/Build/2022-08-15-10-56-07.gh-issue-95973.Bsswsc.rst create mode 100644 Misc/NEWS.d/next/Build/2022-08-26-11-50-03.gh-issue-96269.x_J5h0.rst create mode 100644 Misc/NEWS.d/next/C API/2022-06-06-16-04-14.gh-issue-93503.MHJTu8.rst create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-15-20-52-41.gh-issue-93678.X7GuIJ.rst create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-18-13-47-59.gh-issue-96046.5Hqbka.rst create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-22-21-33-28.gh-issue-96187.W_6SRG.rst create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-08-24-14-30-26.gh-issue-96237.msif5f.rst create mode 100644 Misc/NEWS.d/next/Documentation/2022-08-19-17-07-45.gh-issue-96098.nDp43u.rst create mode 100644 Misc/NEWS.d/next/Library/2022-04-01-09-43-54.bpo-32547.NIUiNC.rst create mode 100644 Misc/NEWS.d/next/Library/2022-05-09-21-31-41.gh-issue-92445.tJosdm.rst create mode 100644 Misc/NEWS.d/next/Library/2022-08-20-12-56-15.gh-issue-96145.8ah3pE.rst create mode 100644 Misc/NEWS.d/next/Library/2022-08-22-13-54-20.gh-issue-96175.bH7zGU.rst create mode 100644 Misc/NEWS.d/next/Library/2022-08-22-18-42-17.gh-issue-96159.3bFU39.rst create mode 100644 Misc/NEWS.d/next/Library/2022-08-23-13-30-30.gh-issue-96172.7WTHer.rst create mode 100644 Misc/NEWS.d/next/Library/2022-08-27-14-38-49.gh-issue-90467.VOOB0p.rst create mode 100644 Misc/NEWS.d/next/Tests/2022-08-22-14-59-42.gh-issue-95243.DeD66V.rst create mode 100644 Modules/clinic/_testinternalcapi.c.h create mode 100644 Objects/object_layout.md create mode 100644 Objects/object_layout_312.gv create mode 100644 Objects/object_layout_312.png create mode 100644 Objects/object_layout_full_312.gv create mode 100644 Objects/object_layout_full_312.png create mode 100644 Python/ceval_gil.c delete mode 100644 Python/ceval_gil.h ```
jaraco commented 2 years ago

I may or may not follow up on chained PRs. And the documentation is actually quite complete. I'm unsure where I got the impression that the documentation did not capture some basic guidance on branching strategy.