From 3d1825b12c88bbb18cc5beb3a7b1f36f6acca0a7 Mon Sep 17 00:00:00 2001 From: kevsmir02 Date: Thu, 1 Oct 2026 13:42:52 +0800 Subject: [PATCH] [Fix] Changing a site's branch no longer checks out the live release under modern deployment With modern deployment enabled, a site's path is `/current`, which points at the active release. UpdateBranch ran `git fetch origin` and `git checkout -f ` in that path, so saving a new branch swapped the code of the live release in place, with no build, no pre-flight and no migrations. The forced checkout also restored tracked files over the shared resources, replacing the `storage` symlink with a plain directory in that release. The branch is now switched in `/source`, the checkout that holds the shared resources and is pulled on every deployment. The next deployment clones the new branch into a fresh release as usual. Sites without modern deployment keep their current behaviour. --- app/Actions/Site/UpdateBranch.php | 8 ++++++-- app/SSH/OS/Git.php | 8 ++++---- tests/Feature/SitesTest.php | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/app/Actions/Site/UpdateBranch.php b/app/Actions/Site/UpdateBranch.php index 0a13ea062..ee23de8c6 100755 --- a/app/Actions/Site/UpdateBranch.php +++ b/app/Actions/Site/UpdateBranch.php @@ -10,6 +10,9 @@ class UpdateBranch { /** + * With modern deployment the site path is the live release, so the branch + * is switched in the source checkout and the next deployment clones it. + * * @param array $input * * @throws SSHError @@ -21,8 +24,9 @@ public function update(Site $site, array $input): void ])->validate(); $site->branch = $input['branch']; - app(Git::class)->fetchOrigin($site); - app(Git::class)->checkout($site); + $path = $site->modernDeploymentEnabled() ? $site->basePath().'/source' : null; + app(Git::class)->fetchOrigin($site, $path); + app(Git::class)->checkout($site, $path); $site->save(); } } diff --git a/app/SSH/OS/Git.php b/app/SSH/OS/Git.php index f374be763..5e12208a8 100644 --- a/app/SSH/OS/Git.php +++ b/app/SSH/OS/Git.php @@ -38,11 +38,11 @@ public function clone(Site $site, ?string $path = null): void /** * @throws SSHError */ - public function checkout(Site $site): void + public function checkout(Site $site, ?string $path = null): void { $site->server->ssh($site->user)->exec( view('ssh.git.checkout', [ - 'path' => escapeshellarg((string) $site->path), + 'path' => escapeshellarg((string) ($path ?? $site->path)), 'branch' => escapeshellarg((string) $site->branch), ]), 'checkout-branch', @@ -53,7 +53,7 @@ public function checkout(Site $site): void /** * @throws SSHError */ - public function fetchOrigin(Site $site): void + public function fetchOrigin(Site $site, ?string $path = null): void { $ssh = $site->server->ssh($site->user); @@ -63,7 +63,7 @@ public function fetchOrigin(Site $site): void $ssh->exec( view('ssh.git.fetch-origin', [ - 'path' => escapeshellarg((string) $site->path), + 'path' => escapeshellarg((string) ($path ?? $site->path)), ]), 'fetch-origin', $site->id diff --git a/tests/Feature/SitesTest.php b/tests/Feature/SitesTest.php index a9251034d..4723463e3 100644 --- a/tests/Feature/SitesTest.php +++ b/tests/Feature/SitesTest.php @@ -559,6 +559,35 @@ SSH::assertExecutedContains("git checkout -f 'master'"); }); +test('change branch with modern deployment checks out the source, not the live release', function () { + SSH::fake(); + + $this->site->update([ + 'path' => '/home/vito/vito.test/current', + 'type_data' => [ + 'modern_deployment' => true, + 'modern_deployment_history' => 10, + 'modern_deployment_shared_resources' => ['.env', 'storage'], + ], + ]); + + $this->actingAs($this->user); + + $this->patch(route('site-settings.update-branch', [ + 'server' => $this->server->id, + 'site' => $this->site, + ]), [ + 'branch' => 'develop', + ]) + ->assertSessionDoesntHaveErrors(); + + expect($this->site->refresh()->branch)->toEqual('develop'); + + SSH::assertExecutedContains("cd '/home/vito/vito.test/source'"); + SSH::assertExecutedContains("git checkout -f 'develop'"); + SSH::assertNotExecutedContains("cd '/home/vito/vito.test/current'"); +}); + test('update web directory', function () { SSH::fake();