Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package chezmoi for openSUSE:Factory checked 
in at 2024-05-01 14:56:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/chezmoi (Old)
 and      /work/SRC/openSUSE:Factory/.chezmoi.new.1880 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "chezmoi"

Wed May  1 14:56:48 2024 rev:52 rq:1171014 version:2.48.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/chezmoi/chezmoi.changes  2024-04-16 
20:12:03.714572283 +0200
+++ /work/SRC/openSUSE:Factory/.chezmoi.new.1880/chezmoi.changes        
2024-05-01 14:57:10.875495367 +0200
@@ -1,0 +2,16 @@
+Tue Apr 30 15:39:55 UTC 2024 - Filippo Bonazzi <filippo.bona...@suse.com>
+
+- Update to version 2.48.0:
+  - Features
+    * feat: Add --tree flag to unmanaged command
+    * feat: Add --tree flag to managed command
+    * feat: Add --tree flag to ignored command
+    * feat: Include name of target in error message
+  - Fixes
+    * fix: Apply .chezmoiignore to dirs in external archives
+    * fix: Remove unmanaged files from exact_ directories containing external 
files
+    * fix: Better detect username on Android/Termux systems
+  - Documentation updates
+    * docs: Document --tree flag
+
+-------------------------------------------------------------------

Old:
----
  chezmoi-2.47.4.obscpio

New:
----
  chezmoi-2.48.0.obscpio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ chezmoi.spec ++++++
--- /var/tmp/diff_new_pack.gGnN0Q/_old  2024-05-01 14:57:11.571520620 +0200
+++ /var/tmp/diff_new_pack.gGnN0Q/_new  2024-05-01 14:57:11.571520620 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           chezmoi
-Version:        2.47.4
+Version:        2.48.0
 Release:        0
 Summary:        A multi-host manager for dotfiles
 License:        MIT

++++++ _service ++++++
--- /var/tmp/diff_new_pack.gGnN0Q/_old  2024-05-01 14:57:11.615522217 +0200
+++ /var/tmp/diff_new_pack.gGnN0Q/_new  2024-05-01 14:57:11.619522361 +0200
@@ -2,7 +2,7 @@
   <service name="obs_scm" mode="manual">
     <param name="scm">git</param>
     <param name="url">https://github.com/twpayne/chezmoi.git</param>
-    <param name="revision">v2.47.4</param>
+    <param name="revision">v2.48.0</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
   </service>

++++++ chezmoi-2.47.4.obscpio -> chezmoi-2.48.0.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/govulncheck.yml 
new/chezmoi-2.48.0/.github/workflows/govulncheck.yml
--- old/chezmoi-2.47.4/.github/workflows/govulncheck.yml        2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/.github/workflows/govulncheck.yml        2024-04-26 
21:51:18.000000000 +0200
@@ -16,7 +16,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - name: go-version
       id: go-version
       run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/installer.yml 
new/chezmoi-2.48.0/.github/workflows/installer.yml
--- old/chezmoi-2.47.4/.github/workflows/installer.yml  2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/.github/workflows/installer.yml  2024-04-26 
21:51:18.000000000 +0200
@@ -17,7 +17,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - id: filter
       uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
       with:
@@ -36,7 +36,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: reviewdog/action-misspell@5bd7be2fc7ae56a517184f5c4bbcf2fd7afe3927
       with:
         locale: US
@@ -50,7 +50,7 @@
     env:
       BINARY: ${{ matrix.os == 'windows-2022' && 'bin/chezmoi.exe' || 
'bin/chezmoi' }}
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - name: test-${{ matrix.os }}-local
       shell: bash
       run: |
@@ -73,7 +73,7 @@
     env:
       BINARY: ${{ matrix.os == 'windows-2022' && 'bin/chezmoi.exe' || 
'bin/chezmoi' }}
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - name: test-${{ matrix.os }}-local
       shell: pwsh
       run: |
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/.github/workflows/main.yml 
new/chezmoi-2.48.0/.github/workflows/main.yml
--- old/chezmoi-2.47.4/.github/workflows/main.yml       2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/.github/workflows/main.yml       2024-04-26 
21:51:18.000000000 +0200
@@ -30,7 +30,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - id: filter
       uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36
       with:
@@ -56,7 +56,7 @@
     permissions:
       security-events: write
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 1
     - uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2
@@ -68,7 +68,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: reviewdog/action-misspell@5bd7be2fc7ae56a517184f5c4bbcf2fd7afe3927
       with:
         locale: US
@@ -79,7 +79,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - name: test
       env:
         CHEZMOI_GITHUB_TOKEN: ${{ secrets.CHEZMOI_GITHUB_TOKEN }}
@@ -92,7 +92,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - name: test
       env:
         CHEZMOI_GITHUB_TOKEN: ${{ secrets.CHEZMOI_GITHUB_TOKEN }}
@@ -105,7 +105,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: ${{ env.GO_VERSION }}
@@ -140,7 +140,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: oldstable
@@ -173,7 +173,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 0
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
@@ -238,7 +238,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 0
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
@@ -280,7 +280,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: ${{ env.GO_VERSION }}
@@ -298,7 +298,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: ${{ env.GO_VERSION }}
@@ -324,7 +324,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 0
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
@@ -372,7 +372,7 @@
     permissions:
       contents: read
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: ${{ env.GO_VERSION }}
@@ -414,13 +414,13 @@
       run: snapcraft whoami
       env:
         SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 0
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
       with:
         go-version: ${{ env.GO_VERSION }}
-    - uses: sigstore/cosign-installer@e1523de7571e31dbe865fd2e80c5c7c23ae71eb4
+    - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20
     - name: create-syso
       run: |
         make create-syso
@@ -442,7 +442,7 @@
     permissions:
       contents: write
     steps:
-    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
+    - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b
       with:
         fetch-depth: 0
     - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/assets/chezmoi.io/docs/links/articles.md.yaml 
new/chezmoi-2.48.0/assets/chezmoi.io/docs/links/articles.md.yaml
--- old/chezmoi-2.47.4/assets/chezmoi.io/docs/links/articles.md.yaml    
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/assets/chezmoi.io/docs/links/articles.md.yaml    
2024-04-26 21:51:18.000000000 +0200
@@ -1,4 +1,4 @@
-articles:
+Garticles:
 - date: '2019-01-10'
   version: 0.0.11
   title: 'Linux Fu: The kitchen sync'
@@ -407,3 +407,7 @@
   version: 2.47.2
   title: Whatever happened to dotfiles?
   url: https://ryan0x44.substack.com/p/whatever-happened-to-dotfiles
+- date: '2024-04-24'
+  version: 2.47.4
+  title: 'Chezmoi: Manage Your Dotfiles Across Multiple Linux Systems'
+  url: https://linuxtldr.com/installing-chezmoi/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/assets/chezmoi.io/docs/quick-start.md 
new/chezmoi-2.48.0/assets/chezmoi.io/docs/quick-start.md
--- old/chezmoi-2.47.4/assets/chezmoi.io/docs/quick-start.md    2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/assets/chezmoi.io/docs/quick-start.md    2024-04-26 
21:51:18.000000000 +0200
@@ -74,7 +74,7 @@
 and then push your repo:
 
 ```console
-$ git remote add origin https://github.com/$GITHUB_USERNAME/dotfiles.git
+$ git remote add origin g...@github.com:$GITHUB_USERNAME/dotfiles.git
 $ git branch -M main
 $ git push -u origin main
 ```
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/assets/chezmoi.io/docs/reference/command-line-flags/common.md
 
new/chezmoi-2.48.0/assets/chezmoi.io/docs/reference/command-line-flags/common.md
--- 
old/chezmoi-2.47.4/assets/chezmoi.io/docs/reference/command-line-flags/common.md
    2024-04-12 13:51:15.000000000 +0200
+++ 
new/chezmoi-2.48.0/assets/chezmoi.io/docs/reference/command-line-flags/common.md
    2024-04-26 21:51:18.000000000 +0200
@@ -55,6 +55,10 @@
 Interpret *targets* passed to the command as paths in the source directory
 rather than the destination directory.
 
+## `--tree`
+
+Print paths as a tree instead of a list.
+
 ## `--use-builtin-diff`
 
 Use chezmoi's builtin diff, even if the `diff.command` configuration variable
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/go.mod new/chezmoi-2.48.0/go.mod
--- old/chezmoi-2.47.4/go.mod   2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/go.mod   2024-04-26 21:51:18.000000000 +0200
@@ -6,12 +6,12 @@
 
 require (
        filippo.io/age v1.1.1
-       github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1
+       github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2
        github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0
        github.com/Masterminds/sprig/v3 v3.2.3
        github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2
        github.com/Shopify/ejson v1.5.0
-       github.com/alecthomas/assert/v2 v2.8.0
+       github.com/alecthomas/assert/v2 v2.8.1
        github.com/aws/aws-sdk-go-v2 v1.26.1
        github.com/aws/aws-sdk-go-v2/config v1.27.11
        github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.28.6
@@ -32,7 +32,7 @@
        github.com/mitchellh/mapstructure v1.5.0
        github.com/muesli/combinator v0.3.0
        github.com/muesli/termenv v0.15.2
-       github.com/pelletier/go-toml/v2 v2.2.0
+       github.com/pelletier/go-toml/v2 v2.2.1
        github.com/rogpeppe/go-internal v1.12.0
        github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
        github.com/spf13/cobra v1.8.0
@@ -60,13 +60,13 @@
 require (
        dario.cat/mergo v1.0.0 // indirect
        github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
-       github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
-       github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 
// indirect
+       github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 // indirect
+       github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1 
// indirect
        github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // 
indirect
        github.com/BobuSumisu/aho-corasick v1.0.3 // indirect
        github.com/Masterminds/goutils v1.1.1 // indirect
        github.com/Masterminds/semver/v3 v3.2.1 // indirect
-       github.com/Microsoft/go-winio v0.6.1 // indirect
+       github.com/Microsoft/go-winio v0.6.2 // indirect
        github.com/ProtonMail/go-crypto v1.0.0 // indirect
        github.com/alecthomas/chroma/v2 v2.13.0 // indirect
        github.com/alecthomas/repr v0.4.0 // indirect
@@ -88,7 +88,7 @@
        github.com/bradenhilton/cityhash v1.0.0 // indirect
        github.com/charmbracelet/harmonica v0.2.0 // indirect
        github.com/charmbracelet/lipgloss v0.10.0 // indirect
-       github.com/cloudflare/circl v1.3.7 // indirect
+       github.com/cloudflare/circl v1.3.8 // indirect
        github.com/containerd/console v1.0.4 // indirect
        github.com/creack/pty/v2 v2.0.0-20231209135443-03db72c7b76c // indirect
        github.com/cyphar/filepath-securejoin v0.2.4 // indirect
@@ -136,7 +136,7 @@
        github.com/rs/zerolog v1.32.0 // indirect
        github.com/sagikazarmark/locafero v0.4.0 // indirect
        github.com/sagikazarmark/slog-shim v0.1.0 // indirect
-       github.com/shopspring/decimal v1.3.1 // indirect
+       github.com/shopspring/decimal v1.4.0 // indirect
        github.com/skeema/knownhosts v1.2.2 // indirect
        github.com/sourcegraph/conc v0.3.0 // indirect
        github.com/spf13/afero v1.11.0 // indirect
@@ -147,8 +147,7 @@
        github.com/yuin/goldmark v1.7.1 // indirect
        github.com/yuin/goldmark-emoji v1.0.2 // indirect
        go.uber.org/multierr v1.11.0 // indirect
-       golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect
-       golang.org/x/mod v0.17.0 // indirect
+       golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
        golang.org/x/net v0.24.0 // indirect
        golang.org/x/text v0.14.0 // indirect
        golang.org/x/tools v0.20.0 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/go.sum new/chezmoi-2.48.0/go.sum
--- old/chezmoi-2.47.4/go.sum   2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/go.sum   2024-04-26 21:51:18.000000000 +0200
@@ -20,14 +20,14 @@
 filippo.io/edwards25519 v1.0.0/go.mod 
h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 
h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod 
h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 
h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod 
h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 
h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod 
h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 
h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod 
h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 
h1:sUFnFjzDUie80h24I7mrKtwCKgLY9L8h5Tp2x9+TWqk=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0/go.mod 
h1:52JbnQTp15qg5mRkMBHwp0j0ZFwHJ42Sx3zVV5RE9p0=
 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.1.0 
h1:h4Zxgmi9oyZL2l8jeg1iRTqPloHktywWcu0nlJmo1tA=
 github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets 
v1.1.0/go.mod h1:LgLGXawqSreJz135Elog0ywTJDsm0Hz2k+N+6ZK35u8=
-github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 
h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
-github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod 
h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1 
h1:9fXQS/0TtQmKXp8SureKouF+idbQvp7cPUxykiohnBs=
+github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.1/go.mod 
h1:f+OaoSg0VQYPMqB0Jp2D54j1VHzITYcJaCNwV+k00ts=
 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 
h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod 
h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/BobuSumisu/aho-corasick v1.0.3 
h1:uuf+JHwU9CHP2Vx+wAy6jcksJThhJS9ehR8a+4nPE9g=
@@ -40,16 +40,16 @@
 github.com/Masterminds/sprig/v3 v3.2.3 
h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA=
 github.com/Masterminds/sprig/v3 v3.2.3/go.mod 
h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
 github.com/Microsoft/go-winio v0.5.2/go.mod 
h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
-github.com/Microsoft/go-winio v0.6.1 
h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
-github.com/Microsoft/go-winio v0.6.1/go.mod 
h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
+github.com/Microsoft/go-winio v0.6.2 
h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod 
h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
 github.com/ProtonMail/go-crypto v1.0.0 
h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
 github.com/ProtonMail/go-crypto v1.0.0/go.mod 
h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
 github.com/Shopify/ejson v1.5.0 h1:SDV5HmQlpn3hSUiw9HV0nOj9tpzup5i0OV71ioLYkpw=
 github.com/Shopify/ejson v1.5.0/go.mod 
h1:a4+JLWuTe9+tTofPBGWZoqzf0af6eQKGmFqbxoMSARc=
 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d 
h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod 
h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
-github.com/alecthomas/assert/v2 v2.8.0 
h1:8b0foWfS2dH6MltxQMPvWdSGN1wE4K1vyab9PGW4qgE=
-github.com/alecthomas/assert/v2 v2.8.0/go.mod 
h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/alecthomas/assert/v2 v2.8.1 
h1:YCxnYR6jjpfnEK5AK5SysALKdUEBPGH4Y7As6tBnDw0=
+github.com/alecthomas/assert/v2 v2.8.1/go.mod 
h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
 github.com/alecthomas/chroma/v2 v2.13.0 
h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
 github.com/alecthomas/chroma/v2 v2.13.0/go.mod 
h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
 github.com/alecthomas/repr v0.4.0 
h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
@@ -115,8 +115,8 @@
 github.com/charmbracelet/lipgloss v0.10.0 
h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s=
 github.com/charmbracelet/lipgloss v0.10.0/go.mod 
h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE=
 github.com/cloudflare/circl v1.3.3/go.mod 
h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
-github.com/cloudflare/circl v1.3.7 
h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
-github.com/cloudflare/circl v1.3.7/go.mod 
h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
+github.com/cloudflare/circl v1.3.8 
h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI=
+github.com/cloudflare/circl v1.3.8/go.mod 
h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
 github.com/containerd/console v1.0.4 
h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro=
 github.com/containerd/console v1.0.4/go.mod 
h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
 github.com/coreos/go-semver v0.3.1 
h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
@@ -304,6 +304,8 @@
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod 
h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.2 
h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod 
h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5 
h1:8Q0qkMVC/MmWkpIdlvZgcv2o2jrlF6zqVOh7W5YHdMA=
+github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod 
h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
 github.com/montanaflynn/stats v0.7.0 
h1:r3y12KyNxj/Sb/iOE46ws+3mS1+MZca1wlHQFPsY/JU=
 github.com/montanaflynn/stats v0.7.0/go.mod 
h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 
h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
@@ -328,8 +330,8 @@
 github.com/onsi/gomega v1.27.10/go.mod 
h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
 github.com/pelletier/go-toml v1.9.3 
h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
 github.com/pelletier/go-toml v1.9.3/go.mod 
h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
-github.com/pelletier/go-toml/v2 v2.2.0 
h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
-github.com/pelletier/go-toml/v2 v2.2.0/go.mod 
h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pelletier/go-toml/v2 v2.2.1 
h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
+github.com/pelletier/go-toml/v2 v2.2.1/go.mod 
h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/peterbourgon/diskv v2.0.1+incompatible 
h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
 github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod 
h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
 github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
@@ -368,11 +370,11 @@
 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 
h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod 
h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
 github.com/shopspring/decimal v1.2.0/go.mod 
h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
-github.com/shopspring/decimal v1.3.1 
h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
-github.com/shopspring/decimal v1.3.1/go.mod 
h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
+github.com/shopspring/decimal v1.4.0 
h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod 
h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
 github.com/sirupsen/logrus v1.7.0/go.mod 
h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/sirupsen/logrus v1.9.0 
h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
-github.com/sirupsen/logrus v1.9.0/go.mod 
h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/sirupsen/logrus v1.9.3 
h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod 
h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
 github.com/skeema/knownhosts v1.2.2 
h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
 github.com/skeema/knownhosts v1.2.2/go.mod 
h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
 github.com/smarty/assertions v1.15.0 
h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY=
@@ -466,8 +468,8 @@
 golang.org/x/crypto v0.7.0/go.mod 
h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
 golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
 golang.org/x/crypto v0.22.0/go.mod 
h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 
h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc=
-golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod 
h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f 
h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
+golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod 
h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod 
h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/chezmoi/sourcestate.go 
new/chezmoi-2.48.0/internal/chezmoi/sourcestate.go
--- old/chezmoi-2.47.4/internal/chezmoi/sourcestate.go  2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/chezmoi/sourcestate.go  2024-04-26 
21:51:18.000000000 +0200
@@ -1108,6 +1108,14 @@
                allSourceStateEntries[targetRelPath] = 
append(allSourceStateEntries[targetRelPath], sourceStateEntry)
        }
 
+       // Where there are multiple SourceStateEntries for a single target, 
replace
+       // them with a single canonical SourceStateEntry if possible.
+       for targetRelPath, sourceStateEntries := range allSourceStateEntries {
+               if sourceStateEntry, ok := 
canonicalSourceStateEntry(sourceStateEntries); ok {
+                       allSourceStateEntries[targetRelPath] = 
[]SourceStateEntry{sourceStateEntry}
+               }
+       }
+
        // Generate SourceStateRemoves for exact directories.
        for targetRelPath, sourceStateEntries := range allSourceStateEntries {
                if len(sourceStateEntries) != 1 {
@@ -1231,11 +1239,6 @@
                        continue
                }
 
-               // Allow duplicate equivalent source entries for directories.
-               if allEquivalentDirs(sourceStateEntries) {
-                       continue
-               }
-
                origins := make([]string, 0, len(sourceStateEntries))
                for _, sourceStateEntry := range sourceStateEntries {
                        origins = append(origins, 
sourceStateEntry.Origin().OriginString())
@@ -2191,7 +2194,7 @@
        }, nil
 }
 
-// populateImplicitDirs creates implicit parent directories for 
externalRelPath.
+// populateImplicitParentDirs creates implicit parent directories for 
externalRelPath.
 func (s *SourceState) populateImplicitParentDirs(
        externalRelPath RelPath,
        external *External,
@@ -2307,6 +2310,9 @@
                targetRelPath := externalRelPath.JoinString(name)
 
                if s.Ignore(targetRelPath) {
+                       if fileInfo.IsDir() {
+                               return fs.SkipDir
+                       }
                        return nil
                }
 
@@ -2793,9 +2799,12 @@
        return e.URL + " defined in " + e.sourceAbsPath.String()
 }
 
-// allEquivalentDirs returns if sourceStateEntries are all equivalent
-// directories.
-func allEquivalentDirs(sourceStateEntries []SourceStateEntry) bool {
+// canonicalSourceStateEntry returns the canonical SourceStateEntry for the
+// given sourceStateEntries.
+//
+// This only applies to directories, where SourceStateImplicitDirs are
+// considered equivalent to all SourceStateDirs.
+func canonicalSourceStateEntry(sourceStateEntries []SourceStateEntry) 
(SourceStateEntry, bool) {
        // Find all directories to check for equivalence.
        var firstSourceStateDir *SourceStateDir
        sourceStateDirs := make([]SourceStateEntry, 0, len(sourceStateEntries))
@@ -2807,29 +2816,37 @@
                case *SourceStateImplicitDir:
                        sourceStateDirs = append(sourceStateDirs, 
sourceStateEntry)
                default:
-                       return false
+                       return nil, false
                }
        }
 
-       // If there are no SourceStateDirs then there are no equivalent 
directories.
-       if len(sourceStateDirs) == 0 {
-               return false
-       }
-
-       // Check for equivalence.
-       for _, sourceStateDir := range sourceStateDirs {
-               switch sourceStateDir := sourceStateDir.(type) {
-               case *SourceStateDir:
-                       if sourceStateDir.Attr != firstSourceStateDir.Attr {
-                               return false
+       switch len(sourceStateDirs) {
+       case 0:
+               // If there are no SourceStateDirs then there are no equivalent 
directories.
+               return nil, false
+       case 1:
+               return sourceStateDirs[0], true
+       default:
+               // Check for equivalence.
+               for _, sourceStateDir := range sourceStateDirs {
+                       switch sourceStateDir := sourceStateDir.(type) {
+                       case *SourceStateDir:
+                               if sourceStateDir.Attr != 
firstSourceStateDir.Attr {
+                                       return nil, false
+                               }
+                       case *SourceStateImplicitDir:
+                               // SourceStateImplicitDirs are considered 
equivalent to all other
+                               // directories.
                        }
-               case *SourceStateImplicitDir:
-                       // SourceStateImplicitDirs are considered equivalent to 
all other
-                       // directories.
                }
+               // If all directories are equivalent then return the first real
+               // *SourceStateDir, if it exists.
+               if firstSourceStateDir != nil {
+                       return firstSourceStateDir, true
+               }
+               // Otherwise, return the first entry which is a 
*SourceStateImplicitDir.
+               return sourceStateDirs[0], true
        }
-
-       return true
 }
 
 // isAppleDoubleFile returns true if the file looks like and has the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest.go 
new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest.go
--- old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest.go      2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest.go      2024-04-26 
21:51:18.000000000 +0200
@@ -69,6 +69,9 @@
 
 // JoinLines joins lines with newlines.
 func JoinLines(lines ...string) string {
+       if len(lines) == 0 {
+               return ""
+       }
        return strings.Join(lines, "\n") + "\n"
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest_test.go 
new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest_test.go
--- old/chezmoi-2.47.4/internal/chezmoitest/chezmoitest_test.go 2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/chezmoitest/chezmoitest_test.go 2024-04-26 
21:51:18.000000000 +0200
@@ -14,7 +14,7 @@
        }{
                {
                        lines:    nil,
-                       expected: "\n",
+                       expected: "",
                },
                {
                        lines:    []string{""},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/applycmd_test.go 
new/chezmoi-2.48.0/internal/cmd/applycmd_test.go
--- old/chezmoi-2.47.4/internal/cmd/applycmd_test.go    2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/applycmd_test.go    2024-04-26 
21:51:18.000000000 +0200
@@ -2,6 +2,8 @@
 
 import (
        "io/fs"
+       "net/http"
+       "net/http/httptest"
        "path/filepath"
        "testing"
 
@@ -233,6 +235,27 @@
        })
 }
 
+func TestIssue2597(t *testing.T) {
+       chezmoitest.WithTestFS(t, map[string]any{
+               "/home/user": map[string]any{
+                       ".local/share/chezmoi": map[string]any{
+                               ".chezmoiexternal.toml": chezmoitest.JoinLines(
+                                       `[".oh-my-zsh"]`,
+                                       `    type = "archive"`,
+                                       `    url = 
"https://github.com/ohmyzsh/ohmyzsh/archive/master.tar.gz"`,
+                                       `    exact = true`,
+                                       `    stripComponents = 1`,
+                               ),
+                               ".chezmoiignore": chezmoitest.JoinLines(
+                                       `.oh-my-zsh/cache`,
+                               ),
+                       },
+               },
+       }, func(fileSystem vfs.FS) {
+               assert.NoError(t, newTestConfig(t, 
fileSystem).execute([]string{"apply"}))
+       })
+}
+
 func TestIssue3206(t *testing.T) {
        chezmoitest.WithTestFS(t, map[string]any{
                "/home/user": map[string]any{
@@ -264,3 +287,39 @@
                assert.NoError(t, newTestConfig(t, 
fileSystem).execute([]string{"apply"}))
        })
 }
+
+func TestIssue3703(t *testing.T) {
+       httpServer := httptest.NewServer(http.HandlerFunc(func(w 
http.ResponseWriter, r *http.Request) {
+               _, err := w.Write([]byte("contents of file\n"))
+               assert.NoError(t, err)
+       }))
+       defer httpServer.Close()
+
+       chezmoitest.WithTestFS(t, map[string]any{
+               "/home/user": map[string]any{
+                       ".local": map[string]any{
+                               "bin": map[string]any{
+                                       "unmanaged": "",
+                               },
+                               "share/chezmoi": map[string]any{
+                                       ".chezmoiexternal.toml.tmpl": 
chezmoitest.JoinLines(
+                                               `[".local/bin/file"]`,
+                                               `    type = "file"`,
+                                               `    url = 
"`+httpServer.URL+`/file"`,
+                                       ),
+                                       "dot_local/exact_bin/.keep": "",
+                               },
+                       },
+               },
+       }, func(fileSystem vfs.FS) {
+               assert.NoError(t, newTestConfig(t, 
fileSystem).execute([]string{"apply"}))
+               vfst.RunTests(t, fileSystem, ".local/bin",
+                       vfst.TestPath("/home/user/.local/bin/file",
+                               vfst.TestContentsString("contents of file\n"),
+                       ),
+                       vfst.TestPath("/home/user/.local/bin/unmanaged",
+                               vfst.TestDoesNotExist(),
+                       ),
+               )
+       })
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/cmd.go 
new/chezmoi-2.48.0/internal/cmd/cmd.go
--- old/chezmoi-2.47.4/internal/cmd/cmd.go      2024-04-12 13:51:15.000000000 
+0200
+++ new/chezmoi-2.48.0/internal/cmd/cmd.go      2024-04-26 21:51:18.000000000 
+0200
@@ -138,7 +138,7 @@
        return help.example
 }
 
-// extractHelps returns the helps parse from r.
+// extractHelp returns the helps parse from r.
 func extractHelp(command string, data []byte, longHelpTermRenderer, 
exampleTermRenderer *glamour.TermRenderer) (*help, error) {
        type stateType int
        const (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/config.go 
new/chezmoi-2.48.0/internal/cmd/config.go
--- old/chezmoi-2.47.4/internal/cmd/config.go   2024-04-12 13:51:15.000000000 
+0200
+++ new/chezmoi-2.48.0/internal/cmd/config.go   2024-04-26 21:51:18.000000000 
+0200
@@ -194,6 +194,7 @@
        chattr          chattrCmdConfig
        dump            dumpCmdConfig
        executeTemplate executeTemplateCmdConfig
+       ignored         ignoredCmdConfig
        _import         importCmdConfig
        init            initCmdConfig
        managed         managedCmdConfig
@@ -652,11 +653,14 @@
                switch err := sourceState.Apply(targetSystem, c.destSystem, 
c.persistentState, targetDirAbsPath, targetRelPath, applyOptions); {
                case errors.Is(err, fs.SkipDir):
                        continue
-               case err != nil && c.keepGoing:
-                       c.errorf("%v\n", err)
-                       keptGoingAfterErr = true
                case err != nil:
-                       return err
+                       err = fmt.Errorf("%s: %w", targetRelPath, err)
+                       if c.keepGoing {
+                               c.errorf("%v\n", err)
+                               keptGoingAfterErr = true
+                       } else {
+                               return err
+                       }
                }
        }
 
@@ -2219,23 +2223,28 @@
 func (c *Config) newTemplateData(cmd *cobra.Command) *templateData {
        // Determine the user's username and group, if possible.
        //
-       // user.Current and user.LookupGroupId in Go's standard library are
+       // os/user.Current and os/user.LookupGroupId in Go's standard library 
are
        // generally unreliable, so work around errors if possible, or ignore 
them.
        //
+       // On Android, user.Current always fails. Instead, use $LOGNAME (as 
this is
+       // set by Termux), or $USER if $LOGNAME is not set.
+       //
        // If CGO is disabled, then the Go standard library falls back to 
parsing
        // /etc/passwd and /etc/group, which will return incorrect results 
without
        // error if the system uses an alternative password database such as 
NIS or
        // LDAP.
        //
-       // If CGO is enabled then user.Current and user.LookupGroupId will use 
the
-       // underlying libc functions, namely getpwuid_r and getgrnam_r. If 
linked
-       // with glibc this will return the correct result. If linked with musl 
then
-       // they will use musl's implementation which, like Go's non-CGO
+       // If CGO is enabled then os/user.Current and os/user.LookupGroupId 
will use
+       // the underlying libc functions, namely getpwuid_r and getgrnam_r. If
+       // linked with glibc this will return the correct result. If linked with
+       // musl then they will use musl's implementation which, like Go's 
non-CGO
        // implementation, also only parses /etc/passwd and /etc/group and so 
also
        // returns incorrect results without error if NIS or LDAP are being 
used.
        //
-       // On Windows, the user's group ID returned by user.Current() is an SID 
and
-       // no further useful lookup is possible with Go's standard library.
+       // On Windows, the user's group ID returned by os/user.Current() is an 
SID
+       // and no further useful lookup is possible with Go's standard library.
+       //
+       // If os/user.Current fails, then fallback to $USER.
        //
        // Since neither the username nor the group are likely widely used in
        // templates, leave these variables unset if their values cannot be
@@ -2243,7 +2252,9 @@
        // alerting the user to the problem and allowing them to find 
alternative
        // solutions.
        var gid, group, uid, username string
-       if currentUser, err := user.Current(); err == nil {
+       if runtime.GOOS == "android" {
+               username = firstNonEmptyString(os.Getenv("LOGNAME"), 
os.Getenv("USER"))
+       } else if currentUser, err := user.Current(); err == nil {
                gid = currentUser.Gid
                uid = currentUser.Uid
                username = currentUser.Username
@@ -2657,6 +2668,23 @@
        return os.WriteFile(c.outputAbsPath.String(), data, 0o666) 
//nolint:gosec
 }
 
+type writePathsOptions struct {
+       tree bool
+}
+
+func (c *Config) writePaths(paths []string, options writePathsOptions) error {
+       builder := strings.Builder{}
+       if options.tree {
+               newPathListTreeFromPathsSlice(paths).writeChildren(&builder, 
"", "  ")
+       } else {
+               sort.Strings(paths)
+               for _, path := range paths {
+                       fmt.Fprintln(&builder, path)
+               }
+       }
+       return c.writeOutputString(builder.String())
+}
+
 // writeOutputString writes data to the configured output.
 func (c *Config) writeOutputString(data string) error {
        return c.writeOutput([]byte(data))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/ignoredcmd.go 
new/chezmoi-2.48.0/internal/cmd/ignoredcmd.go
--- old/chezmoi-2.47.4/internal/cmd/ignoredcmd.go       2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/ignoredcmd.go       2024-04-26 
21:51:18.000000000 +0200
@@ -1,13 +1,15 @@
 package cmd
 
 import (
-       "strings"
-
        "github.com/spf13/cobra"
 
        "github.com/twpayne/chezmoi/v2/internal/chezmoi"
 )
 
+type ignoredCmdConfig struct {
+       tree bool
+}
+
 func (c *Config) newIgnoredCmd() *cobra.Command {
        ignoredCmd := &cobra.Command{
                Use:         "ignored",
@@ -19,18 +21,13 @@
                Annotations: newAnnotations(),
        }
 
+       ignoredCmd.Flags().BoolVarP(&c.ignored.tree, "tree", "t", 
c.ignored.tree, "Print paths as a tree")
+
        return ignoredCmd
 }
 
 func (c *Config) runIgnoredCmd(cmd *cobra.Command, args []string, sourceState 
*chezmoi.SourceState) error {
-       builder := strings.Builder{}
-       for _, relPath := range sourceState.Ignored() {
-               if _, err := builder.WriteString(relPath.String()); err != nil {
-                       return err
-               }
-               if err := builder.WriteByte('\n'); err != nil {
-                       return err
-               }
-       }
-       return c.writeOutputString(builder.String())
+       return c.writePaths(stringersToStrings(sourceState.Ignored()), 
writePathsOptions{
+               tree: c.ignored.tree,
+       })
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/managedcmd.go 
new/chezmoi-2.48.0/internal/cmd/managedcmd.go
--- old/chezmoi-2.47.4/internal/cmd/managedcmd.go       2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/managedcmd.go       2024-04-26 
21:51:18.000000000 +0200
@@ -2,8 +2,6 @@
 
 import (
        "fmt"
-       "sort"
-       "strings"
 
        "github.com/spf13/cobra"
 
@@ -13,6 +11,7 @@
 type managedCmdConfig struct {
        filter    *chezmoi.EntryTypeFilter
        pathStyle chezmoi.PathStyle
+       tree      bool
 }
 
 func (c *Config) newManagedCmd() *cobra.Command {
@@ -30,6 +29,7 @@
        managedCmd.Flags().VarP(c.managed.filter.Exclude, "exclude", "x", 
"Exclude entry types")
        managedCmd.Flags().VarP(c.managed.filter.Include, "include", "i", 
"Include entry types")
        managedCmd.Flags().VarP(&c.managed.pathStyle, "path-style", "p", "Path 
style")
+       managedCmd.Flags().BoolVarP(&c.managed.tree, "tree", "t", 
c.managed.tree, "Print paths as a tree")
 
        return managedCmd
 }
@@ -48,7 +48,7 @@
                }
        }
 
-       var paths []string
+       var paths []fmt.Stringer
        _ = sourceState.ForEach(
                func(targetRelPath chezmoi.RelPath, sourceStateEntry 
chezmoi.SourceStateEntry) error {
                        if 
!c.managed.filter.IncludeSourceStateEntry(sourceStateEntry) {
@@ -77,26 +77,23 @@
                                }
                        }
 
-                       var path string
+                       var path fmt.Stringer
                        switch c.managed.pathStyle {
                        case chezmoi.PathStyleAbsolute:
-                               path = 
c.DestDirAbsPath.Join(targetRelPath).String()
+                               path = c.DestDirAbsPath.Join(targetRelPath)
                        case chezmoi.PathStyleRelative:
-                               path = targetRelPath.String()
+                               path = targetRelPath
                        case chezmoi.PathStyleSourceAbsolute:
-                               path = 
c.SourceDirAbsPath.Join(sourceStateEntry.SourceRelPath().RelPath()).String()
+                               path = 
c.SourceDirAbsPath.Join(sourceStateEntry.SourceRelPath().RelPath())
                        case chezmoi.PathStyleSourceRelative:
-                               path = 
sourceStateEntry.SourceRelPath().RelPath().String()
+                               path = 
sourceStateEntry.SourceRelPath().RelPath()
                        }
                        paths = append(paths, path)
                        return nil
                },
        )
 
-       sort.Strings(paths)
-       builder := strings.Builder{}
-       for _, path := range paths {
-               fmt.Fprintln(&builder, path)
-       }
-       return c.writeOutputString(builder.String())
+       return c.writePaths(stringersToStrings(paths), writePathsOptions{
+               tree: c.managed.tree,
+       })
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/pathlist.go 
new/chezmoi-2.48.0/internal/cmd/pathlist.go
--- old/chezmoi-2.47.4/internal/cmd/pathlist.go 1970-01-01 01:00:00.000000000 
+0100
+++ new/chezmoi-2.48.0/internal/cmd/pathlist.go 2024-04-26 21:51:18.000000000 
+0200
@@ -0,0 +1,49 @@
+package cmd
+
+import (
+       "strings"
+
+       "github.com/twpayne/chezmoi/v2/internal/chezmoimaps"
+)
+
+type pathListTreeNode struct {
+       component string
+       children  map[string]*pathListTreeNode
+}
+
+func newPathListTreeNode(component string) *pathListTreeNode {
+       return &pathListTreeNode{
+               component: component,
+               children:  make(map[string]*pathListTreeNode),
+       }
+}
+
+func newPathListTreeFromPathsSlice(paths []string) *pathListTreeNode {
+       root := newPathListTreeNode("")
+       for _, path := range paths {
+               n := root
+               for _, component := range strings.Split(path, "/") {
+                       child, ok := n.children[component]
+                       if !ok {
+                               child = newPathListTreeNode(component)
+                               n.children[component] = child
+                       }
+                       n = child
+               }
+       }
+       return root
+}
+
+func (n *pathListTreeNode) write(sb *strings.Builder, prefix, indent string) {
+       sb.WriteString(prefix)
+       sb.WriteString(n.component)
+       sb.WriteByte('\n')
+       n.writeChildren(sb, prefix+indent, indent)
+}
+
+func (n *pathListTreeNode) writeChildren(sb *strings.Builder, prefix, indent 
string) {
+       for _, key := range chezmoimaps.SortedKeys(n.children) {
+               child := n.children[key]
+               child.write(sb, prefix, indent)
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/pathlist_test.go 
new/chezmoi-2.48.0/internal/cmd/pathlist_test.go
--- old/chezmoi-2.47.4/internal/cmd/pathlist_test.go    1970-01-01 
01:00:00.000000000 +0100
+++ new/chezmoi-2.48.0/internal/cmd/pathlist_test.go    2024-04-26 
21:51:18.000000000 +0200
@@ -0,0 +1,75 @@
+package cmd
+
+import (
+       "strings"
+       "testing"
+
+       "github.com/alecthomas/assert/v2"
+
+       "github.com/twpayne/chezmoi/v2/internal/chezmoitest"
+)
+
+func TestNewNodeFromPathsSlice(t *testing.T) {
+       for _, tc := range []struct {
+               name     string
+               paths    []string
+               expected []string
+       }{
+               {
+                       name: "empty",
+               },
+               {
+                       name: "root",
+                       paths: []string{
+                               "a",
+                       },
+                       expected: []string{
+                               "a",
+                       },
+               },
+               {
+                       name: "simple",
+                       paths: []string{
+                               "a",
+                               "b",
+                       },
+                       expected: []string{
+                               "a",
+                               "b",
+                       },
+               },
+               {
+                       name: "simple_nesting",
+                       paths: []string{
+                               "a/b",
+                       },
+                       expected: []string{
+                               "a",
+                               "  b",
+                       },
+               },
+               {
+                       name: "multiple_simple_nesting",
+                       paths: []string{
+                               "a/a",
+                               "a/b",
+                               "b/a",
+                               "b/b",
+                       },
+                       expected: []string{
+                               "a",
+                               "  a",
+                               "  b",
+                               "b",
+                               "  a",
+                               "  b",
+                       },
+               },
+       } {
+               t.Run(tc.name, func(t *testing.T) {
+                       var sb strings.Builder
+                       
newPathListTreeFromPathsSlice(tc.paths).writeChildren(&sb, "", "  ")
+                       assert.Equal(t, chezmoitest.JoinLines(tc.expected...), 
sb.String())
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/apply.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/apply.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/apply.txtar        
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/apply.txtar        
2024-04-26 21:51:18.000000000 +0200
@@ -69,3 +69,4 @@
 
 # test that chezmoi apply --source-path fails when called with a 
targetDirAbsPath
 ! exec chezmoi apply --force --source-path $HOME${/}.file
+[!windows] stderr ${HOME@R}/\.file:\snot\sin\s${CHEZMOISOURCEDIR@R}$
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/external.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/external.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/external.txtar     
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/external.txtar     
2024-04-26 21:51:18.000000000 +0200
@@ -97,7 +97,7 @@
 
 # test that checksums detect corrupt files
 ! exec chezmoi apply --force
-stderr 'MD5 mismatch'
+stderr \.file:\sMD5\smismatch
 stderr 'SHA256 mismatch'
 
 chhome home12/user
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/ignore.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/ignore.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/ignore.txtar       
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/ignore.txtar       
2024-04-26 21:51:18.000000000 +0200
@@ -11,6 +11,10 @@
 exec chezmoi ignored
 cmp stdout golden/ignored
 
+# test that chezmoi ignored --tree lists the ignored entries in a tree-like 
format
+exec chezmoi ignored --tree
+cmp stdout golden/ignored-tree
+
 chhome home2/user
 
 # test that chezmoi manage lists all managed files
@@ -48,6 +52,9 @@
 -- golden/ignored --
 .dir
 README.md
+-- golden/ignored-tree --
+.dir
+README.md
 -- golden/managed-all --
 .dir
 .dir/file.txt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue2597.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue2597.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue2597.txtar    
1970-01-01 01:00:00.000000000 +0100
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue2597.txtar    
2024-04-26 21:51:18.000000000 +0200
@@ -0,0 +1,20 @@
+exec tar czf www/master.tar.gz master
+
+httpd www
+
+exec chezmoi apply
+exists $HOME/.oh-my-zsh/README.md
+! exists $HOME/.oh-my-zsh/cache/.gitkeep
+
+-- home/user/.local/share/chezmoi/.chezmoiexternal.toml.tmpl --
+[".oh-my-zsh"]
+    type = "archive"
+    url = "{{ env "HTTPD_URL" }}/master.tar.gz"
+    exact = true
+    stripComponents = 1
+-- home/user/.local/share/chezmoi/.chezmoiignore --
+.oh-my-zsh/cache
+-- master/README.md --
+# contents of README.md
+-- master/cache/.gitkeep --
+-- www/.keep --
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue3703.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue3703.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/issue3703.txtar    
1970-01-01 01:00:00.000000000 +0100
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/issue3703.txtar    
2024-04-26 21:51:18.000000000 +0200
@@ -0,0 +1,16 @@
+httpd www
+
+# test that chezmoi apply removes unmanaged files from an exact_ directory 
containing an external
+exists $HOME/.local/bin/unmanaged
+exec chezmoi apply --debug
+cmp $HOME/.local/bin/file www/file
+! exists $HOME/.local/bin/unmanaged
+
+-- home/user/.local/bin/unmanaged --
+-- home/user/.local/share/chezmoi/.chezmoiexternal.toml.tmpl --
+[".local/bin/file"]
+    type = "file"
+    url = "{{ env "HTTPD_URL" }}/file"
+-- home/user/.local/share/chezmoi/dot_local/exact_bin/.keep --
+-- www/file --
+# contents of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/keepgoing.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/keepgoing.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/keepgoing.txtar    
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/keepgoing.txtar    
2024-04-26 21:51:18.000000000 +0200
@@ -8,6 +8,7 @@
 cmp $HOME/1ok golden/1ok
 ! exists $HOME/2error
 ! exists $HOME/3ok
+stderr '2error: template: 2error\.tmpl:2: unclosed action started at 
2error\.tmpl:1'
 
 # test that chezmoi apply with --keep-going writes all files that it can 
without errors
 ! exec chezmoi apply --force --keep-going
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/managedtree.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/managedtree.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/managedtree.txtar  
1970-01-01 01:00:00.000000000 +0100
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/managedtree.txtar  
2024-04-26 21:51:18.000000000 +0200
@@ -0,0 +1,20 @@
+mksourcedir
+
+# test that chezmoi managed --tree produces tree-like output
+exec chezmoi managed --tree
+cmp stdout golden/stdout
+
+-- golden/stdout --
+.create
+.dir
+  file
+  subdir
+    file
+.empty
+.executable
+.file
+.private
+.readonly
+.remove
+.symlink
+.template
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/noencryption.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/noencryption.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/noencryption.txtar 
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/noencryption.txtar 
2024-04-26 21:51:18.000000000 +0200
@@ -6,7 +6,7 @@
 
 # test that chezmoi apply without encryption fails
 ! exec chezmoi apply --force
-stderr 'no encryption'
+stderr \.encrypted:\sno\sencryption$
 
 -- home/user/.encrypted --
 # contents of .encrypted
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/scriptsdir_unix.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/scriptsdir_unix.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/scriptsdir_unix.txtar      
2024-04-12 13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/scriptsdir_unix.txtar      
2024-04-26 21:51:18.000000000 +0200
@@ -8,13 +8,13 @@
 
 # test that chezmoi apply fails if .chezmoiscripts contains a non-script
 ! exec chezmoi apply
-stderr 'not a script'
+stderr ${CHEZMOISOURCEDIR@R}/\.chezmoiscripts/dot_file:\snot\sa\sscript$
 
 chhome home3/user
 
 # test that chezmoi apply fails if .chezmoiscripts contains duplicate targets
 ! exec chezmoi apply
-stderr 'inconsistent state'
+stderr \.chezmoiscripts/script\.sh:\sinconsistent\sstate
 
 chhome home4/user
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/chezmoi-2.47.4/internal/cmd/testdata/scripts/unmanagedtree.txtar 
new/chezmoi-2.48.0/internal/cmd/testdata/scripts/unmanagedtree.txtar
--- old/chezmoi-2.47.4/internal/cmd/testdata/scripts/unmanagedtree.txtar        
1970-01-01 01:00:00.000000000 +0100
+++ new/chezmoi-2.48.0/internal/cmd/testdata/scripts/unmanagedtree.txtar        
2024-04-26 21:51:18.000000000 +0200
@@ -0,0 +1,12 @@
+# test that chezmoi unmanaged --tree produces tree-like output
+exec chezmoi unmanaged --tree
+cmp stdout golden/stdout
+
+-- golden/stdout --
+.dir
+  file
+  subdir
+.local
+-- home/user/.dir/file --
+-- home/user/.dir/subdir/file --
+-- home/user/.local/share/chezmoi/dot_dir/.keep --
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/unmanagedcmd.go 
new/chezmoi-2.48.0/internal/cmd/unmanagedcmd.go
--- old/chezmoi-2.47.4/internal/cmd/unmanagedcmd.go     2024-04-12 
13:51:15.000000000 +0200
+++ new/chezmoi-2.48.0/internal/cmd/unmanagedcmd.go     2024-04-26 
21:51:18.000000000 +0200
@@ -4,7 +4,6 @@
        "fmt"
        "io/fs"
        "sort"
-       "strings"
 
        "github.com/spf13/cobra"
 
@@ -14,6 +13,7 @@
 
 type unmanagedCmdConfig struct {
        pathStyle chezmoi.PathStyle
+       tree      bool
 }
 
 func (c *Config) newUnmanagedCmd() *cobra.Command {
@@ -28,6 +28,7 @@
        }
 
        unmanagedCmd.Flags().VarP(&c.unmanaged.pathStyle, "path-style", "p", 
"Path style")
+       unmanagedCmd.Flags().BoolVarP(&c.unmanaged.tree, "tree", "t", 
c.unmanaged.tree, "Print paths as a tree")
 
        return unmanagedCmd
 }
@@ -93,16 +94,18 @@
                }
        }
 
-       builder := strings.Builder{}
-       sortedRelPaths := chezmoi.RelPaths(unmanagedRelPaths.Elements())
-       sort.Sort(sortedRelPaths)
-       for _, relPath := range sortedRelPaths {
-               switch c.unmanaged.pathStyle {
-               case chezmoi.PathStyleAbsolute:
-                       fmt.Fprintln(&builder, c.DestDirAbsPath.Join(relPath))
-               case chezmoi.PathStyleRelative:
-                       fmt.Fprintln(&builder, relPath)
+       paths := make([]fmt.Stringer, 0, len(unmanagedRelPaths.Elements()))
+       for relPath := range unmanagedRelPaths {
+               var path fmt.Stringer
+               if c.unmanaged.pathStyle == chezmoi.PathStyleAbsolute {
+                       path = c.DestDirAbsPath.Join(relPath)
+               } else {
+                       path = relPath
                }
+               paths = append(paths, path)
        }
-       return c.writeOutputString(builder.String())
+
+       return c.writePaths(stringersToStrings(paths), writePathsOptions{
+               tree: c.unmanaged.tree,
+       })
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/chezmoi-2.47.4/internal/cmd/util.go 
new/chezmoi-2.48.0/internal/cmd/util.go
--- old/chezmoi-2.47.4/internal/cmd/util.go     2024-04-12 13:51:15.000000000 
+0200
+++ new/chezmoi-2.48.0/internal/cmd/util.go     2024-04-26 21:51:18.000000000 
+0200
@@ -1,6 +1,7 @@
 package cmd
 
 import (
+       "fmt"
        "strings"
        "unicode"
 
@@ -107,6 +108,15 @@
        return singular + "s"
 }
 
+// stringersToStrings converts a slice of fmt.Stringers to a list of strings.
+func stringersToStrings[T fmt.Stringer](ss []T) []string {
+       result := make([]string, 0, len(ss))
+       for _, s := range ss {
+               result = append(result, s.String())
+       }
+       return result
+}
+
 // titleFirst returns s with its first rune converted to title case.
 func titleFirst(s string) string {
        if s == "" {
@@ -130,7 +140,7 @@
        return strings.Join(words, "")
 }
 
-// upperSnakeCaseToCamelCaseKeys returns m with all keys converted from
+// upperSnakeCaseToCamelCaseMap returns m with all keys converted from
 // UPPER_SNAKE_CASE to camelCase.
 func upperSnakeCaseToCamelCaseMap[V any](m map[string]V) map[string]V {
        result := make(map[string]V)

++++++ chezmoi.obsinfo ++++++
--- /var/tmp/diff_new_pack.gGnN0Q/_old  2024-05-01 14:57:12.027537165 +0200
+++ /var/tmp/diff_new_pack.gGnN0Q/_new  2024-05-01 14:57:12.031537311 +0200
@@ -1,5 +1,5 @@
 name: chezmoi
-version: 2.47.4
-mtime: 1712922675
-commit: d6ad485c86aa6501f5a7754ccba2a2b03d46c1a2
+version: 2.48.0
+mtime: 1714161078
+commit: c758a1c57fb6084631736a7dda5ac0aaeeffa946
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/chezmoi/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.chezmoi.new.1880/vendor.tar.gz differ: char 5, line 
1

Reply via email to