Subject: bug#79024: 31.0.50; Multiple working trees support for VC

From: Eli Zaretskii <[email-masked]>
Date: Sun, 27 Jul 2025 12:17:11 +0300

> From: Sean Whitton <[email-masked]>
> Cc: [email-masked],  [email-masked]
> Date: Sun, 27 Jul 2025 09:42:31 +0100
> 
> Hello,
> 
> On Sat 26 Jul 2025 at 04:49pm +03, Eli Zaretskii wrote:
> 
> > I don't understand the question.  The test files are compiled when the
> > test is run, if the .elc file is outdated.
> 
> But if you just do 'make' in the root of the source tree, they're not
> recompiled, right?  Otherwise I would have seen and fixed the warning.

"make" builds Emacs, but doesn't run the test suite.  This is similar
to what other projects do: to run the test suite, you need to say
"make check".

Since the entire test suite takes quite some time to run, I usually
run only the relevant test(s), like this:

  make -C test lisp/some-tests

(assuming the test file is test/lisp/some-tests.el).  Some changes
need to run more than one test file.

> Is that deliberate?  Even if we don't run the tests as part of the
> build, we could compile them, and therefore be more likely to notice
> problems like this.

I'm not sure it would be TRT to have "make" do anything in the test
suite, no.

> >   Test vc-test-git07-other-working-trees condition:
> >       (file-missing "Opening output file" "No such file or directory"
> > 		    "/nonexistent/.emacs.d/projects.eld")
> >      FAILED  24/56  vc-test-git07-other-working-trees (0.120713 sec) at lisp/vc/vc
> >
> > Maybe this fails because my Git is very old?  (It does support
> > worktrees, though.)  If you could show a series of shell commands this
> > test invokes, I could perhaps run them from the shell and see what
> > happens.

Paul now posted an almost identical failure, so I don't think this has
anything to do with my Git version.

> > OK, did that (perhaps this should be in the comments to the test?).
> > But the test is still skipped.  I think I understand why: we run the
> > test suite with a bogus HOME directory, so the real ~/.hgrc is not
> > used, and "hg share" says "unknown command".  I see the same on
> > GNU/Linux, so this is not specific to Windows.  Does the test work for
> > you?
> 
> Thanks, I didn't see these issues previously because I had been running
> the tests only interactively.
> Now rectified that and sorted out enabling the share extension for hg
> and fixed the /nonexistent/.emacs.d/project.eld issue.
> 
> The tests still do not pass because after executing the line
> 
>     ;; Test `move-working-tree'.
>     (vc-move-working-tree backend second third)
> 
> there is then an error, at some point:
> 
>     error in process sentinel: Setting current directory: No such file or directory, /tmp/vc-testfFGMCu/second/
> 
> I haven't yet been able to determine what is causing this process
> sentinel left behind in the 'second' working tree (that the test renames
> out of existence).

That's not what I see here.  The Git test still fails in the same way:

  Registering (foo)...
  Registering (foo)... done
  Mark set
  Press C-c C-c when you are done editing.
  Enter a change comment.  Type C-c C-c when done
  Checking in foo...
  Test vc-test-git07-other-working-trees backtrace:
    signal(error ("Failed (status 128): git --no-pager commit -F c:/User
    error("Failed (%s): %s" "status 128" "git --no-pager commit -F c:/Us
    vc-do-command("*vc*" 0 "git" ("foo") "--no-pager" "commit" "-F" "c:/
    apply(vc-do-command "*vc*" 0 "git" ("foo") "--no-pager" ("commit" "-
    vc-git-command(nil 0 ("foo") "commit" "-F" "c:/Users/EliZ/AppData/Lo
    apply(vc-git-command nil 0 ("foo") ("commit" "-F" "c:/Users/EliZ/App
    vc-git-checkin(("foo") #("Summary: Testing other working trees\n" 0
    apply(vc-git-checkin (("foo") #("Summary: Testing other working tree
    vc-call-backend(Git checkin ("foo") #("Summary: Testing other workin
    #f(compiled-function (backend rev patch-string files comment) #<byte
    #f(compiled-function (files comment) #<bytecode 0x123ed980b51f4b48>)
    vc-finish-logentry()
    funcall-interactively(vc-finish-logentry)
    call-interactively(vc-finish-logentry)
    log-edit-done()
    (let (vc-async-checkin) (log-edit-done))
    (save-current-buffer (set-buffer (find-file-noselect tmp-name)) (vc-
    (let* ((first (file-name-as-directory (expand-file-name "first" defa
    (progn (add-hook 'vc-test--cleanup-hook (let ((dir default-directory
    (unwind-protect (progn (add-hook 'vc-test--cleanup-hook (let ((dir d
    (let ((vc-handled-backends (list backend)) (default-directory (file-
    (progn (let ((vc-handled-backends (list backend)) (default-directory
    (unwind-protect (progn (let ((vc-handled-backends (list backend)) (d
    (let* ((coding-system-for-write nil) (temp-file (file-name-as-direct
    vc-test--other-working-trees(Git)
    (let ((vc-hg-global-switches (cons "--config=extensions.share=" vc-h
    #f(lambda () :dynbind (let ((value-478 (gensym "ert-form-evaluation-
    #f(compiled-function () #<bytecode 0x7b91ca0e300b608>)()
    handler-bind-1(#f(compiled-function () #<bytecode 0x7b91ca0e300b608>
    ert--run-test-internal(#s(ert--test-execution-info :test ... :result
    ert-run-test(#s(ert-test :name vc-test-git07-other-working-trees :do
    ert-run-or-rerun-test(#s(ert--stats :selector ... :tests ... :test-m
    ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil
    ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp))))
    ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco
    eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n
    command-line-1(("-L" ";." "-l" "ert" "--eval" "(setq treesit-extra-l
    command-line()
    normal-top-level()
  Test vc-test-git07-other-working-trees condition:
      (error
       "Failed (status 128): git --no-pager commit -F c:/Users/EliZ/AppData/Local/Temp/git-msgexkgWo --only -- foo")
     FAILED  24/56  vc-test-git07-other-working-trees (0.357570 sec) at lisp/vc/vc-tests/vc-tests.el:1

And the corresponding Hg test fails like this:

  Registering (foo)...
  Registering (foo)... done
  Mark set
  Press C-c C-c when you are done editing.
  Enter a change comment.  Type C-c C-c when done
  Checking in foo...
  Test vc-test-hg07-other-working-trees backtrace:
    signal(error ("Failed (status 255): hg --config ui.report_untrusted=
    error("Failed (%s): %s" "status 255" "hg --config ui.report_untruste
    vc-do-command("*vc*" 0 "hg" ("foo") "--config" "ui.report_untrusted=
    apply(vc-do-command ("*vc*" 0 "hg" ("foo") "--config" "ui.report_unt
    vc-hg--command-1(vc-do-command ("*vc*" 0 "hg" ("foo")) ("commit" "-m
    vc-hg-command(nil 0 ("foo") "commit" "-m" "Testing other working tre
    apply(vc-hg-command nil 0 ("foo") ("commit" "-m" "Testing other work
    vc-hg-checkin(("foo") #("Summary: Testing other working trees\nTesti
    apply(vc-hg-checkin (("foo") #("Summary: Testing other working trees
    vc-call-backend(Hg checkin ("foo") #("Summary: Testing other working
    #f(compiled-function (backend rev patch-string files comment) #<byte
    #f(compiled-function (files comment) #<bytecode 0x123ed980b54f4b48>)
    vc-finish-logentry()
    funcall-interactively(vc-finish-logentry)
    call-interactively(vc-finish-logentry)
    log-edit-done()
    (let (vc-async-checkin) (log-edit-done))
    (save-current-buffer (set-buffer (find-file-noselect tmp-name)) (vc-
    (let* ((first (file-name-as-directory (expand-file-name "first" defa
    (progn (add-hook 'vc-test--cleanup-hook (let ((dir default-directory
    (unwind-protect (progn (add-hook 'vc-test--cleanup-hook (let ((dir d
    (let ((vc-handled-backends (list backend)) (default-directory (file-
    (progn (let ((vc-handled-backends (list backend)) (default-directory
    (unwind-protect (progn (let ((vc-handled-backends (list backend)) (d
    (let* ((coding-system-for-write nil) (temp-file (file-name-as-direct
    vc-test--other-working-trees(Hg)
    (let ((vc-hg-global-switches (cons "--config=extensions.share=" vc-h
    #f(lambda () :dynbind (let ((value-511 (gensym "ert-form-evaluation-
    #f(compiled-function () #<bytecode 0x7b91ca0e300b608>)()
    handler-bind-1(#f(compiled-function () #<bytecode 0x7b91ca0e300b608>
    ert--run-test-internal(#s(ert--test-execution-info :test ... :result
    ert-run-test(#s(ert-test :name vc-test-hg07-other-working-trees :doc
    ert-run-or-rerun-test(#s(ert--stats :selector ... :tests ... :test-m
    ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil
    ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp))))
    ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco
    eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n
    command-line-1(("-L" ";." "-l" "ert" "--eval" "(setq treesit-extra-l
    command-line()
    normal-top-level()
  Test vc-test-hg07-other-working-trees condition:
      (error
       "Failed (status 255): hg --config ui.report_untrusted=0 --config=extensions.share= commit -m Testing other working trees\n\nTesting other working trees\n foo")
     FAILED  32/56  vc-test-hg07-other-working-trees (0.424025 sec) at lisp/vc/vc-tests/vc-tests.el:1

I think that's because MS-Windows doesn't support command lines with
embedded newlines (see the -m switch above), so we need to use the
same trick with a temporary file as we do in Git.

On GNU/Linux, the Git test fails like this:

  Checking in foo...
  Checking in foo...done
  Test vc-test-git07-other-working-trees backtrace:
    signal(error ("Failed (status 129): git --no-pager worktree list --p
    apply(signal (error ("Failed (status 129): git --no-pager worktree l
    (setq value-239 (apply fn-237 args-238))
    (unwind-protect (setq value-239 (apply fn-237 args-238)) (setq form-
    (if (unwind-protect (setq value-239 (apply fn-237 args-238)) (setq f
    (let (form-description-241) (if (unwind-protect (setq value-239 (app
    (let ((value-239 'ert-form-evaluation-aborted-240)) (let (form-descr
    (let* ((fn-237 #'equal) (args-238 (condition-case err (list (list se
    (save-current-buffer (set-buffer (find-file-noselect tmp-name)) (let
    (let* ((first (file-name-as-directory (expand-file-name "first" defa
    (progn (add-hook 'vc-test--cleanup-hook (let ((dir default-directory
    (unwind-protect (progn (add-hook 'vc-test--cleanup-hook (let ((dir d
    (let ((vc-handled-backends (list backend)) (default-directory (file-
    (progn (let ((vc-handled-backends (list backend)) (default-directory
    (unwind-protect (progn (let ((vc-handled-backends (list backend)) (d
    (let* ((coding-system-for-write nil) (temp-file (file-name-as-direct
    vc-test--other-working-trees(Git)
    (let ((vc-hg-global-switches (cons "--config=extensions.share=" vc-h
    #f(lambda () :dynbind (let ((value-478 (gensym "ert-form-evaluation-
    #f(compiled-function () #<bytecode 0x6a0ab5e05cce532>)()
    handler-bind-1(#f(compiled-function () #<bytecode 0x6a0ab5e05cce532>
    ert--run-test-internal(#s(ert--test-execution-info :test #s(ert-test
    ert-run-test(#s(ert-test :name vc-test-git07-other-working-trees :do
    ert-run-or-rerun-test(#s(ert--stats :selector ... :tests ... :test-m
    ert-run-tests((not (or (tag :unstable) (tag :nativecomp))) #f(compil
    ert-run-tests-batch((not (or (tag :unstable) (tag :nativecomp))))
    ert-run-tests-batch-and-exit((not (or (tag :unstable) (tag :nativeco
    eval((ert-run-tests-batch-and-exit '(not (or (tag :unstable) (tag :n
    command-line-1(("-L" ":." "-l" "ert" "--eval" "(setq treesit-extra-l
    command-line()
    normal-top-level()
  Test vc-test-git07-other-working-trees condition:
      (error
       "Failed (status 129): git --no-pager worktree list --porcelain -z")
     FAILED  24/56  vc-test-git07-other-working-trees (0.191993 sec) at lisp/vc/vc-tests/vc-tests.el:1

And hg07-other-working-trees indeed fails like you say:

  Checking in foo...
  Checking in foo...done
  error in process sentinel: Setting current directory: No such file or directory, /tmp/vc-testC5QRAj/second/