micropython-branch-manager 3.0.1__tar.gz → 3.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. micropython_branch_manager-3.0.2/.cache/pip/http-v2/3/a/9/0/a/3a90a4636ff8a0016bbb5ae63eff66f7ed5689db21aa1584b5f7036f +0 -0
  2. micropython_branch_manager-3.0.1/.cache/pip/http-v2/b/2/1/a/2/b21a2d54fe091c13377bc0abd5697d45d42eb7ca369341785675df45.body → micropython_branch_manager-3.0.2/.cache/pip/http-v2/3/a/9/0/a/3a90a4636ff8a0016bbb5ae63eff66f7ed5689db21aa1584b5f7036f.body +9 -9
  3. micropython_branch_manager-3.0.2/.cache/pip/http-v2/5/f/7/3/c/5f73c55638bab0e38deb49e63e1b83a8d874933898591baf17441634 +0 -0
  4. micropython_branch_manager-3.0.1/.cache/pip/http-v2/f/9/a/b/3/f9ab31eb3a9dd78406ca10dd83c580077dd9d3c984a8877c762be2f6.body → micropython_branch_manager-3.0.2/.cache/pip/http-v2/5/f/7/3/c/5f73c55638bab0e38deb49e63e1b83a8d874933898591baf17441634.body +0 -0
  5. micropython_branch_manager-3.0.2/.cache/pip/http-v2/a/1/9/5/3/a19537d3cf37c122db841d6fe4cd322bc10d1a558bb00d146b85cb9a +0 -0
  6. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.cache/pip/http-v2/a/1/9/5/3/a19537d3cf37c122db841d6fe4cd322bc10d1a558bb00d146b85cb9a.body +0 -0
  7. micropython_branch_manager-3.0.2/.cache/pip/http-v2/a/d/e/e/f/adeef5b9611702687bbddade5f7c0af65110caf98ba1a0070c9d116e +0 -0
  8. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.cache/pip/http-v2/a/d/e/e/f/adeef5b9611702687bbddade5f7c0af65110caf98ba1a0070c9d116e.body +0 -0
  9. micropython_branch_manager-3.0.2/.cache/pip/selfcheck/fe300af6f7d708c14827daac3afc81fbb8306b73de8dd6e3f1f8ea3b +1 -0
  10. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/PKG-INFO +22 -3
  11. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/README.md +21 -2
  12. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/_version.py +2 -2
  13. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/cli.py +5 -0
  14. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/config.py +1 -0
  15. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/rebase.py +40 -11
  16. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/conftest.py +1 -0
  17. micropython_branch_manager-3.0.2/tests/test_cli.py +50 -0
  18. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_config.py +3 -1
  19. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_integration.py +40 -0
  20. micropython_branch_manager-3.0.1/.cache/pip/http-v2/0/3/e/7/3/03e73f705d8e7ecb1a968fbcda6d411f43fea72aaf46399126c42e61 +0 -0
  21. micropython_branch_manager-3.0.1/.cache/pip/http-v2/0/3/e/7/3/03e73f705d8e7ecb1a968fbcda6d411f43fea72aaf46399126c42e61.body +0 -0
  22. micropython_branch_manager-3.0.1/.cache/pip/http-v2/a/1/9/5/3/a19537d3cf37c122db841d6fe4cd322bc10d1a558bb00d146b85cb9a +0 -0
  23. micropython_branch_manager-3.0.1/.cache/pip/http-v2/a/d/e/e/f/adeef5b9611702687bbddade5f7c0af65110caf98ba1a0070c9d116e +0 -0
  24. micropython_branch_manager-3.0.1/.cache/pip/http-v2/b/2/1/a/2/b21a2d54fe091c13377bc0abd5697d45d42eb7ca369341785675df45 +0 -0
  25. micropython_branch_manager-3.0.1/.cache/pip/http-v2/c/9/1/f/5/c91f580d88bf83782e78be42725d05696c3911af8667eb629ddc701e +0 -0
  26. micropython_branch_manager-3.0.1/.cache/pip/http-v2/c/9/1/f/5/c91f580d88bf83782e78be42725d05696c3911af8667eb629ddc701e.body +0 -355
  27. micropython_branch_manager-3.0.1/.cache/pip/http-v2/f/9/a/b/3/f9ab31eb3a9dd78406ca10dd83c580077dd9d3c984a8877c762be2f6 +0 -0
  28. micropython_branch_manager-3.0.1/.cache/pip/selfcheck/fe300af6f7d708c14827daac3afc81fbb8306b73de8dd6e3f1f8ea3b +0 -1
  29. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.gitignore +0 -0
  30. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.gitlab-ci.yml +0 -0
  31. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.pre-commit-config.yaml +0 -0
  32. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/.python-version +0 -0
  33. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/CLAUDE.md +0 -0
  34. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/LICENSE +0 -0
  35. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/docs/gitlab_mr_example.png +0 -0
  36. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/pyproject.toml +0 -0
  37. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/__init__.py +0 -0
  38. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/__main__.py +0 -0
  39. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/branch_sync.py +0 -0
  40. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/exceptions.py +0 -0
  41. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/git.py +0 -0
  42. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/github.py +0 -0
  43. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/pr.py +0 -0
  44. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/rerere.py +0 -0
  45. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/trailers.py +0 -0
  46. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/src/micropython_branch_manager/update_branch.py +0 -0
  47. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_branch_sync.py +0 -0
  48. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_exceptions.py +0 -0
  49. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_git.py +0 -0
  50. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_github.py +0 -0
  51. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_trailers.py +0 -0
  52. {micropython_branch_manager-3.0.1 → micropython_branch_manager-3.0.2}/tests/test_update_branch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uv
3
- Version: 0.12.19
3
+ Version: 0.13.7
4
4
  Classifier: Development Status :: 5 - Production/Stable
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -51,13 +51,13 @@ An extremely fast Python package and project manager, written in Rust.
51
51
  - A single tool to replace `pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`, and
52
52
  more.
53
53
  - [10-100x faster](https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md) than `pip`.
54
- - Provides [comprehensive project management](https://github.com/astral-sh/uv/blob/0.12.19/README.md#projects), with a
54
+ - Provides [comprehensive project management](https://github.com/astral-sh/uv/blob/0.13.7/README.md#projects), with a
55
55
  [universal lockfile](https://docs.astral.sh/uv/concepts/projects/layout#the-lockfile).
56
- - [Runs scripts](https://github.com/astral-sh/uv/blob/0.12.19/README.md#scripts), with support for
56
+ - [Runs scripts](https://github.com/astral-sh/uv/blob/0.13.7/README.md#scripts), with support for
57
57
  [inline dependency metadata](https://docs.astral.sh/uv/guides/scripts#declaring-script-dependencies).
58
- - [Installs and manages](https://github.com/astral-sh/uv/blob/0.12.19/README.md#python-versions) Python versions.
59
- - [Runs and installs](https://github.com/astral-sh/uv/blob/0.12.19/README.md#tools) tools published as Python packages.
60
- - Includes a [pip-compatible interface](https://github.com/astral-sh/uv/blob/0.12.19/README.md#the-pip-interface) for a performance boost with a familiar
58
+ - [Installs and manages](https://github.com/astral-sh/uv/blob/0.13.7/README.md#python-versions) Python versions.
59
+ - [Runs and installs](https://github.com/astral-sh/uv/blob/0.13.7/README.md#tools) tools published as Python packages.
60
+ - Includes a [pip-compatible interface](https://github.com/astral-sh/uv/blob/0.13.7/README.md#the-pip-interface) for a performance boost with a familiar
61
61
  CLI.
62
62
  - Supports Cargo-style [workspaces](https://docs.astral.sh/uv/concepts/projects/workspaces) for
63
63
  scalable projects.
@@ -308,7 +308,7 @@ It's pronounced as "you - vee" ([`/juː viː/`](https://en.wikipedia.org/wiki/He
308
308
 
309
309
  #### How should I stylize uv?
310
310
 
311
- Just "uv", please. See the [style guide](https://github.com/astral-sh/uv/blob/0.12.19/STYLE.md#styling-uv) for details.
311
+ Just "uv", please. See the [style guide](https://github.com/astral-sh/uv/blob/0.13.7/STYLE.md#styling-uv) for details.
312
312
 
313
313
  #### What platforms does uv support?
314
314
 
@@ -337,9 +337,9 @@ for Windows support.
337
337
 
338
338
  uv is licensed under either of
339
339
 
340
- - Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/astral-sh/uv/blob/0.12.19/LICENSE-APACHE) or
340
+ - Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/astral-sh/uv/blob/0.13.7/LICENSE-APACHE) or
341
341
  <https://www.apache.org/licenses/LICENSE-2.0>)
342
- - MIT license ([LICENSE-MIT](https://github.com/astral-sh/uv/blob/0.12.19/LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
342
+ - MIT license ([LICENSE-MIT](https://github.com/astral-sh/uv/blob/0.13.7/LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
343
343
 
344
344
  at your option.
345
345
 
@@ -0,0 +1 @@
1
+ {"key":"/usr/local","last_check":"2026-11-04T01:19:10.772621+00:00","pypi_version":"26.3"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: micropython-branch-manager
3
- Version: 3.0.1
3
+ Version: 3.0.2
4
4
  Summary: Tool for managing MicroPython fork integration branches
5
5
  Project-URL: Homepage, https://gitlab.com/alelec/micropython-branch-manager
6
6
  Project-URL: Repository, https://gitlab.com/alelec/micropython-branch-manager.git
@@ -16,6 +16,22 @@ Description-Content-Type: text/markdown
16
16
 
17
17
  # micropython-branch-manager
18
18
 
19
+ > **Project rename:** This project will be renamed to `marshal-branch-manager` after this final normal release of `micropython-branch-manager`. The new package is not yet available. It will use the `mbm` command and will not provide the `micropython-branch-manager` command alias.
20
+ >
21
+ > Once the new package is available, to migrate a `uv tool` installation, uninstall the old package before installing the new one. Both packages provide `mbm`, so installing them together causes an executable conflict:
22
+ >
23
+ > ```bash
24
+ > uv tool uninstall micropython-branch-manager
25
+ > uv tool install marshal-branch-manager
26
+ > ```
27
+ >
28
+ > For a pip installation, use the same Python environment for both commands:
29
+ >
30
+ > ```bash
31
+ > python -m pip uninstall micropython-branch-manager
32
+ > python -m pip install marshal-branch-manager
33
+ > ```
34
+
19
35
  `mbm` keeps a fork of a GitHub project up to date when you're carrying a stack of unmerged PRs and local feature branches on top of upstream. It was written for MicroPython (hence the name) but works with any GitHub-hosted project.
20
36
 
21
37
  The idea is simple. Your fork has an _integration branch_ (say `main` or `mimxrt`) which is basically upstream plus one merge commit per feature branch. When upstream moves, `mbm rebase` throws that branch away and rebuilds it: each feature branch is rebased onto the new upstream on its own, then merged in, in the order listed in `mbm.toml`. You get a clean, readable history where every feature is still an isolated branch you can push back to its PR.
@@ -31,7 +47,7 @@ On top of that it:
31
47
  ## Install
32
48
 
33
49
  ```bash
34
- uv tool install micropython-branch-manager
50
+ uv tool install marshal-branch-manager
35
51
  ```
36
52
 
37
53
  You'll also want the GitHub CLI (`gh`) installed and logged in (`gh auth login`). It's used for PR lookups; without it `mbm` still works but can't skip merged PRs or fill in PR details.
@@ -193,7 +209,8 @@ title = "ports/mimxrt: Update nxp_driver to MCUX_2.16.100."
193
209
  author = "andrewleech"
194
210
 
195
211
  [[submodules.branches]]
196
- name = "my-local-hack" # no PR, just a local branch
212
+ name = "my-local-hack" # no PR, lives in your fork or just locally
213
+ author = "andrewleech"
197
214
  ```
198
215
 
199
216
  Per submodule:
@@ -209,6 +226,8 @@ Per branch:
209
226
  - `pr_url`, `pr_number`, `title`: the PR it belongs to, if any
210
227
  - `author`: GitHub owner of the fork the branch lives in, used to decide where to push it
211
228
 
229
+ Branches with a `pr_number` are always fetched fresh from the PR on upstream. Ones without are fetched from the author's fork remote, and `rebase` uses whichever of that and your local branch is newer, so a stale local checkout doesn't matter (and unpushed local commits aren't lost). If the two have diverged it stops and asks you to sort it out first. With no fork remote, or the branch not pushed yet, it just uses the local branch.
230
+
212
231
  Older configs with everything at the top level (no `[[submodules]]`) still load fine.
213
232
 
214
233
  The GitHub repo used for PR lookups comes from the `upstream` remote. If there isn't a GitHub `upstream` remote it assumes `micropython/micropython`.
@@ -1,5 +1,21 @@
1
1
  # micropython-branch-manager
2
2
 
3
+ > **Project rename:** This project will be renamed to `marshal-branch-manager` after this final normal release of `micropython-branch-manager`. The new package is not yet available. It will use the `mbm` command and will not provide the `micropython-branch-manager` command alias.
4
+ >
5
+ > Once the new package is available, to migrate a `uv tool` installation, uninstall the old package before installing the new one. Both packages provide `mbm`, so installing them together causes an executable conflict:
6
+ >
7
+ > ```bash
8
+ > uv tool uninstall micropython-branch-manager
9
+ > uv tool install marshal-branch-manager
10
+ > ```
11
+ >
12
+ > For a pip installation, use the same Python environment for both commands:
13
+ >
14
+ > ```bash
15
+ > python -m pip uninstall micropython-branch-manager
16
+ > python -m pip install marshal-branch-manager
17
+ > ```
18
+
3
19
  `mbm` keeps a fork of a GitHub project up to date when you're carrying a stack of unmerged PRs and local feature branches on top of upstream. It was written for MicroPython (hence the name) but works with any GitHub-hosted project.
4
20
 
5
21
  The idea is simple. Your fork has an _integration branch_ (say `main` or `mimxrt`) which is basically upstream plus one merge commit per feature branch. When upstream moves, `mbm rebase` throws that branch away and rebuilds it: each feature branch is rebased onto the new upstream on its own, then merged in, in the order listed in `mbm.toml`. You get a clean, readable history where every feature is still an isolated branch you can push back to its PR.
@@ -15,7 +31,7 @@ On top of that it:
15
31
  ## Install
16
32
 
17
33
  ```bash
18
- uv tool install micropython-branch-manager
34
+ uv tool install marshal-branch-manager
19
35
  ```
20
36
 
21
37
  You'll also want the GitHub CLI (`gh`) installed and logged in (`gh auth login`). It's used for PR lookups; without it `mbm` still works but can't skip merged PRs or fill in PR details.
@@ -177,7 +193,8 @@ title = "ports/mimxrt: Update nxp_driver to MCUX_2.16.100."
177
193
  author = "andrewleech"
178
194
 
179
195
  [[submodules.branches]]
180
- name = "my-local-hack" # no PR, just a local branch
196
+ name = "my-local-hack" # no PR, lives in your fork or just locally
197
+ author = "andrewleech"
181
198
  ```
182
199
 
183
200
  Per submodule:
@@ -193,6 +210,8 @@ Per branch:
193
210
  - `pr_url`, `pr_number`, `title`: the PR it belongs to, if any
194
211
  - `author`: GitHub owner of the fork the branch lives in, used to decide where to push it
195
212
 
213
+ Branches with a `pr_number` are always fetched fresh from the PR on upstream. Ones without are fetched from the author's fork remote, and `rebase` uses whichever of that and your local branch is newer, so a stale local checkout doesn't matter (and unpushed local commits aren't lost). If the two have diverged it stops and asks you to sort it out first. With no fork remote, or the branch not pushed yet, it just uses the local branch.
214
+
196
215
  Older configs with everything at the top level (no `[[submodules]]`) still load fine.
197
216
 
198
217
  The GitHub repo used for PR lookups comes from the `upstream` remote. If there isn't a GitHub `upstream` remote it assumes `micropython/micropython`.
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '3.0.1'
22
- __version_tuple__ = version_tuple = (3, 0, 1)
21
+ __version__ = version = '3.0.2'
22
+ __version_tuple__ = version_tuple = (3, 0, 2)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -340,6 +340,11 @@ def config(
340
340
 
341
341
  def main() -> None:
342
342
  """Entry point."""
343
+ print(
344
+ "Notice: micropython-branch-manager is being renamed to marshal-branch-manager; "
345
+ "the command remains mbm.",
346
+ file=sys.stderr,
347
+ )
343
348
  try:
344
349
  app()
345
350
  except (MBMError, ValueError) as e:
@@ -14,6 +14,7 @@ TOML_HEADER = """\
14
14
  # micropython-branch-manager (mbm)
15
15
  # Install: pip install micropython-branch-manager
16
16
  # or: uv tool install micropython-branch-manager
17
+ # This project is being renamed to marshal-branch-manager.
17
18
  # Usage: mbm --help
18
19
 
19
20
  """
@@ -157,7 +157,10 @@ class RebaseManager:
157
157
  try:
158
158
  pr = github.get_pr(identifier)
159
159
  except GitHubError as error:
160
- print(f"WARNING: Could not check PR state for {branch.name}: {error}")
160
+ if branch.pr_number is None:
161
+ print(f"INFO: No PR found for {branch.name}; treating it as a local branch")
162
+ else:
163
+ print(f"WARNING: Could not check PR state for {branch.name}: {error}")
161
164
  active.append(branch)
162
165
  continue
163
166
  if branch.author is None:
@@ -267,15 +270,36 @@ class RebaseManager:
267
270
  print(f" Fetching PR #{branch.pr_number} from upstream...")
268
271
  self.git.run("fetch", "upstream", f"+pull/{branch.pr_number}/head:{temp_branch}")
269
272
  return temp_branch
270
- else:
271
- remote = self.git.resolve_remote_for_pr(branch.pr_url)
272
- if remote:
273
- print(f" Fetching {branch.name} from {remote}...")
274
- self.git.run("fetch", remote, branch.name)
275
- remote_ref = f"{remote}/{branch.name}"
276
- if not self.git.branch_exists(branch.name):
277
- self.git.create_branch(branch.name, remote_ref)
273
+ remote = self.git.resolve_push_remote(branch.author, branch.pr_url)
274
+ if not remote:
275
+ if not self.git.branch_exists(branch.name):
276
+ raise GitError(f"Branch {branch.name} not found locally and no fork remote found")
277
+ return branch.name
278
+ print(f" Fetching {branch.name} from {remote}...")
279
+ remote_ref = f"{remote}/{branch.name}"
280
+ self.git.run(
281
+ "fetch", remote, f"+refs/heads/{branch.name}:refs/remotes/{remote_ref}", check=False
282
+ )
283
+ if not self.git.run("rev-parse", "--verify", "--quiet", remote_ref, check=False):
284
+ if not self.git.branch_exists(branch.name):
285
+ raise GitError(f"Branch {branch.name} not found locally or on {remote}")
286
+ print(f" {branch.name} not on {remote}, using local branch")
278
287
  return branch.name
288
+ return self._newest_of(branch.name, remote_ref)
289
+
290
+ def _newest_of(self, local: str, remote_ref: str) -> str:
291
+ """Return whichever of a local branch and its fork copy contains the other.
292
+
293
+ Uses the fork copy when the local branch is missing or behind it, keeps the
294
+ local branch when it is ahead (unpushed work), and fails when they diverge.
295
+ """
296
+ if not self.git.branch_exists(local) or self._is_ancestor(local, remote_ref):
297
+ return remote_ref
298
+ if self._is_ancestor(remote_ref, local):
299
+ return local
300
+ raise GitError(
301
+ f"Local branch {local} has diverged from {remote_ref}; reconcile them before rebasing."
302
+ )
279
303
 
280
304
  def _train_rerere(self, target: str, branches: list[BranchConfig]) -> None:
281
305
  """Train rerere from the active branch stack before rebuilding."""
@@ -329,10 +353,16 @@ class RebaseManager:
329
353
  self, update_branch: str, force_push: bool, branches: list[BranchConfig]
330
354
  ) -> tuple[dict[str, bool], list[RemoteDivergenceError]]:
331
355
  """Push feature branches to their forks and the update branch to GitLab."""
332
- print("\nPushing branches...")
333
356
  push_results: dict[str, bool] = {}
334
357
  divergence_errors: list[RemoteDivergenceError] = []
335
358
  remotes = self.git.list_remotes()
359
+ gitlab_remote = find_gitlab_remote(self.git)
360
+ if self._update_branches:
361
+ print("\nPushing branches...")
362
+ elif gitlab_remote:
363
+ print("\nPushing update branch (feature branches left alone)...")
364
+ else:
365
+ print("\nNo pushes: feature branch updates are off and there's no GitLab remote.")
336
366
 
337
367
  for branch in branches if self._update_branches else []:
338
368
  remote = self.git.resolve_push_remote(branch.author, branch.pr_url, remotes)
@@ -358,7 +388,6 @@ class RebaseManager:
358
388
  push_results[branch.name] = False
359
389
 
360
390
  # Push update branch to GitLab
361
- gitlab_remote = find_gitlab_remote(self.git)
362
391
  if gitlab_remote:
363
392
  try:
364
393
  print(f"Pushing {update_branch} to {gitlab_remote}...")
@@ -32,6 +32,7 @@ SAMPLE_CONFIG_TOML = """\
32
32
  # micropython-branch-manager (mbm)
33
33
  # Install: pip install micropython-branch-manager
34
34
  # or: uv tool install micropython-branch-manager
35
+ # This project is being renamed to marshal-branch-manager.
35
36
  # Usage: mbm --help
36
37
 
37
38
  [[submodules]]
@@ -0,0 +1,50 @@
1
+ """Tests for the command-line entry point."""
2
+
3
+ import subprocess
4
+ import sys
5
+
6
+ NOTICE = (
7
+ "Notice: micropython-branch-manager is being renamed to marshal-branch-manager; "
8
+ "the command remains mbm."
9
+ )
10
+
11
+
12
+ def run_cli(*args, cwd=None):
13
+ return subprocess.run(
14
+ [sys.executable, "-m", "micropython_branch_manager", *args],
15
+ cwd=cwd,
16
+ capture_output=True,
17
+ text=True,
18
+ check=False,
19
+ )
20
+
21
+
22
+ def test_help_shows_notice_on_stderr():
23
+ result = run_cli("--help")
24
+
25
+ assert result.returncode == 0
26
+ assert "Usage:" in result.stdout
27
+ assert NOTICE not in result.stdout
28
+ assert result.stderr.strip() == NOTICE
29
+
30
+
31
+ def test_config_command_remains_functional(tmp_path, sample_config_toml):
32
+ subprocess.run(["git", "init", "-q", str(tmp_path)], check=True)
33
+ config_path = tmp_path / "mbm.toml"
34
+ config_path.write_text(sample_config_toml)
35
+
36
+ result = run_cli("config", "--config", str(config_path))
37
+
38
+ assert result.returncode == 0
39
+ assert "Integration branch: main" in result.stdout
40
+ assert "feature-1: Add feature 1" in result.stdout
41
+ assert NOTICE not in result.stdout
42
+ assert result.stderr.strip() == NOTICE
43
+
44
+
45
+ def test_invalid_command_keeps_failure_status():
46
+ result = run_cli("not-a-command")
47
+
48
+ assert result.returncode != 0
49
+ assert NOTICE in result.stderr
50
+ assert NOTICE not in result.stdout
@@ -104,7 +104,9 @@ def test_config_save(tmp_path):
104
104
  content = config_path.read_text()
105
105
 
106
106
  assert "# micropython-branch-manager (mbm)" in content
107
- assert "uv tool install" in content
107
+ assert "pip install micropython-branch-manager" in content
108
+ assert "uv tool install micropython-branch-manager" in content
109
+ assert "being renamed to marshal-branch-manager" in content
108
110
  assert 'path = "src/micropython"' in content
109
111
  assert 'integration_branch = "develop"' in content
110
112
  assert 'name = "test"' in content
@@ -326,3 +326,43 @@ def test_parse_identifier_rejects_url_for_other_repo(tmp_path):
326
326
  assert manager.parse_identifier(url, "can1357/oh-my-pi") == 13389
327
327
  with pytest.raises(ConfigError):
328
328
  manager.parse_identifier(url, "micropython/micropython")
329
+
330
+
331
+ def _git(cwd, *args):
332
+ import subprocess
333
+
334
+ return subprocess.run(
335
+ ["git", "-c", "user.name=t", "-c", "user.email=t@t", *args],
336
+ cwd=cwd,
337
+ check=True,
338
+ capture_output=True,
339
+ text=True,
340
+ ).stdout.strip()
341
+
342
+
343
+ def test_fork_only_branch_uses_newest_copy_and_rejects_divergence(tmp_path):
344
+ """A branch with no PR integrates the fork copy when the local ref is stale."""
345
+ fork = tmp_path / "fork"
346
+ fork.mkdir()
347
+ _git(fork, "init", "-q", "-b", "main")
348
+ _git(fork, "commit", "-q", "--allow-empty", "-m", "base")
349
+ _git(fork, "branch", "feat")
350
+ work = tmp_path / "work"
351
+ _git(tmp_path, "clone", "-q", str(fork), str(work))
352
+ _git(work, "remote", "set-url", "origin", "https://github.com/me/proj.git")
353
+ _git(work, "config", f"url.{fork}.insteadOf", "https://github.com/me/proj.git")
354
+ _git(work, "branch", "feat", "origin/feat")
355
+ _git(fork, "checkout", "-q", "feat")
356
+ _git(fork, "commit", "-q", "--allow-empty", "-m", "pushed from elsewhere")
357
+
358
+ manager = _make_rebase_manager(work, [BranchConfig(name="feat", author="me")])
359
+ branch = manager.sub.branches[0]
360
+ with patch.object(
361
+ manager.git, "list_remotes", return_value={"origin": "https://github.com/me/proj.git"}
362
+ ):
363
+ assert manager._fetch_pr_branch(branch) == "origin/feat"
364
+
365
+ _git(work, "checkout", "-q", "feat")
366
+ _git(work, "commit", "-q", "--allow-empty", "-m", "local only")
367
+ with pytest.raises(GitError, match="diverged"):
368
+ manager._fetch_pr_branch(branch)
@@ -1,355 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: uv
3
- Version: 0.12.17
4
- Classifier: Development Status :: 5 - Production/Stable
5
- Classifier: Environment :: Console
6
- Classifier: Intended Audience :: Developers
7
- Classifier: Operating System :: OS Independent
8
- Classifier: Programming Language :: Python
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Classifier: Programming Language :: Python :: 3.13
15
- Classifier: Programming Language :: Python :: 3.14
16
- Classifier: Programming Language :: Python :: 3.15
17
- Classifier: Programming Language :: Python :: 3 :: Only
18
- Classifier: Programming Language :: Rust
19
- Classifier: Topic :: Software Development :: Quality Assurance
20
- Classifier: Topic :: Software Development :: Testing
21
- Classifier: Topic :: Software Development :: Libraries
22
- License-File: LICENSE-APACHE
23
- License-File: LICENSE-MIT
24
- Summary: An extremely fast Python package and project manager, written in Rust.
25
- Keywords: uv,requirements,packaging
26
- Home-Page: https://pypi.org/project/uv/
27
- Author-email: "Astral Software Inc." <hey@astral.sh>
28
- License-Expression: MIT OR Apache-2.0
29
- Requires-Python: >=3.8
30
- Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
31
- Project-URL: Changelog, https://github.com/astral-sh/uv/blob/main/CHANGELOG.md
32
- Project-URL: Discord, https://discord.gg/astral-sh
33
- Project-URL: Documentation, https://docs.astral.sh/uv
34
- Project-URL: Releases, https://github.com/astral-sh/uv/releases
35
- Project-URL: Repository, https://github.com/astral-sh/uv
36
-
37
- # uv
38
-
39
- An extremely fast Python package and project manager, written in Rust.
40
-
41
- <p align="center">
42
- <img alt="Shows a bar chart with benchmark results." src="https://github.com/astral-sh/uv/assets/1309177/629e59c0-9c6e-4013-9ad4-adb2bcf5080d">
43
- </p>
44
-
45
- <p align="center">
46
- <i>Installing <a href="https://trio.readthedocs.io/">Trio</a>'s dependencies with a warm cache.</i>
47
- </p>
48
-
49
- ## Highlights
50
-
51
- - A single tool to replace `pip`, `pip-tools`, `pipx`, `poetry`, `pyenv`, `twine`, `virtualenv`, and
52
- more.
53
- - [10-100x faster](https://github.com/astral-sh/uv/blob/main/BENCHMARKS.md) than `pip`.
54
- - Provides [comprehensive project management](https://github.com/astral-sh/uv/blob/0.12.17/README.md#projects), with a
55
- [universal lockfile](https://docs.astral.sh/uv/concepts/projects/layout#the-lockfile).
56
- - [Runs scripts](https://github.com/astral-sh/uv/blob/0.12.17/README.md#scripts), with support for
57
- [inline dependency metadata](https://docs.astral.sh/uv/guides/scripts#declaring-script-dependencies).
58
- - [Installs and manages](https://github.com/astral-sh/uv/blob/0.12.17/README.md#python-versions) Python versions.
59
- - [Runs and installs](https://github.com/astral-sh/uv/blob/0.12.17/README.md#tools) tools published as Python packages.
60
- - Includes a [pip-compatible interface](https://github.com/astral-sh/uv/blob/0.12.17/README.md#the-pip-interface) for a performance boost with a familiar
61
- CLI.
62
- - Supports Cargo-style [workspaces](https://docs.astral.sh/uv/concepts/projects/workspaces) for
63
- scalable projects.
64
- - Disk-space efficient, with a [global cache](https://docs.astral.sh/uv/concepts/cache) for
65
- dependency deduplication.
66
- - Installable without Rust or Python via `curl` or `pip`.
67
- - Supports macOS, Linux, and Windows.
68
-
69
- uv is backed by [Astral](https://astral.sh), the creators of
70
- [Ruff](https://github.com/astral-sh/ruff) and [ty](https://github.com/astral-sh/ty).
71
-
72
- ## Installation
73
-
74
- Install uv with our standalone installers:
75
-
76
- ```bash
77
- # On macOS and Linux.
78
- curl -LsSf https://astral.sh/uv/install.sh | sh
79
- ```
80
-
81
- ```bash
82
- # On Windows.
83
- powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
84
- ```
85
-
86
- Or, from [PyPI](https://pypi.org/project/uv/):
87
-
88
- ```bash
89
- # With pip.
90
- pip install uv
91
- ```
92
-
93
- ```bash
94
- # Or pipx.
95
- pipx install uv
96
- ```
97
-
98
- If installed via the standalone installer, uv can update itself to the latest version:
99
-
100
- ```bash
101
- uv self update
102
- ```
103
-
104
- See the [installation documentation](https://docs.astral.sh/uv/getting-started/installation/) for
105
- details and alternative installation methods.
106
-
107
- ## Documentation
108
-
109
- uv's documentation is available at [docs.astral.sh/uv](https://docs.astral.sh/uv).
110
-
111
- Additionally, the command line reference documentation can be viewed with `uv help`.
112
-
113
- ## Features
114
-
115
- ### Projects
116
-
117
- uv manages project dependencies and environments, with support for lockfiles, workspaces, and more,
118
- similar to `rye` or `poetry`:
119
-
120
- ```console
121
- $ uv init example
122
- Initialized project `example` at `/home/user/example`
123
-
124
- $ cd example
125
-
126
- $ uv add ruff
127
- Creating virtual environment at: .venv
128
- Resolved 2 packages in 170ms
129
- Built example @ file:///home/user/example
130
- Prepared 2 packages in 627ms
131
- Installed 2 packages in 1ms
132
- + example==0.1.0 (from file:///home/user/example)
133
- + ruff==0.5.0
134
-
135
- $ uv run ruff check
136
- All checks passed!
137
-
138
- $ uv lock
139
- Resolved 2 packages in 0.33ms
140
-
141
- $ uv sync
142
- Resolved 2 packages in 0.70ms
143
- Checked 1 package in 0.02ms
144
- ```
145
-
146
- See the [project documentation](https://docs.astral.sh/uv/guides/projects/) to get started.
147
-
148
- uv also supports building and publishing projects, even if they're not managed with uv. See the
149
- [publish guide](https://docs.astral.sh/uv/guides/publish/) to learn more.
150
-
151
- ### Scripts
152
-
153
- uv manages dependencies and environments for single-file scripts.
154
-
155
- Create a new script and add inline metadata declaring its dependencies:
156
-
157
- ```console
158
- $ echo 'import requests; print(requests.get("https://astral.sh"))' > example.py
159
-
160
- $ uv add --script example.py requests
161
- Updated `example.py`
162
- ```
163
-
164
- Then, run the script in an isolated virtual environment:
165
-
166
- ```console
167
- $ uv run example.py
168
- Reading inline script metadata from: example.py
169
- Installed 5 packages in 12ms
170
- <Response [200]>
171
- ```
172
-
173
- See the [scripts documentation](https://docs.astral.sh/uv/guides/scripts/) to get started.
174
-
175
- ### Tools
176
-
177
- uv executes and installs command-line tools provided by Python packages, similar to `pipx`.
178
-
179
- Run a tool in an ephemeral environment using `uvx` (an alias for `uv tool run`):
180
-
181
- ```console
182
- $ uvx pycowsay 'hello world!'
183
- Resolved 1 package in 167ms
184
- Installed 1 package in 9ms
185
- + pycowsay==0.0.0.2
186
- """
187
-
188
- ------------
189
- < hello world! >
190
- ------------
191
- \ ^__^
192
- \ (oo)\_______
193
- (__)\ )\/\
194
- ||----w |
195
- || ||
196
- ```
197
-
198
- Install a tool with `uv tool install`:
199
-
200
- ```console
201
- $ uv tool install ruff
202
- Resolved 1 package in 6ms
203
- Installed 1 package in 2ms
204
- + ruff==0.5.0
205
- Installed 1 executable: ruff
206
-
207
- $ ruff --version
208
- ruff 0.5.0
209
- ```
210
-
211
- See the [tools documentation](https://docs.astral.sh/uv/guides/tools/) to get started.
212
-
213
- ### Python versions
214
-
215
- uv installs Python and allows quickly switching between versions.
216
-
217
- Install multiple Python versions:
218
-
219
- ```console
220
- $ uv python install 3.12 3.13 3.14
221
- Installed 3 versions in 972ms
222
- + cpython-3.12.12-macos-aarch64-none (python3.12)
223
- + cpython-3.13.9-macos-aarch64-none (python3.13)
224
- + cpython-3.14.0-macos-aarch64-none (python3.14)
225
-
226
- ```
227
-
228
- Download Python versions as needed:
229
-
230
- ```console
231
- $ uv venv --python 3.12.0
232
- Using Python 3.12.0
233
- Creating virtual environment at: .venv
234
- Activate with: source .venv/bin/activate
235
-
236
- $ uv run --python pypy@3.8 -- python --version
237
- Python 3.8.16 (a9dbdca6fc3286b0addd2240f11d97d8e8de187a, Dec 29 2022, 11:45:30)
238
- [PyPy 7.3.11 with GCC Apple LLVM 13.1.6 (clang-1316.0.21.2.5)] on darwin
239
- Type "help", "copyright", "credits" or "license" for more information.
240
- >>>>
241
- ```
242
-
243
- Use a specific Python version in the current directory:
244
-
245
- ```console
246
- $ uv python pin 3.11
247
- Pinned `.python-version` to `3.11`
248
- ```
249
-
250
- See the [Python installation documentation](https://docs.astral.sh/uv/guides/install-python/) to get
251
- started.
252
-
253
- ### The pip interface
254
-
255
- uv provides a drop-in replacement for common `pip`, `pip-tools`, and `virtualenv` commands.
256
-
257
- uv extends their interfaces with advanced features, such as dependency version overrides,
258
- platform-independent resolutions, reproducible resolutions, alternative resolution strategies, and
259
- more.
260
-
261
- Migrate to uv without changing your existing workflows — and experience a 10-100x speedup — with the
262
- `uv pip` interface.
263
-
264
- Compile requirements into a platform-independent requirements file:
265
-
266
- ```console
267
- $ uv pip compile requirements.in \
268
- --universal \
269
- --output-file requirements.txt
270
- Resolved 43 packages in 12ms
271
- ```
272
-
273
- Create a virtual environment:
274
-
275
- ```console
276
- $ uv venv
277
- Using Python 3.12.3
278
- Creating virtual environment at: .venv
279
- Activate with: source .venv/bin/activate
280
- ```
281
-
282
- Install the locked requirements:
283
-
284
- ```console
285
- $ uv pip sync requirements.txt
286
- Resolved 43 packages in 11ms
287
- Installed 43 packages in 208ms
288
- + babel==2.15.0
289
- + black==24.4.2
290
- + certifi==2024.7.4
291
- ...
292
- ```
293
-
294
- See the [pip interface documentation](https://docs.astral.sh/uv/pip/index/) to get started.
295
-
296
- ## Contributing
297
-
298
- We are passionate about supporting contributors of all levels of experience and would love to see
299
- you get involved in the project. See the
300
- [contributing guide](https://github.com/astral-sh/uv?tab=contributing-ov-file#contributing) to get
301
- started.
302
-
303
- ## FAQ
304
-
305
- #### How do you pronounce uv?
306
-
307
- It's pronounced as "you - vee" ([`/juː viː/`](https://en.wikipedia.org/wiki/Help:IPA/English#Key))
308
-
309
- #### How should I stylize uv?
310
-
311
- Just "uv", please. See the [style guide](https://github.com/astral-sh/uv/blob/0.12.17/STYLE.md#styling-uv) for details.
312
-
313
- #### What platforms does uv support?
314
-
315
- See uv's [platform support](https://docs.astral.sh/uv/reference/platforms/) document.
316
-
317
- #### Is uv ready for production?
318
-
319
- Yes, uv is stable and widely used in production. See uv's
320
- [versioning policy](https://docs.astral.sh/uv/reference/versioning/) document for details.
321
-
322
- ## Acknowledgements
323
-
324
- uv's dependency resolver uses [PubGrub](https://github.com/pubgrub-rs/pubgrub) under the hood. We're
325
- grateful to the PubGrub maintainers, especially [Jacob Finkelman](https://github.com/Eh2406), for
326
- their support.
327
-
328
- uv's Git implementation is based on [Cargo](https://github.com/rust-lang/cargo).
329
-
330
- Some of uv's optimizations are inspired by the great work we've seen in [pnpm](https://pnpm.io/),
331
- [Orogene](https://github.com/orogene/orogene), and [Bun](https://github.com/oven-sh/bun). We've also
332
- learned a lot from Nathaniel J. Smith's [Posy](https://github.com/njsmith/posy) and adapted its
333
- [trampoline](https://github.com/njsmith/posy/tree/main/src/trampolines/windows-trampolines/posy-trampoline)
334
- for Windows support.
335
-
336
- ## License
337
-
338
- uv is licensed under either of
339
-
340
- - Apache License, Version 2.0, ([LICENSE-APACHE](https://github.com/astral-sh/uv/blob/0.12.17/LICENSE-APACHE) or
341
- <https://www.apache.org/licenses/LICENSE-2.0>)
342
- - MIT license ([LICENSE-MIT](https://github.com/astral-sh/uv/blob/0.12.17/LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
343
-
344
- at your option.
345
-
346
- Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in uv
347
- by you, as defined in the Apache-2.0 license, shall be dually licensed as above, without any
348
- additional terms or conditions.
349
-
350
- <div align="center">
351
- <a target="_blank" href="https://astral.sh" style="background:none">
352
- <img src="https://raw.githubusercontent.com/astral-sh/uv/main/assets/svg/Astral.svg" alt="Made by Astral">
353
- </a>
354
- </div>
355
-
@@ -1 +0,0 @@
1
- {"key":"/usr/local","last_check":"2026-09-22T00:08:41.848944+00:00","pypi_version":"26.2.1"}