Skip to content

Conversation

@jensens
Copy link
Member

@jensens jensens commented Oct 31, 2025

Summary

Adds support for Git's multiple push URL feature, enabling pushing to multiple remotes (e.g., GitHub + GitLab mirrors) automatically. Uses multiline configuration syntax consistent with version-overrides and ignores.

Motivation

Users often need to mirror repositories across multiple Git hosting services (GitHub, GitLab, Bitbucket) for redundancy, CI/CD pipelines, or organizational requirements. Git natively supports multiple push URLs per remote, and mxdev should support this workflow.

Changes

Core Implementation

1. Configuration Parsing (config.py):

  • Added parse_multiline_list() function to parse multiline configuration values
  • Modified package parsing to detect multiple pushurls and create pushurls list
  • First pushurl stored in pushurl key for backward compatibility

2. Git Operations (vcs/git.py):

  • Updated git_set_pushurl() to handle both single and multiple pushurls
  • First pushurl set with git config remote.origin.pushurl URL
  • Additional pushurls set with git config --add remote.origin.pushurl URL

3. Tests (tests/test_config.py, tests/test_git_additional.py):

  • test_config_parse_multiple_pushurls(): Validates multiline parsing and backward compat
  • test_git_set_pushurl_multiple(): Verifies git command sequence with --add flag
  • test_git_checkout_with_multiple_pushurls(): End-to-end integration test

Configuration Example

[my-package]
url = https://github.com/org/repo.git
pushurl =
    git@github.com:org/repo.git
    git@gitlab.com:org/repo.git
    git@bitbucket.org:org/repo.git

When you run git push in the checked-out repository, Git will push to all configured pushurls sequentially.

Backward Compatibility ✅

Fully backward compatible:

  • Single pushurl: pushurl = git@github.com:org/repo.git (unchanged behavior, no pushurls list)
  • Multiple pushurls: New multiline syntax (creates pushurls list)
  • Existing code checking "pushurl" in source continues to work
  • Smart threading requires no changes (checks for presence, not count)

Testing

  • ✅ All 197 tests pass (194 existing + 3 new)
  • ✅ All linting checks pass (ruff, isort, mypy)
  • ✅ Backward compatibility verified with existing single-pushurl tests
  • ✅ New tests cover multiline parsing, git commands, and end-to-end integration

Documentation

  • ✅ README.md: Updated pushurl table entry and added "Multiple Push URLs" section with examples
  • ✅ CHANGES.md: Added feature entry under 5.0.2

Implementation Notes

Git Behavior:

  • Git's native behavior pushes to ALL pushurls sequentially when git push is run
  • If one pushurl fails, Git continues to the next and reports errors
  • This implementation mirrors Git's native multi-pushurl support exactly

Design Decisions:

  • Multiline syntax chosen for consistency with version-overrides and ignores
  • ConfigParser doesn't support duplicate keys, so multiline is the natural choice
  • Smart threading logic unchanged (checks "pushurl" in source for any value)

Related

Complements the smart threading enhancement from PR #69 - HTTPS URLs with any pushurl (single or multiple) are processed in parallel as they're assumed to be public/read-only.

Enables pushing to multiple remotes (e.g., GitHub + GitLab mirrors)
by configuring multiple push URLs using multiline syntax, consistent
with version-overrides and ignores patterns.

Implementation:
- config.py: Add parse_multiline_list() to parse multiline pushurl values
- config.py: Detect and store multiple pushurls as list with backward compat
- vcs/git.py: Update git_set_pushurl() to use --add flag for additional URLs
- First pushurl set without --add, subsequent ones with --add

Configuration example:
```ini
[my-package]
url = https://github.com/org/repo.git
pushurl =
    git@github.com:org/repo.git
    git@gitlab.com:org/repo.git
    git@bitbucket.org:org/repo.git
```

Backward compatibility:
- Single pushurl: Works unchanged (no pushurls list created)
- Multiple pushurls: New multiline syntax (pushurls list created)
- First pushurl stored in pushurl key for backward compat
- Smart threading logic unchanged (checks for pushurl presence)

Tests:
- test_config_parse_multiple_pushurls: Config parsing validation
- test_git_set_pushurl_multiple: Git command sequence verification
- test_git_checkout_with_multiple_pushurls: End-to-end integration

All 197 tests pass (194 existing + 3 new).
All linting checks pass.

Documentation updated in README.md and CHANGES.md.
@jensens jensens force-pushed the feature/multiple-pushurls branch from 3723e3b to 9af2804 Compare October 31, 2025 22:10
@jensens jensens marked this pull request as ready for review October 31, 2025 22:45
@rnixx rnixx merged commit 019c87d into main Nov 3, 2025
17 checks passed
@rnixx rnixx deleted the feature/multiple-pushurls branch November 3, 2025 13:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants