Compare commits

..
4 Commits
Author SHA1 Message Date
Romaric Jodin 3656290156 upload: add --ignore-remote-commits
When uploading a branch that merges another remote-tracking branch (such
as an upstream branch into the destination branch), ReviewableBranch
only excludes the destination tracking branch (^base). As a result, git
rev-list walks the merged parent and counts all merged commits even
though they already exist on a remote branch, triggering the unusual
commit count warning in _VerifyPendingCommits.

Add --ignore-remote-commits to `repo upload` to pass --not --remotes to
git rev-list in ReviewableBranch so commits already reachable from
refs/remotes/* are excluded from the pending commit list.

Test: ./run_tests tests/test_project.py tests/test_subcmds_upload.py
Change-Id: Ib1fb864982729e20a621144580fe95daa478eaee
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/651284
Tested-by: Romaric Jodin <rjodin@google.com>
Reviewed-by: Brian Gan <brgan@google.com>
Commit-Queue: Romaric Jodin <rjodin@google.com>
2026-11-03 00:10:19 -08:00
Brian Gan b90c7cd8f9 docs: add Repology links for distro package versions
The Ubuntu and Debian release wiki pages added in
https://gerrit-review.googlesource.com/c/git-repo/+/649983 only list
distro release and EOL dates, not which versions of Python, Git, or
OpenSSH shipped in each distro release.

Add Repology package version links alongside the distro release pages
in python-support.md and requirements.json so maintainers can check
which versions shipped across historical Ubuntu and Debian releases.

Bug: 575551885
Change-Id: Ib256fd9b364074b52d3e15d185af519d8376cb28
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/650868
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Brian Gan <brgan@google.com>
Commit-Queue: Brian Gan <brgan@google.com>
2026-11-02 13:20:14 -08:00
Brian Gan c5340585b8 docs: release: update release process to match current practice
The documented process has drifted from how releases are actually done:
* Releases are now cut weekly by an automated pipeline, so the manual
  steps are only a fallback, and for rollbacks.
* Releases are tested (both updating an existing checkout and a fresh
  init) before pushing anything.
* The tag is pushed & announced first, and only promoted to stable after
  a day.
* Direct pushes to the stable branch are rejected, so it has to be
  deleted & recreated via the Gerrit REST API instead.

Bug: 575551885
Change-Id: Ib36df07811c225558aba1a925b9703f3b2017e6f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/649984
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Brian Gan <brgan@google.com>
Commit-Queue: Brian Gan <brgan@google.com>
2026-10-27 12:29:45 -07:00
Brian Gan 86a7bec83d docs: release: remove stale Project References table
The table of git/python/ssh/distro versions hasn't been kept up to date
and duplicates information maintained upstream by the distros and
projects themselves.  Drop it, and point the places that referenced it
(python-support.md & requirements.json) at the Ubuntu & Debian release
pages instead.

Bug: 575551885
Change-Id: Id1cb2225b3852273ca717fc7a443449fb2fd006e
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/649983
Reviewed-by: Gavin Mak <gavinmak@google.com>
Tested-by: Brian Gan <brgan@google.com>
Commit-Queue: Brian Gan <brgan@google.com>
2026-10-27 10:39:40 -07:00
9 changed files with 201 additions and 220 deletions

No files matched your search

+1
View File
@@ -411,6 +411,7 @@ _repo() {
'(-y --yes)'{-y,--yes}'[Answer yes to all prompts]' \
'--ignore-untracked-files[Ignore untracked files]' \
'--no-ignore-untracked-files[Do not ignore untracked files]' \
'--ignore-remote-commits[Ignore commits already in remote branches]' \
'--no-cert-checks[Do not check certificates]' \
'--no-verify[Do not verify]' \
'--verify[Verify]' \
+7 -4
View File
@@ -45,10 +45,10 @@ that are critical to us.
That said, let's assume we need functionality that only exists in Python 3.7.
How do we decide when it's acceptable to drop Python 3.6?
1. Review the [Project References](./release-process.md#project-references) to
see what major distros are using the previous version of Python, and when
they go EOL. Generally we care about Ubuntu LTS & current/previous Debian
stable versions.
1. Review what major distros are using the previous version of Python (e.g.
via [Repology Python versions]), and when they go EOL (e.g. via
[Ubuntu releases] & [Debian releases]). Generally we care about Ubuntu LTS
& current/previous Debian stable versions.
* If they're all EOL already, then go for it, drop support.
* If they aren't EOL, start a thread on [repo-discuss] to see how the user
base feels about the proposal.
@@ -88,5 +88,8 @@ $ repo-2.32 init --repo-rev=repo-1 ...
[repo-discuss]: https://groups.google.com/forum/#!forum/repo-discuss
[Debian releases]: https://wiki.debian.org/DebianReleases#Versions_of_Debian_stable
[Repology Python versions]: https://repology.org/project/python/versions
[repo hooks]: ./repo-hooks.md
[repo launcher]: ../repo
[Ubuntu releases]: https://wiki.ubuntu.com/Releases
+54 -200
View File
@@ -5,11 +5,19 @@ related topics and flows.
[TOC]
## Schedule
## Schedule {#schedule}
Releases are automated.
Every Tuesday morning [US PT], a pipeline checks if any new commits have landed
since last release.
If so, it tags & tests the latest `main`, pushes & announces the tag, and then
promotes it to `stable` a day later.
The release is skipped if there's a holiday or [production freeze](#freeze)
that week.
Maintainers can also trigger it by hand.
The [manual steps](#manual) below are only needed as a fallback, or to roll
back a release.
There is no specific schedule for when releases are made.
Usually it's more along the lines of "enough minor changes have been merged",
or "there's a known issue the maintainers know should get fixed".
If you find a fix has been merged for an issue important to you, but hasn't been
released after a week or so, feel free to [contact] us to request a new release.
@@ -48,6 +56,11 @@ Whenever major changes are made to the launcher script, you should increment the
At runtime, repo will check this to see if it needs to be updated (and notify
the user automatically).
When `VERSION` changes, the release pipeline publishes the new launcher to the
`git-repo-downloads` Google Cloud Storage bucket.
To publish it by hand, run `./release/sign-launcher.py`, which signs the
launcher and prints the commands to upload it.
## Key management
Every release has a git tag that is signed with a key that repo recognizes.
@@ -96,8 +109,8 @@ If that tag is valid, then repo will warn and use that commit instead.
If that tag cannot be verified, it gives up and forces the user to resolve.
If env variable `REPO_SKIP_SELF_UPDATE` is defined, this will
bypass the self update algorithm.
If the env variable `REPO_SKIP_SELF_UPDATE` is set to anything other than `0`,
`repo sync` will bypass the self update algorithm.
### Force an update
@@ -110,29 +123,20 @@ All development happens on the `main` branch and should generally be stable.
Since the repo launcher defaults to tracking the `stable` branch, it is not
normally updated until a new release is available.
If something goes wrong with a new release, an older release can be force pushed
and clients will automatically downgrade.
The `maint` branch is used to track the previous major release of repo.
It is not normally meant to be used by people as `stable` should be good enough.
Once a new major release is pushed to the `stable` branch, then the previous
major release can be pushed to `maint`.
For example, when `stable` moves from `v1.10.x` to `v1.11.x`, then the `maint`
branch will be updated from `v1.9.x` to `v1.10.x`.
If something goes wrong with a new release, `stable` can be pointed back at an
older release and clients will automatically downgrade.
We don't have parallel release branches/series.
Typically all tags are made against the `main` branch and then pushed to the
Typically all tags are made against the `main` branch and then promoted to the
`stable` branch to make it available to the rest of the world.
Since repo doesn't typically see a lot of changes, this tends to be OK.
## Creating a new release
## Creating a new release {#manual}
When you want to create a new release, you'll need to select a good version and
Releases are normally created automatically (see [Schedule](#schedule)).
If you need to create one by hand, you'll need to select a good version and
create a signed tag using a key registered in repo itself.
Typically we just tag the latest version of the `main` branch.
The tag could be pushed now, but it won't be used by clients normally (since the
default `repo-rev` setting is `stable`).
This would allow some early testing on systems who explicitly select `main`.
### Creating a signed tag
@@ -147,10 +151,10 @@ internal processes for accessing the restricted keys.
```sh
# Pick the new version.
$ t=v2.30
$ t=v2.XX
# Create a new signed tag with the current HEAD.
$ ./release/sign-tag.py $t
# Create a new signed tag of the latest main branch.
$ ./release/sign-tag.py $t origin/main
# Verify the signed tag.
$ git show $t
@@ -158,199 +162,49 @@ $ git show $t
### Push the new release
Once you're ready to make the release available to everyone, push it to the
`stable` branch.
Make sure you never push the tag itself to the stable branch!
Only push the commit -- note the use of `^0` below.
First push the tag, [announce](#announce) it, and wait a day to get feedback
from people testing new releases early.
```sh
$ git push https://gerrit-review.googlesource.com/git-repo $t
$ git push https://gerrit-review.googlesource.com/git-repo $t^0:stable
```
If something goes horribly wrong, you can force push the previous version to the
`stable` branch and people should automatically recover.
Again, make sure you never push the tag itself!
Then make the release available to everyone by updating the `stable` branch.
Direct pushes to it are rejected, so it has to be deleted & recreated via the
authenticated [Gerrit REST API] (see [go/repo-release] for maintainers).
Make sure you never point the stable branch at the tag itself!
Only use the commit -- note the use of `^0` below.
The commit is resolved before deleting anything so that a bad `$t` can't leave
`stable` missing.
```sh
$ oldrev="whatever-old-commit"
$ git push https://gerrit-review.googlesource.com/git-repo $oldrev:stable --force
$ api=https://gerrit-review.googlesource.com/a/projects/git-repo/branches/stable
$ rev=$(git rev-parse --verify "$t^0") && \
curl --fail -X DELETE "$api" && \
curl --fail -X PUT -H 'Content-Type: application/json' \
-d "{\"revision\":\"$rev\"}" "$api"
```
### Announce the release
If something goes horribly wrong, run the same commands with the previous
release (e.g. `t=$(git describe --abbrev=0 $t^0~)`) and people should
automatically recover.
Once you do push a new release to `stable`, make sure to announce it on the
[repo-discuss@googlegroups.com] group.
### Announce the release {#announce}
Once you push a new release, make sure to announce it on the
[repo-discuss@googlegroups.com] group, and follow up once it's on `stable`.
Here is an [example announcement].
You can create a short changelog using the command:
You can create a short changelog since the previous release using the command:
```sh
# If you haven't pushed to the stable branch yet, you can use origin/stable.
# If you have pushed, change origin/stable to the previous release tag.
# This assumes "main" is the current tagged release. If it's newer, change it
# to the current release tag too.
$ git log --format="%h (%aN) %s" --no-merges origin/stable..main
$ git log --format="%h (%aN) %s" --no-merges \
$(git describe --abbrev=0 $t^0~)..$t
```
## Project References
Here's a table showing the relationship of major tools, their EOL dates, and
their status in Ubuntu & Debian.
Those distros tend to be good indicators of how long we need to support things.
Things in bold indicate stuff to take note of, but does not guarantee that we
still support them.
Things in italics are things we used to care about but probably don't anymore.
| Date | EOL | [Git][rel-g] | [Python][rel-p] | [SSH][rel-o] | [Ubuntu][rel-u] / [Debian][rel-d] | Git | Python | SSH |
|:--------:|:------------:|:------------:|:---------------:|:------------:|-----------------------------------|:---:|:------:|:---:|
| Apr 2008 | | | | 5.0 |
| Jun 2008 | | | | 5.1 |
| Oct 2008 | *Oct 2013* | | 2.6.0 | | *10.04 Lucid* - 10.10 Maverick / *Squeeze* |
| Dec 2008 | *Feb 2009* | | 3.0.0 |
| Feb 2009 | | | | 5.2 |
| Feb 2009 | *Mar 2012* | | | | Debian 5 Lenny | 1.5.6.5 | 2.5.2 |
| Jun 2009 | *Jun 2016* | | 3.1.0 | | *10.04 Lucid* - 10.10 Maverick / *Squeeze* |
| Sep 2009 | | | | 5.3 | *10.04 Lucid* |
| Feb 2010 | *Oct 2012* | 1.7.0 | | | *10.04 Lucid* - *12.04 Precise* - 12.10 Quantal |
| Mar 2010 | | | | 5.4 |
| Apr 2010 | | | | 5.5 | 10.10 Maverick |
| Apr 2010 | *Apr 2015* | | | | *10.04 Lucid* | 1.7.0.4 | 2.6.5 3.1.2 | 5.3 |
| Jul 2010 | *Dec 2019* | | *2.7.0* | | 11.04 Natty - *<current>* |
| Aug 2010 | | | | 5.6 |
| Oct 2010 | | | | | 10.10 Maverick | 1.7.1 | 2.6.6 3.1.3 | 5.5 |
| Jan 2011 | | | | 5.7 |
| Feb 2011 | | | | 5.8 | 11.04 Natty |
| Feb 2011 | *Feb 2016* | | | | Debian 6 Squeeze | 1.7.2.5 | 2.6.6 3.1.3 |
| Apr 2011 | | | | | 11.04 Natty | 1.7.4 | 2.7.1 3.2.0 | 5.8 |
| Sep 2011 | | | | 5.9 | *12.04 Precise* |
| Oct 2011 | *Feb 2016* | | 3.2.0 | | 11.04 Natty - 12.10 Quantal |
| Oct 2011 | | | | | 11.10 Ocelot | 1.7.5.4 | 2.7.2 3.2.2 | 5.8 |
| Apr 2012 | | | | 6.0 | 12.10 Quantal |
| Apr 2012 | *Apr 2019* | | | | *12.04 Precise* | 1.7.9.5 | 2.7.3 3.2.3 | 5.9 |
| Aug 2012 | | | | 6.1 | 13.04 Raring |
| Sep 2012 | *Sep 2017* | | 3.3.0 | | 13.04 Raring - 13.10 Saucy |
| Oct 2012 | *Dec 2014* | 1.8.0 | | | 13.04 Raring - 13.10 Saucy |
| Oct 2012 | | | | | 12.10 Quantal | 1.7.10.4 | 2.7.3 3.2.3 | 6.0 |
| Mar 2013 | | | | 6.2 | 13.10 Saucy |
| Apr 2013 | | | | | 13.04 Raring | 1.8.1.2 | 2.7.4 3.3.1 | 6.1 |
| May 2013 | *May 2018* | | | | Debian 7 Wheezy | 1.7.10.4 | 2.7.3 3.2.3 |
| Sep 2013 | | | | 6.3 |
| Oct 2013 | | | | | 13.10 Saucy | 1.8.3.2 | 2.7.5 3.3.2 | 6.2 |
| Nov 2013 | | | | 6.4 |
| Jan 2014 | | | | 6.5 |
| Feb 2014 | *Dec 2014* | **1.9.0** | | | *14.04 Trusty* |
| Mar 2014 | *Mar 2019* | | *3.4.0* | | *14.04 Trusty* - 15.10 Wily / *Jessie* |
| Mar 2014 | | | | 6.6 | *14.04 Trusty* - 14.10 Utopic |
| Apr 2014 | *Apr 2024* | | | | *14.04 Trusty* | 1.9.1 | 2.7.5 3.4.0 | 6.6 |
| May 2014 | *Dec 2014* | 2.0.0 |
| Aug 2014 | *Dec 2014* | *2.1.0* | | | 14.10 Utopic - 15.04 Vivid / *Jessie* |
| Oct 2014 | | | | 6.7 | 15.04 Vivid |
| Oct 2014 | | | | | 14.10 Utopic | 2.1.0 | 2.7.8 3.4.2 | 6.6 |
| Nov 2014 | *Sep 2015* | 2.2.0 |
| Feb 2015 | *Sep 2015* | 2.3.0 |
| Mar 2015 | | | | 6.8 |
| Apr 2015 | *May 2017* | 2.4.0 |
| Apr 2015 | *Jun 2020* | | | | *Debian 8 Jessie* | 2.1.4 | 2.7.9 3.4.2 |
| Apr 2015 | | | | | 15.04 Vivid | 2.1.4 | 2.7.9 3.4.3 | 6.7 |
| Jul 2015 | *May 2017* | 2.5.0 | | | 15.10 Wily |
| Jul 2015 | | | | 6.9 | 15.10 Wily |
| Aug 2015 | | | | 7.0 |
| Aug 2015 | | | | 7.1 |
| Sep 2015 | *May 2017* | 2.6.0 |
| Sep 2015 | *Sep 2020* | | *3.5.0* | | *16.04 Xenial* - 17.04 Zesty / *Stretch* |
| Oct 2015 | | | | | 15.10 Wily | 2.5.0 | 2.7.9 3.4.3 | 6.9 |
| Jan 2016 | *Jul 2017* | *2.7.0* | | | *16.04 Xenial* |
| Feb 2016 | | | | 7.2 | *16.04 Xenial* |
| Mar 2016 | *Jul 2017* | 2.8.0 |
| Apr 2016 | *Apr 2026* | | | | *16.04 Xenial* | 2.7.4 | 2.7.11 3.5.1 | 7.2 |
| Jun 2016 | *Jul 2017* | 2.9.0 | | | 16.10 Yakkety |
| Jul 2016 | | | | 7.3 | 16.10 Yakkety |
| Sep 2016 | *Sep 2017* | 2.10.0 |
| Oct 2016 | | | | | 16.10 Yakkety | 2.9.3 | 2.7.11 3.5.1 | 7.3 |
| Nov 2016 | *Sep 2017* | *2.11.0* | | | 17.04 Zesty / *Stretch* |
| Dec 2016 | **Dec 2021** | | **3.6.0** | | 17.10 Artful - **18.04 Bionic** - 18.10 Cosmic |
| Dec 2016 | | | | 7.4 | 17.04 Zesty / *Debian 9 Stretch* |
| Feb 2017 | *Sep 2017* | 2.12.0 |
| Mar 2017 | | | | 7.5 | 17.10 Artful |
| Apr 2017 | | | | | 17.04 Zesty | 2.11.0 | 2.7.13 3.5.3 | 7.4 |
| May 2017 | *May 2018* | 2.13.0 |
| Jun 2017 | *Jun 2022* | | | | *Debian 9 Stretch* | 2.11.0 | 2.7.13 3.5.3 | 7.4 |
| Aug 2017 | *Dec 2019* | 2.14.0 | | | 17.10 Artful |
| Oct 2017 | *Dec 2019* | 2.15.0 |
| Oct 2017 | | | | 7.6 | **18.04 Bionic** |
| Oct 2017 | | | | | 17.10 Artful | 2.14.1 | 2.7.14 3.6.3 | 7.5 |
| Jan 2018 | *Dec 2019* | 2.16.0 |
| Apr 2018 | *Mar 2021* | **2.17.0** | | | **18.04 Bionic** |
| Apr 2018 | | | | 7.7 | 18.10 Cosmic |
| Apr 2018 | **Apr 2028** | | | | **18.04 Bionic** | 2.17.0 | 2.7.15 3.6.5 | 7.6 |
| Jun 2018 | *Mar 2021* | 2.18.0 |
| Jun 2018 | **Jun 2023** | | 3.7.0 | | 19.04 Disco - **Buster** |
| Aug 2018 | | | | 7.8 |
| Sep 2018 | *Mar 2021* | 2.19.0 | | | 18.10 Cosmic |
| Oct 2018 | | | | 7.9 | 19.04 Disco / **Buster** |
| Oct 2018 | | | | | 18.10 Cosmic | 2.19.1 | 2.7.15 3.6.6 | 7.7 |
| Dec 2018 | *Mar 2021* | **2.20.0** | | | 19.04 Disco - 19.10 Eoan / **Buster** |
| Feb 2019 | *Mar 2021* | 2.21.0 |
| Apr 2019 | | | | 8.0 | 19.10 Eoan |
| Apr 2019 | | | | | 19.04 Disco | 2.20.1 | 2.7.16 3.7.3 | 7.9 |
| Jun 2019 | | 2.22.0 |
| Jul 2019 | **Jul 2024** | | | | **Debian 10 Buster** | 2.20.1 | 2.7.16 3.7.3 | 7.9 |
| Aug 2019 | *Mar 2021* | 2.23.0 |
| Oct 2019 | **Oct 2024** | | 3.8.0 | | **20.04 Focal** - 20.10 Groovy |
| Oct 2019 | | | | 8.1 |
| Oct 2019 | | | | | 19.10 Eoan | 2.20.1 | 2.7.17 3.7.5 | 8.0 |
| Nov 2019 | *Mar 2021* | 2.24.0 |
| Jan 2020 | *Mar 2021* | 2.25.0 | | | **20.04 Focal** |
| Feb 2020 | | | | 8.2 | **20.04 Focal** |
| Mar 2020 | *Mar 2021* | 2.26.0 |
| Apr 2020 | **Apr 2030** | | | | **20.04 Focal** | 2.25.1 | 2.7.17 3.8.2 | 8.2 |
| May 2020 | *Mar 2021* | 2.27.0 | | | 20.10 Groovy |
| May 2020 | | | | 8.3 |
| Jul 2020 | *Mar 2021* | 2.28.0 |
| Sep 2020 | | | | 8.4 | 21.04 Hirsute / **Bullseye** |
| Oct 2020 | *Mar 2021* | 2.29.0 |
| Oct 2020 | | | | | 20.10 Groovy | 2.27.0 | 2.7.18 3.8.6 | 8.3 |
| Oct 2020 | **Oct 2025** | | 3.9.0 | | 21.04 Hirsute / **Bullseye** |
| Dec 2020 | *Mar 2021* | 2.30.0 | | | 21.04 Hirsute / **Bullseye** |
| Mar 2021 | | 2.31.0 | | 8.5 |
| Apr 2021 | | | | 8.6 |
| Apr 2021 | *Jan 2022* | | | | 21.04 Hirsute | 2.30.2 | 2.7.18 3.9.4 | 8.4 |
| Jun 2021 | | 2.32.0 |
| Aug 2021 | | 2.33.0 | | 8.7 |
| Aug 2021 | **Aug 2026** | | | | **Debian 11 Bullseye** | 2.30.2 | 2.7.18 3.9.2 | 8.4 |
| Sep 2021 | | | | 8.8 |
| Oct 2021 | | 2.34.0 | 3.10.0 | | **22.04 Jammy** |
| Jan 2022 | | 2.35.0 |
| Feb 2022 | | | | 8.9 | **22.04 Jammy** |
| Apr 2022 | | 2.36.0 | | 9.0 |
| Apr 2022 | **Apr 2032** | | | | **22.04 Jammy** | 2.34.1 | 2.7.18 3.10.6 | 8.9 |
| Jun 2022 | | 2.37.0 |
| Oct 2022 | | 2.38.0 | | 9.1 |
| Oct 2022 | | | 3.11.0 | | **Bookworm** |
| Dec 2022 | | 2.39.0 | | | **Bookworm** |
| Feb 2023 | | | | 9.2 | **Bookworm** |
| Mar 2023 | | 2.40.0 | | 9.3 |
| Jun 2023 | | 2.41.0 |
| Jun 2023 | **Jun 2028** | | | | **Debian 12 Bookworm** | 2.39.2 | 3.11.2 | 9.2 |
| Aug 2023 | | 2.42.0 | | 9.4 |
| Oct 2023 | | | 3.12.0 | 9.5 |
| Nov 2022 | | 2.43.0 |
| Dec 2023 | | | | 9.6 |
| Feb 2024 | | 2.44.0 |
| Mar 2024 | | | | 9.7 |
| Oct 2024 | | | 3.13.0 |
| **Date** | **EOL** | **[Git][rel-g]** | **[Python][rel-p]** | **[SSH][rel-o]** | **[Ubuntu][rel-u] / [Debian][rel-d]** | **Git** | **Python** | **SSH** |
[contact]: ../README.md#contact
[rel-d]: https://en.wikipedia.org/wiki/Debian_version_history
[rel-g]: https://en.wikipedia.org/wiki/Git#Releases
[rel-o]: https://www.openssh.com/releasenotes.html
[rel-p]: https://en.wikipedia.org/wiki/History_of_Python#Table_of_versions
[rel-u]: https://wiki.ubuntu.com/Releases
[example announcement]: https://groups.google.com/d/topic/repo-discuss/UGBNismWo1M/discussion
[repo-discuss@googlegroups.com]: https://groups.google.com/forum/#!forum/repo-discuss
[go/repo-release]: https://goto.google.com/repo-release
[Gerrit REST API]: https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#branch-endpoints
+4 -1
View File
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
.TH REPO "1" "August 2026" "repo upload" "Repo Manual"
.TH REPO "1" "October 2026" "repo upload" "Repo Manual"
.SH NAME
repo \- repo upload - manual page for repo upload
.SH SYNOPSIS
@@ -80,6 +80,9 @@ ignore untracked files in the working copy
\fB\-\-no\-ignore\-untracked\-files\fR
always ask about untracked files in the working copy
.TP
\fB\-\-ignore\-remote\-commits\fR
ignore commits already in remote branches
.TP
\fB\-\-no\-cert\-checks\fR
disable verifying ssl certs (unsafe)
.SS Logging options:
+33 -7
View File
@@ -36,6 +36,7 @@ from color import Coloring
import error
import fetch
import git_command
from git_config import Branch
from git_config import GetSchemeFromUrl
from git_config import GetUrlCookieFile
from git_config import GitConfig
@@ -180,10 +181,17 @@ class ReviewableBranch:
_commit_cache = None
_base_exists = None
def __init__(self, project, branch, base):
def __init__(
self,
project: "Project",
branch: Branch,
base: str,
ignore_remote_commits: bool = False,
) -> None:
self.project = project
self.branch = branch
self.base = base
self.ignore_remote_commits = ignore_remote_commits
@property
def name(self):
@@ -204,6 +212,7 @@ class ReviewableBranch:
"--date-order",
not_rev(self.base),
git_refs.R_HEADS + self.name,
*(("--not", "--remotes") if self.ignore_remote_commits else ()),
"--",
)
try:
@@ -226,7 +235,10 @@ class ReviewableBranch:
def unabbrev_commits(self):
r = {}
for commit in self.project.bare_git.rev_list(
not_rev(self.base), git_refs.R_HEADS + self.name, "--"
not_rev(self.base),
git_refs.R_HEADS + self.name,
*(("--not", "--remotes") if self.ignore_remote_commits else ()),
"--",
):
r[commit[0:8]] = commit
return r
@@ -1424,7 +1436,11 @@ class Project:
if git_refs.R_HEADS + n not in heads:
self.bare_git.DeleteRef(name, ref_id)
def GetUploadableBranches(self, selected_branch=None):
def GetUploadableBranches(
self,
selected_branch: Optional[str] = None,
ignore_remote_commits: bool = False,
) -> List[ReviewableBranch]:
"""List any branches which can be uploaded for review."""
if selected_branch:
branch = self.GetBranch(selected_branch)
@@ -1436,7 +1452,9 @@ class Project:
pub_id = self.bare_ref.get(git_refs.R_PUB + selected_branch)
if pub_id and pub_id == head_id:
return []
rb = self.GetUploadableBranch(selected_branch)
rb = self.GetUploadableBranch(
selected_branch, ignore_remote_commits=ignore_remote_commits
)
if rb:
rb.branch.current = selected_branch == self.CurrentBranch
return [rb]
@@ -1454,18 +1472,26 @@ class Project:
if branch_config.published == branch_config.revision:
continue
rb = self.GetUploadableBranch(branch)
rb = self.GetUploadableBranch(
branch, ignore_remote_commits=ignore_remote_commits
)
if rb:
rb.branch.current = branch_config.current
ready.append(rb)
return ready
def GetUploadableBranch(self, branch_name):
def GetUploadableBranch(
self,
branch_name: Optional[str],
ignore_remote_commits: bool = False,
) -> Optional[ReviewableBranch]:
"""Get a single uploadable branch, or None."""
branch = self.GetBranch(branch_name)
base = branch.LocalMerge
if branch.LocalMerge:
rb = ReviewableBranch(self, branch, base)
rb = ReviewableBranch(
self, branch, base, ignore_remote_commits=ignore_remote_commits
)
if rb.commits:
return rb
return None
+8 -3
View File
@@ -19,9 +19,14 @@
# Hard versions are when we refuse to work the tool. Users will be shown an
# error message before we abort entirely.
# When deciding whether to upgrade a version requirement, check out the distro
# lists to see who will be impacted:
# https://gerrit.googlesource.com/git-repo/+/HEAD/docs/release-process.md#Project-References
# When deciding whether to upgrade a version requirement, check out what
# versions major distros (e.g. Ubuntu LTS & Debian stable) ship and when they
# go EOL to see who will be impacted:
# https://wiki.ubuntu.com/Releases
# https://wiki.debian.org/DebianReleases#Versions_of_Debian_stable
# https://repology.org/project/python/versions
# https://repology.org/project/git/versions
# https://repology.org/project/openssh/versions
{
# The repo launcher itself. This allows us to force people to upgrade as some
+12 -2
View File
@@ -369,6 +369,12 @@ Gerrit Code Review: https://www.gerritcodereview.com/
action="store_false",
help="always ask about untracked files in the working copy",
)
p.add_option(
"--ignore-remote-commits",
action="store_true",
default=False,
help="ignore commits already in remote branches",
)
p.add_option(
"--no-cert-checks",
dest="validate_certs",
@@ -738,10 +744,14 @@ Gerrit Code Review: https://www.gerritcodereview.com/
cbr = None
if opt.current_branch:
cbr = project.CurrentBranch
up_branch = project.GetUploadableBranch(cbr)
up_branch = project.GetUploadableBranch(
cbr, ignore_remote_commits=opt.ignore_remote_commits
)
avail = [up_branch] if up_branch else None
else:
avail = project.GetUploadableBranches(opt.branch)
avail = project.GetUploadableBranches(
opt.branch, ignore_remote_commits=opt.ignore_remote_commits
)
return (project_idx, avail, cbr)
def ValidateOptions(self, opt: optparse.Values, args: List[str]) -> None:
+45 -1
View File
@@ -137,6 +137,48 @@ class ReviewableBranchTests(unittest.TestCase):
self.assertTrue(rb.current)
def test_ignore_remote_commits(self) -> None:
"""Check ignore_remote_commits excludes commits in refs/remotes/*."""
with utils_for_test.TempGitTree() as tempdir:
fakeproj = FakeProject(tempdir)
with open(os.path.join(tempdir, "readme"), "w") as fp:
fp.write("init")
fakeproj.work_git.add("readme")
fakeproj.work_git.commit("-mInit")
# Create an upstream commit and record it under refs/remotes/.
fakeproj.work_git.checkout("-b", "upstream")
with open(os.path.join(tempdir, "upstream.txt"), "w") as fp:
fp.write("upstream")
fakeproj.work_git.add("upstream.txt")
fakeproj.work_git.commit("-mUpstream change")
fakeproj.work_git.update_ref(
"refs/remotes/upstream/main", "refs/heads/upstream"
)
# Merge the remote branch into work on top of main.
fakeproj.work_git.checkout("-b", "work", "main")
fakeproj.work_git.merge(
"--no-ff", "-mMerge upstream", "refs/remotes/upstream/main"
)
rb_default = project.ReviewableBranch(
fakeproj, fakeproj.config.GetBranch("work"), "main"
)
self.assertEqual(2, len(rb_default.commits))
self.assertEqual(2, len(rb_default.unabbrev_commits))
rb_ignored = project.ReviewableBranch(
fakeproj,
fakeproj.config.GetBranch("work"),
"main",
ignore_remote_commits=True,
)
self.assertEqual(1, len(rb_ignored.commits))
self.assertIn("Merge upstream", rb_ignored.commits[0])
self.assertEqual(1, len(rb_ignored.unabbrev_commits))
class ProjectTests(unittest.TestCase):
"""Check Project behavior."""
@@ -1277,7 +1319,9 @@ class ProjectTests(unittest.TestCase):
) as mock_get_up:
res = proj.GetUploadableBranches("feature")
self.assertEqual(res, [mock_rb])
mock_get_up.assert_called_once_with("feature")
mock_get_up.assert_called_once_with(
"feature", ignore_remote_commits=False
)
def _get_derived_subproject_url(self, submodule_url):
with tempfile.TemporaryDirectory(prefix="repo-tests") as tempdir:
+37 -2
View File
@@ -116,11 +116,46 @@ def test_GatherOne_returns_resolved_current_branch(
"get_parallel_context",
lambda: {"projects": [project]},
)
opt = mock.MagicMock(current_branch=True)
opt = mock.MagicMock(current_branch=True, ignore_remote_commits=False)
assert upload.Upload._GatherOne(opt, 0) == (0, [branch], "topic")
project.GetUploadableBranch.assert_called_once_with("topic")
project.GetUploadableBranch.assert_called_once_with(
"topic", ignore_remote_commits=False
)
def test_GatherOne_forwards_ignore_remote_commits(
cmd: upload.Upload,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""_GatherOne forwards --ignore-remote-commits to project methods."""
project = mock.MagicMock()
project.CurrentBranch = "topic"
branch = mock.sentinel.branch
project.GetUploadableBranch.return_value = branch
project.GetUploadableBranches.return_value = [branch]
monkeypatch.setattr(
upload.Upload,
"get_parallel_context",
lambda: {"projects": [project]},
)
opt_cbr, _ = cmd.OptionParser.parse_args(
["--cbr", "--ignore-remote-commits"]
)
assert upload.Upload._GatherOne(opt_cbr, 0) == (0, [branch], "topic")
project.GetUploadableBranch.assert_called_once_with(
"topic", ignore_remote_commits=True
)
opt_br, _ = cmd.OptionParser.parse_args(
["--br", "topic", "--ignore-remote-commits"]
)
assert upload.Upload._GatherOne(opt_br, 0) == (0, [branch], None)
project.GetUploadableBranches.assert_called_once_with(
"topic", ignore_remote_commits=True
)
def _create_mock_branch(