Repository: kopia/kopia
Pull request #4558 (2025-05-05 23:40:18)

build(deps): bump the common-golang-dependencies group with 9 updates
Bumps the common-golang-dependencies group with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [cloud.google.com/go/storage](https://github.com/googleapis/google-cloud-go) | `1.52.0` | `1.53.0` |
| [golang.org/x/crypto](https://github.com/golang/crypto) | `0.37.0` | `0.38.0` |
| [golang.org/x/net](https://github.com/golang/net) | `0.39.0` | `0.40.0` |
| [golang.org/x/oauth2](https://github.com/golang/oauth2) | `0.29.0` | `0.30.0` |
| [golang.org/x/sync](https://github.com/golang/sync) | `0.13.0` | `0.14.0` |
| [golang.org/x/sys](https://github.com/golang/sys) | `0.32.0` | `0.33.0` |
| [golang.org/x/term](https://github.com/golang/term) | `0.31.0` | `0.32.0` |
| [golang.org/x/text](https://github.com/golang/text) | `0.24.0` | `0.25.0` |
| [google.golang.org/api](https://github.com/googleapis/google-api-go-client) | `0.230.0` | `0.231.0` |

Updates `cloud.google.com/go/storage` from 1.52.0 to 1.53.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/googleapis/google-cloud-go/releases">cloud.google.com/go/storage's releases</a>.</em></p>
<blockquote>
<h2>storage: v1.53.0</h2>
<h2><a href="https://github.com/googleapis/google-cloud-go/compare/storage/v1.52.0...storage/v1.53.0">1.53.0</a> (2025-05-02)</h2>
<h3>Features</h3>
<ul>
<li><strong>storage/control:</strong> Add Anywhere cache control APIs (<a href="https://github.com/googleapis/google-cloud-go/commit/83ae06c3ec7d190e38856ba4cfd8a13f08356b4d">83ae06c</a>)</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li><strong>storage:</strong> Fix append edge cases (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/12074">#12074</a>) (<a href="https://github.com/googleapis/google-cloud-go/commit/0eee1f99a7dc0d1bfc36fa43d78933cae47962ee">0eee1f9</a>)</li>
<li><strong>storage:</strong> Fix retries for redirection errors. (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/12093">#12093</a>) (<a href="https://github.com/googleapis/google-cloud-go/commit/3e177e755f5bf6aa96e8712cc4adcba7eb6f04f6">3e177e7</a>)</li>
<li><strong>storage:</strong> Handle gRPC deadlines in tests. (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/12092">#12092</a>) (<a href="https://github.com/googleapis/google-cloud-go/commit/30b7cd27771ccbd49b70ee106da36362ba8f1e87">30b7cd2</a>)</li>
<li><strong>storage:</strong> Update offset on resumable upload retry (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/12086">#12086</a>) (<a href="https://github.com/googleapis/google-cloud-go/commit/6ce8fe5aec0ec7916eda4d1405cab5f5f65a5de8">6ce8fe5</a>)</li>
<li><strong>storage:</strong> Validate Bidi option for MRD (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/12033">#12033</a>) (<a href="https://github.com/googleapis/google-cloud-go/commit/d9018cf640a9ac25e2b23b75b3bcfa734379ab09">d9018cf</a>)</li>
</ul>
<h3>Documentation</h3>
<ul>
<li><strong>storage/control:</strong> Added comments for Anywhere cache messages (<a href="https://github.com/googleapis/google-cloud-go/commit/83ae06c3ec7d190e38856ba4cfd8a13f08356b4d">83ae06c</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/googleapis/google-cloud-go/commit/5d5e5479d98b379267bea33893b5d6f069d65e82"><code>5d5e547</code></a> chore(main): release spanner 1.53.0 (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/9009">#9009</a>)</li>
<li><a href="https://github.com/googleapis/google-cloud-go/commit/5d181bb3a6fea55b8d9d596213516129006bdae2"><code>5d181bb</code></a> feat(spanner): enable long running transaction clean up (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/8969">#8969</a>)</li>
<li><a href="https://github.com/googleapis/google-cloud-go/commit/9f9b01e2d2cc9a5f903608ba1c6ad3d6ff51e168"><code>9f9b01e</code></a> chore(storage): add server mode [benchmarks] (<a href="https://redirect.github.com/googleapis/google-cloud-go/issues/8562">#8562</a>)</li>
<li>See full diff in <a href="https://github.com/googleapis/google-cloud-go/compare/spanner/v1.52.0...spanner/v1.53.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/crypto` from 0.37.0 to 0.38.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/crypto/commit/aae6e61070421a51c1ba3bd9bba4b9b3979ed488"><code>aae6e61</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/crypto/commit/9c1aa6af88df97634a66726b66bb12e56d1ef6c6"><code>9c1aa6a</code></a> ssh/test: reset the random source before capturing a recording</li>
<li><a href="https://github.com/golang/crypto/commit/88199028d7292312358bd6757cff1ce67cd79828"><code>8819902</code></a> ssh/test: enable Diffie-Hellman key exchange algorithms</li>
<li><a href="https://github.com/golang/crypto/commit/3f311e442e372a8282abb4d82b6d59ac79a97f75"><code>3f311e4</code></a> acme: return error from pre-authorization when unsupported</li>
<li><a href="https://github.com/golang/crypto/commit/1f7c62cd66d3486a9cbcec5a4614c0414e9c8dab"><code>1f7c62c</code></a> ssh/test: skip unsupported tests on js/wasm</li>
<li><a href="https://github.com/golang/crypto/commit/a5f804889e33b2a69e6dc8aba18a771bae29a08f"><code>a5f8048</code></a> acme/autocert: use standard functions to pick the cache directory</li>
<li><a href="https://github.com/golang/crypto/commit/958cde86ef61ba2f51186f4a59557fa82348133a"><code>958cde8</code></a> Revert &quot;chacha20: add loong64 SIMD implementation&quot;</li>
<li><a href="https://github.com/golang/crypto/commit/51f005cfd443a6a8fe542c8c2e58ed138f1cbbe2"><code>51f005c</code></a> Revert &quot;salsa20: add loong64 SIMD implementation&quot;</li>
<li><a href="https://github.com/golang/crypto/commit/7c358664da2071dd8c46274b0e0ba68b11f796cd"><code>7c35866</code></a> Revert &quot;argon2: add loong64 SIMD implementation&quot;</li>
<li><a href="https://github.com/golang/crypto/commit/0091fc8e7c693be8d8cbfee206c04512cf4f7513"><code>0091fc8</code></a> Revert &quot;blake2s: add loong64 SIMD implementation&quot;</li>
<li>Additional commits viewable in <a href="https://github.com/golang/crypto/compare/v0.37.0...v0.38.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/oauth2` from 0.29.0 to 0.30.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/oauth2/commit/cf1431934151b3a93e0b3286eb6798ca08ea3770"><code>cf14319</code></a> oauth2: fix expiration time window check</li>
<li><a href="https://github.com/golang/oauth2/commit/32d34ef364e670a650fe59267b92301ff7ed08f1"><code>32d34ef</code></a> internal: include clientID in auth style cache key</li>
<li><a href="https://github.com/golang/oauth2/commit/2d34e3091be3f4b4700842fb663dad98a10ddfb6"><code>2d34e30</code></a> oauth2: replace a magic number with AuthStyleUnknown</li>
<li><a href="https://github.com/golang/oauth2/commit/696f7b31289a98558822be146698b7834e477e63"><code>696f7b3</code></a> all: modernize with doc links and any</li>
<li><a href="https://github.com/golang/oauth2/commit/471209bbe29fc1e3bf8d4ca3ca89d67f8817d521"><code>471209b</code></a> oauth2: drop dependency on go-cmp</li>
<li><a href="https://github.com/golang/oauth2/commit/6968da209b8fd816452d22ad1b4faca197a5b974"><code>6968da2</code></a> oauth2: sync Token.ExpiresIn from internal Token</li>
<li><a href="https://github.com/golang/oauth2/commit/d2c4e0a6256426212864554628e234ebe6005347"><code>d2c4e0a</code></a> oauth2: context instead of golang.org/x/net/context in doc</li>
<li><a href="https://github.com/golang/oauth2/commit/883dc3c9d87d538c301ebff2ccdcc8b6a0b92890"><code>883dc3c</code></a> endpoints: add various endpoints from stale CLs</li>
<li><a href="https://github.com/golang/oauth2/commit/1c06e8705ef848db9c7553a78b630b9b9f138a87"><code>1c06e87</code></a> all: make use of oauth.Token.ExpiresIn</li>
<li>See full diff in <a href="https://github.com/golang/oauth2/compare/v0.29.0...v0.30.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/sync` from 0.13.0 to 0.14.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/sync/commit/506c70f97318aa991ec5a898685660c880c166ca"><code>506c70f</code></a> errgroup: propagate panic and Goexit through Wait</li>
<li>See full diff in <a href="https://github.com/golang/sync/compare/v0.13.0...v0.14.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/sys` from 0.32.0 to 0.33.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/sys/commit/3d9a6b80792a3911da1fa665c959a5ede3abf476"><code>3d9a6b8</code></a> windows: add WSADuplicateSocket</li>
<li><a href="https://github.com/golang/sys/commit/c0a955987704d2beda71a48afc43cec03e8bcb96"><code>c0a9559</code></a> cpu: add crypto extensions detection for riscv64</li>
<li><a href="https://github.com/golang/sys/commit/8e9e04625d1e3542f462ec617fd078b2d2961e5a"><code>8e9e046</code></a> windows: add virtual key codes and console input consts</li>
<li><a href="https://github.com/golang/sys/commit/7138967c196ab71ebc2d3b2cae146abeab672de0"><code>7138967</code></a> windows: fix slicing of NTUnicodeString values</li>
<li><a href="https://github.com/golang/sys/commit/6a85559a3f1bd2a5418354bf4bd7e306213a81bc"><code>6a85559</code></a> windows: fix dangling pointers in (*SECURITY_DESCRIPTOR).ToAbsolute</li>
<li>See full diff in <a href="https://github.com/golang/sys/compare/v0.32.0...v0.33.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/term` from 0.31.0 to 0.32.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/term/commit/2ec7864a3e7b8faa620696c32a0738119e2477e1"><code>2ec7864</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/term/commit/a809085bff595080269599dbe788dd7fdf616ab4"><code>a809085</code></a> term: support pluggable history</li>
<li>See full diff in <a href="https://github.com/golang/term/compare/v0.31.0...v0.32.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/text` from 0.24.0 to 0.25.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/text/commit/700cc20645cf719b928f5fce7e07528c4f7fa601"><code>700cc20</code></a> go.mod: update golang.org/x dependencies</li>
<li>See full diff in <a href="https://github.com/golang/text/compare/v0.24.0...v0.25.0">compare view</a></li>
</ul>
</details>
<br />

Updates `google.golang.org/api` from 0.230.0 to 0.231.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/googleapis/google-api-go-client/releases">google.golang.org/api's releases</a>.</em></p>
<blockquote>
<h2>v0.231.0</h2>
<h2><a href="https://github.com/googleapis/google-api-go-client/compare/v0.230.0...v0.231.0">0.231.0</a> (2025-04-29)</h2>
<h3>Features</h3>
<ul>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3122">#3122</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/47cbba61ec8d62ebdfd1affe3a9244b20184c781">47cbba6</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3124">#3124</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/677b602b6f3f072ebfac6c5791cc06d15720b136">677b602</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3125">#3125</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/8ccf1f08977c7843d093bba21d391b082e206a75">8ccf1f0</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3126">#3126</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/405935174a0a7c9734c8e6b0dce487c481a7927e">4059351</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3127">#3127</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/ae18b2206b6182d47d69227b638dfc42d975b889">ae18b22</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3129">#3129</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/c33e0d153c99c931e5b953e3ccfa40fe8ac20c02">c33e0d1</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md">google.golang.org/api's changelog</a>.</em></p>
<blockquote>
<h2><a href="https://github.com/googleapis/google-api-go-client/compare/v0.230.0...v0.231.0">0.231.0</a> (2025-04-29)</h2>
<h3>Features</h3>
<ul>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3122">#3122</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/47cbba61ec8d62ebdfd1affe3a9244b20184c781">47cbba6</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3124">#3124</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/677b602b6f3f072ebfac6c5791cc06d15720b136">677b602</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3125">#3125</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/8ccf1f08977c7843d093bba21d391b082e206a75">8ccf1f0</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3126">#3126</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/405935174a0a7c9734c8e6b0dce487c481a7927e">4059351</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3127">#3127</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/ae18b2206b6182d47d69227b638dfc42d975b889">ae18b22</a>)</li>
<li><strong>all:</strong> Auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3129">#3129</a>) (<a href="https://github.com/googleapis/google-api-go-client/commit/c33e0d153c99c931e5b953e3ccfa40fe8ac20c02">c33e0d1</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/70d3b4f38ec8df290ddcaedb749eaf29f798958c"><code>70d3b4f</code></a> chore(main): release 0.231.0 (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3123">#3123</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/c33e0d153c99c931e5b953e3ccfa40fe8ac20c02"><code>c33e0d1</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3129">#3129</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/673da13c2fc8c8758ae8c1c1fc2d02fdb9556bc5"><code>673da13</code></a> chore(all): update all (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3128">#3128</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/ae18b2206b6182d47d69227b638dfc42d975b889"><code>ae18b22</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3127">#3127</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/405935174a0a7c9734c8e6b0dce487c481a7927e"><code>4059351</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3126">#3126</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/8ccf1f08977c7843d093bba21d391b082e206a75"><code>8ccf1f0</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3125">#3125</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/677b602b6f3f072ebfac6c5791cc06d15720b136"><code>677b602</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3124">#3124</a>)</li>
<li><a href="https://github.com/googleapis/google-api-go-client/commit/47cbba61ec8d62ebdfd1affe3a9244b20184c781"><code>47cbba6</code></a> feat(all): auto-regenerate discovery clients (<a href="https://redirect.github.com/googleapis/google-api-go-client/issues/3122">#3122</a>)</li>
<li>See full diff in <a href="https://github.com/googleapis/google-api-go-client/compare/v0.230.0...v0.231.0">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions


</details>


Patch:
diff --git a/cli/command_diff.go b/cli/command_diff.go
index c3d9f6e2..c8033dce 100644
--- a/cli/command_diff.go
+++ b/cli/command_diff.go
@@ -18,6 +18,7 @@ type commandDiff struct {
 	diffFirstObjectPath  string
 	diffSecondObjectPath string
 	diffCompareFiles     bool
+	diffStatsOnly        bool
 	diffCommandCommand   string
 
 	out textOutput
@@ -28,6 +29,7 @@ func (c *commandDiff) setup(svc appServices, parent commandParent) {
 	cmd.Arg("object-path1", "First object/path").Required().StringVar(&c.diffFirstObjectPath)
 	cmd.Arg("object-path2", "Second object/path").Required().StringVar(&c.diffSecondObjectPath)
 	cmd.Flag("files", "Compare files by launching diff command for all pairs of (old,new)").Short('f').BoolVar(&c.diffCompareFiles)
+	cmd.Flag("stats-only", "Displays only aggregate statistics of the changes between two repository objects").BoolVar(&c.diffStatsOnly)
 	cmd.Flag("diff-command", "Displays differences between two repository objects (files or directories)").Default(defaultDiffCommand()).Envar(svc.EnvName("KOPIA_DIFF")).StringVar(&c.diffCommandCommand)
 	cmd.Action(svc.repositoryReaderAction(c.run))
 
@@ -52,7 +54,7 @@ func (c *commandDiff) run(ctx context.Context, rep repo.Repository) error {
 		return errors.New("arguments to diff must both be directories or both non-directories")
 	}
 
-	d, err := diff.NewComparer(c.out.stdout())
+	d, err := diff.NewComparer(c.out.stdout(), c.diffStatsOnly)
 	if err != nil {
 		return errors.Wrap(err, "error creating comparer")
 	}
diff --git a/go.mod b/go.mod
index 56706e3a..98128f74 100644
--- a/go.mod
+++ b/go.mod
@@ -5,7 +5,7 @@ go 1.23.0
 toolchain go1.23.8
 
 require (
-	cloud.google.com/go/storage v1.52.0
+	cloud.google.com/go/storage v1.53.0
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.9.0
 	github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.1
@@ -58,16 +58,16 @@ require (
 	go.opentelemetry.io/otel/sdk v1.35.0
 	go.opentelemetry.io/otel/trace v1.35.0
 	go.uber.org/zap v1.27.0
-	golang.org/x/crypto v0.37.0
+	golang.org/x/crypto v0.38.0
 	golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
 	golang.org/x/mod v0.24.0
-	golang.org/x/net v0.39.0
-	golang.org/x/oauth2 v0.29.0
-	golang.org/x/sync v0.13.0
-	golang.org/x/sys v0.32.0
-	golang.org/x/term v0.31.0
-	golang.org/x/text v0.24.0
-	google.golang.org/api v0.230.0
+	golang.org/x/net v0.40.0
+	golang.org/x/oauth2 v0.30.0
+	golang.org/x/sync v0.14.0
+	golang.org/x/sys v0.33.0
+	golang.org/x/term v0.32.0
+	golang.org/x/text v0.25.0
+	google.golang.org/api v0.231.0
 	google.golang.org/grpc v1.72.0
 	google.golang.org/protobuf v1.36.6
 	gopkg.in/kothar/go-backblaze.v0 v0.0.0-20210124194846-35409b867216
@@ -76,11 +76,11 @@ require (
 require (
 	al.essio.dev/pkg/shellescape v1.5.1 // indirect
 	cel.dev/expr v0.20.0 // indirect
-	cloud.google.com/go v0.120.0 // indirect
-	cloud.google.com/go/auth v0.16.0 // indirect
+	cloud.google.com/go v0.120.1 // indirect
+	cloud.google.com/go/auth v0.16.1 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
 	cloud.google.com/go/compute/metadata v0.6.0 // indirect
-	cloud.google.com/go/iam v1.5.0 // indirect
+	cloud.google.com/go/iam v1.5.2 // indirect
 	cloud.google.com/go/monitoring v1.24.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
@@ -145,7 +145,7 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/time v0.11.0 // indirect
 	google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index ade269c2..70fe68cc 100644
--- a/go.sum
+++ b/go.sum
@@ -2,24 +2,24 @@ al.essio.dev/pkg/shellescape v1.5.1 h1:86HrALUujYS/h+GtqoB26SBEdkWfmMI6FubjXlsXy
 al.essio.dev/pkg/shellescape v1.5.1/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890=
 cel.dev/expr v0.20.0 h1:OunBvVCfvpWlt4dN7zg3FM6TDkzOePe1+foGJ9AXeeI=
 cel.dev/expr v0.20.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
-cloud.google.com/go v0.120.0 h1:wc6bgG9DHyKqF5/vQvX1CiZrtHnxJjBlKUyF9nP6meA=
-cloud.google.com/go v0.120.0/go.mod h1:/beW32s8/pGRuj4IILWQNd4uuebeT4dkOhKmkfit64Q=
-cloud.google.com/go/auth v0.16.0 h1:Pd8P1s9WkcrBE2n/PhAwKsdrR35V3Sg2II9B+ndM3CU=
-cloud.google.com/go/auth v0.16.0/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
+cloud.google.com/go v0.120.1 h1:Z+5V7yd383+9617XDCyszmK5E4wJRJL+tquMfDj9hLM=
+cloud.google.com/go v0.120.1/go.mod h1:56Vs7sf/i2jYM6ZL9NYlC82r04PThNcPS5YgFmb0rp8=
+cloud.google.com/go/auth v0.16.1 h1:XrXauHMd30LhQYVRHLGvJiYeczweKQXZxsTbV9TiguU=
+cloud.google.com/go/auth v0.16.1/go.mod h1:1howDHJ5IETh/LwYs3ZxvlkXF48aSqqJUM+5o02dNOI=
 cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
 cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
 cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
 cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
-cloud.google.com/go/iam v1.5.0 h1:QlLcVMhbLGOjRcGe6VTGGTyQib8dRLK2B/kYNV0+2xs=
-cloud.google.com/go/iam v1.5.0/go.mod h1:U+DOtKQltF/LxPEtcDLoobcsZMilSRwR7mgNL7knOpo=
+cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
+cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
 cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
 cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
-cloud.google.com/go/longrunning v0.6.6 h1:XJNDo5MUfMM05xK3ewpbSdmt7R2Zw+aQEMbdQR65Rbw=
-cloud.google.com/go/longrunning v0.6.6/go.mod h1:hyeGJUrPHcx0u2Uu1UFSoYZLn4lkMrccJig0t4FI7yw=
+cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
+cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
 cloud.google.com/go/monitoring v1.24.0 h1:csSKiCJ+WVRgNkRzzz3BPoGjFhjPY23ZTcaenToJxMM=
 cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc=
-cloud.google.com/go/storage v1.52.0 h1:ROpzMW/IwipKtatA69ikxibdzQSiXJrY9f6IgBa9AlA=
-cloud.google.com/go/storage v1.52.0/go.mod h1:4wrBAbAYUvYkbrf19ahGm4I5kDQhESSqN3CGEkMGvOY=
+cloud.google.com/go/storage v1.53.0 h1:gg0ERZwL17pJ+Cz3cD2qS60w1WMDnwcm5YPAIQBHUAw=
+cloud.google.com/go/storage v1.53.0/go.mod h1:7/eO2a/srr9ImZW9k5uufcNahT2+fPb8w5it1i5boaA=
 cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE=
 cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
@@ -331,8 +331,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
-golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
-golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
+golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -351,10 +351,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
-golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98=
-golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -362,8 +362,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
-golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -379,8 +379,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -390,8 +390,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
 golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
-golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
-golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -401,8 +401,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
 golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -413,14 +413,14 @@ golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58
 golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.230.0 h1:2u1hni3E+UXAXrONrrkfWpi/V6cyKVAbfGVeGtC3OxM=
-google.golang.org/api v0.230.0/go.mod h1:aqvtoMk7YkiXx+6U12arQFExiRV9D/ekvMCwCd/TksQ=
+google.golang.org/api v0.231.0 h1:LbUD5FUl0C4qwia2bjXhCMH65yz1MLPzA/0OYEsYY7Q=
+google.golang.org/api v0.231.0/go.mod h1:H52180fPI/QQlUc0F4xWfGZILdv09GCWKt2bcsn164A=
 google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
 google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
-google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e h1:UdXH7Kzbj+Vzastr5nVfccbmFsmYNygVLSPk1pEfDoY=
-google.golang.org/genproto/googleapis/api v0.0.0-20250414145226-207652e42e2e/go.mod h1:085qFyf2+XaZlRdCgKNCIZ3afY2p4HHZdoIRpId8F4A=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e h1:ztQaXfzEXTmCBvbtWYRhJxW+0iJcz2qXfd38/e9l7bA=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250414145226-207652e42e2e/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197 h1:9DuBh3k1jUho2DHdxH+kbJwthIAq02vGvZNrD2ggF+Y=
+google.golang.org/genproto/googleapis/api v0.0.0-20250425173222-7b384671a197/go.mod h1:Cd8IzgPo5Akum2c9R6FsXNaZbH3Jpa2gpHlW89FqlyQ=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197 h1:29cjnHVylHwTzH66WfFZqgSQgnxzvWE+jvBwpZCLRxY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250425173222-7b384671a197/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
 google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
diff --git a/internal/diff/diff.go b/internal/diff/diff.go
index 39fe0be6..dc571c7f 100644
--- a/internal/diff/diff.go
+++ b/internal/diff/diff.go
@@ -48,6 +48,7 @@ type Comparer struct {
 	stats         Stats
 	out           io.Writer
 	tmpDir        string
+	statsOnly     bool
 	DiffCommand   string
 	DiffArguments []string
 }
@@ -122,14 +123,14 @@ func (c *Comparer) compareEntry(ctx context.Context, e1, e2 fs.Entry, path strin
 
 	if e1 == nil {
 		if dir2, isDir2 := e2.(fs.Directory); isDir2 {
-			c.output("added directory %v\n", path)
+			c.output(c.statsOnly, "added directory %v\n", path)
 
 			c.stats.DirectoryEntries.Added++
 
 			return c.compareDirectories(ctx, nil, dir2, path)
 		}
 
-		c.output("added file %v (%v bytes)\n", path, e2.Size())
+		c.output(c.statsOnly, "added file %v (%v bytes)\n", path, e2.Size())
 
 		c.stats.FileEntries.Added++
 
@@ -144,14 +145,14 @@ func (c *Comparer) compareEntry(ctx context.Context, e1, e2 fs.Entry, path strin
 
 	if e2 == nil {
 		if dir1, isDir1 := e1.(fs.Directory); isDir1 {
-			c.output("removed directory %v\n", path)
+			c.output(c.statsOnly, "removed directory %v\n", path)
 
 			c.stats.DirectoryEntries.Removed++
 
 			return c.compareDirectories(ctx, dir1, nil, path)
 		}
 
-		c.output("removed file %v (%v bytes)\n", path, e1.Size())
+		c.output(c.statsOnly, "removed file %v (%v bytes)\n", path, e1.Size())
 
 		c.stats.FileEntries.Removed++
 
@@ -172,7 +173,7 @@ func (c *Comparer) compareEntry(ctx context.Context, e1, e2 fs.Entry, path strin
 	if isDir1 {
 		if !isDir2 {
 			// right is a non-directory, left is a directory
-			c.output("changed %v from directory to non-directory\n", path)
+			c.output(c.statsOnly, "changed %v from directory to non-directory\n", path)
 			return nil
 		}
 
@@ -181,14 +182,14 @@ func (c *Comparer) compareEntry(ctx context.Context, e1, e2 fs.Entry, path strin
 
 	if isDir2 {
 		// left is non-directory, right is a directory
-		c.output("changed %v from non-directory to a directory\n", path)
+		c.output(c.statsOnly, "changed %v from non-directory to a directory\n", path)
 
 		return nil
 	}
 
 	if f1, ok := e1.(fs.File); ok {
 		if f2, ok := e2.(fs.File); ok {
-			c.output("changed %v at %v (size %v -> %v)\n", path, e2.ModTime().String(), e1.Size(), e2.Size())
+			c.output(c.statsOnly, "changed %v at %v (size %v -> %v)\n", path, e2.ModTime().String(), e1.Size(), e2.Size())
 
 			c.stats.FileEntries.Modified++
 
@@ -242,10 +243,10 @@ func (c *Comparer) compareEntryMetadata(e1, e2 fs.Entry, fullpath string) {
 	case e1 == e2: // in particular e1 == nil && e2 == nil
 		return
 	case e1 == nil:
-		c.output("%v does not exist in source directory\n", fullpath)
+		c.output(c.statsOnly, "%v does not exist in source directory\n", fullpath)
 		return
 	case e2 == nil:
-		c.output("%v does not exist in destination directory\n", fullpath)
+		c.output(c.statsOnly, "%v does not exist in destination directory\n", fullpath)
 		return
 	}
 
@@ -254,32 +255,32 @@ func (c *Comparer) compareEntryMetadata(e1, e2 fs.Entry, fullpath string) {
 	if m1, m2 := e1.Mode(), e2.Mode(); m1 != m2 {
 		changed = true
 
-		c.output("%v modes differ: %v %v\n", fullpath, m1, m2)
+		c.output(c.statsOnly, "%v modes differ: %v %v\n", fullpath, m1, m2)
 	}
 
 	if s1, s2 := e1.Size(), e2.Size(); s1 != s2 {
 		changed = true
 
-		c.output("%v sizes differ: %v %v\n", fullpath, s1, s2)
+		c.output(c.statsOnly, "%v sizes differ: %v %v\n", fullpath, s1, s2)
 	}
 
 	if mt1, mt2 := e1.ModTime(), e2.ModTime(); !mt1.Equal(mt2) {
 		changed = true
 
-		c.output("%v modification times differ: %v %v\n", fullpath, mt1, mt2)
+		c.output(c.statsOnly, "%v modification times differ: %v %v\n", fullpath, mt1, mt2)
 	}
 
 	o1, o2 := e1.Owner(), e2.Owner()
 	if o1.UserID != o2.UserID {
 		changed = true
 
-		c.output("%v owner users differ: %v %v\n", fullpath, o1.UserID, o2.UserID)
+		c.output(c.statsOnly, "%v owner users differ: %v %v\n", fullpath, o1.UserID, o2.UserID)
 	}
 
 	if o1.GroupID != o2.GroupID {
 		changed = true
 
-		c.output("%v owner groups differ: %v %v\n", fullpath, o1.GroupID, o2.GroupID)
+		c.output(c.statsOnly, "%v owner groups differ: %v %v\n", fullpath, o1.GroupID, o2.GroupID)
 	}
 
 	_, isDir1 := e1.(fs.Directory)
@@ -391,16 +392,18 @@ func (c *Comparer) Stats() Stats {
 	return c.stats
 }
 
-func (c *Comparer) output(msg string, args ...interface{}) {
-	fmt.Fprintf(c.out, msg, args...) //nolint:errcheck
+func (c *Comparer) output(statsOnly bool, msg string, args ...interface{}) {
+	if !statsOnly {
+		fmt.Fprintf(c.out, msg, args...) //nolint:errcheck
+	}
 }
 
 // NewComparer creates a comparer for a given repository that will output the results to a given writer.
-func NewComparer(out io.Writer) (*Comparer, error) {
+func NewComparer(out io.Writer, statsOnly bool) (*Comparer, error) {
 	tmp, err := os.MkdirTemp("", "kopia")
 	if err != nil {
 		return nil, errors.Wrap(err, "error creating temp directory")
 	}
 
-	return &Comparer{out: out, tmpDir: tmp}, nil
+	return &Comparer{out: out, tmpDir: tmp, statsOnly: statsOnly}, nil
 }


Test patch:
diff --git a/internal/diff/diff_test.go b/internal/diff/diff_test.go
index 30deb20e..1b758ad0 100644
--- a/internal/diff/diff_test.go
+++ b/internal/diff/diff_test.go
@@ -17,6 +17,8 @@
 	"github.com/kopia/kopia/repo/object"
 )
 
+const statsOnly = false
+
 var (
 	_ fs.Entry     = (*testFile)(nil)
 	_ fs.Directory = (*testDirectory)(nil)
@@ -110,7 +112,7 @@ func TestCompareEmptyDirectories(t *testing.T) {
 	dir1 := createTestDirectory("testDir1", dirModTime, dirOwnerInfo, dirMode, dirObjectID1)
 	dir2 := createTestDirectory("testDir2", dirModTime, dirOwnerInfo, dirMode, dirObjectID2)
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -165,7 +167,7 @@ func TestCompareIdenticalDirectories(t *testing.T) {
 
 	expectedStats := diff.Stats{}
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -214,7 +216,7 @@ func TestCompareDifferentDirectories(t *testing.T) {
 		&testFile{testBaseEntry: testBaseEntry{modtime: fileModTime, name: "file4.txt"}, content: "klmnopqrstuvwxyz2"},
 	)
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -275,7 +277,7 @@ func TestCompareDifferentDirectories_DirTimeDiff(t *testing.T) {
 	expectedStats := diff.Stats{}
 	expectedStats.DirectoryEntries.Modified = 1
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -324,7 +326,7 @@ func TestCompareDifferentDirectories_FileTimeDiff(t *testing.T) {
 		&testFile{testBaseEntry: testBaseEntry{modtime: fileModTime2, name: "file1.txt", oid: OID2}, content: "abcdefghij"},
 	)
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -382,7 +384,7 @@ func TestCompareFileWithIdenticalContentsButDiffFileMetadata(t *testing.T) {
 		&testFile{testBaseEntry: testBaseEntry{name: "file1.txt", modtime: fileModTime2, oid: object.ID{}, owner: fileOwnerinfo2, mode: 0o777}, content: "abcdefghij"},
 	)
 
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
@@ -442,7 +444,7 @@ func TestCompareIdenticalDirectoriesWithDiffDirectoryMetadata(t *testing.T) {
 		dirObjectID,
 		&testFile{testBaseEntry: testBaseEntry{name: "file1.txt", modtime: fileModTime}, content: "abcdefghij"},
 	)
-	c, err := diff.NewComparer(&buf)
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {
diff --git a/tests/end_to_end_test/restore_test.go b/tests/end_to_end_test/restore_test.go
index c4828b37..e2d5843f 100644
--- a/tests/end_to_end_test/restore_test.go
+++ b/tests/end_to_end_test/restore_test.go
@@ -177,6 +177,8 @@ func TestRestoreCommand(t *testing.T) {
 func compareDirs(t *testing.T, source, restoreDir string) {
 	t.Helper()
 
+	const statsOnly = false
+
 	// Restored contents should match source
 	s, err := localfs.Directory(source)
 	require.NoError(t, err)
@@ -192,7 +194,7 @@ func compareDirs(t *testing.T, source, restoreDir string) {
 	require.NoError(t, err)
 
 	if !assert.Equal(t, wantHash, gotHash, "restored directory hash does not match source's hash") {
-		cmp, err := diff.NewComparer(os.Stderr)
+		cmp, err := diff.NewComparer(os.Stderr, statsOnly)
 		require.NoError(t, err)
 
 		cmp.DiffCommand = "cmp"
diff --git a/tests/recovery/recovery_test/recovery_test.go b/tests/recovery/recovery_test/recovery_test.go
index d588669b..d0b5479b 100644
--- a/tests/recovery/recovery_test/recovery_test.go
+++ b/tests/recovery/recovery_test/recovery_test.go
@@ -297,7 +297,9 @@ func CompareDirs(t *testing.T, source, destination string) {
 
 	ctx := context.Background()
 
-	c, err := diff.NewComparer(&buf)
+	const statsOnly = false
+
+	c, err := diff.NewComparer(&buf, statsOnly)
 	require.NoError(t, err)
 
 	t.Cleanup(func() {