&1'; exec($cmd, $lines, $code); return ['code' => $code, 'output' => trim(implode("\n", $lines))]; } function git_output(array $args): string { return git_run($args)['output']; } function git_local_branches(): array { $out = git_output(['branch', '--list', '--no-color']); $branches = array_values(array_filter(array_map(function ($line) { return trim(ltrim(trim($line), '*')); }, explode("\n", $out)), fn($v) => $v !== '')); sort($branches, SORT_NATURAL | SORT_FLAG_CASE); return $branches; } function git_remote_branches(): array { $out = git_output(['branch', '-r', '--no-color']); $branches = array_values(array_filter(array_map('trim', explode("\n", $out)), function ($branch) { return $branch !== '' && !str_contains($branch, ' -> ') && !str_ends_with($branch, '/HEAD'); })); sort($branches, SORT_NATURAL | SORT_FLAG_CASE); return $branches; } function branch_from_remote(string $remoteBranch): string { $parts = explode('/', $remoteBranch, 2); return $parts[1] ?? $remoteBranch; } function git_last_commit(): string { $out = git_output(['log', '-1', '--oneline', '--decorate=short']); return $out !== '' ? $out : '(unknown)'; } function git_current_branch(): string { return git_output(['rev-parse', '--abbrev-ref', 'HEAD']); } function git_upstream_for_branch(string $branch): ?string { $result = git_run(['rev-parse', '--abbrev-ref', $branch . '@{upstream}']); return $result['code'] === 0 && $result['output'] !== '' ? $result['output'] : null; } function git_is_ancestor(string $ancestor, string $descendant): bool { return git_run(['merge-base', '--is-ancestor', $ancestor, $descendant])['code'] === 0; } function git_pull_all_tracked_branches(): array { $lines = []; $exitCode = 0; $fetch = git_run(['fetch', '--all', '--prune']); $lines[] = '$ git fetch --all --prune'; $lines[] = $fetch['output'] ?: '(no output)'; if ($fetch['code'] !== 0) return ['code' => $fetch['code'], 'output' => implode("\n", $lines)]; $current = git_current_branch(); foreach (git_local_branches() as $branch) { $upstream = git_upstream_for_branch($branch); if ($upstream === null) { $lines[] = ''; $lines[] = $branch . ': no upstream configured, skipped'; continue; } $lines[] = ''; $lines[] = $branch . ' <- ' . $upstream; if ($branch === $current) { $pull = git_run(['merge', '--ff-only', $upstream]); $lines[] = '$ git merge --ff-only ' . $upstream; $lines[] = $pull['output'] ?: '(no output)'; if ($pull['code'] !== 0) $exitCode = $pull['code']; continue; } if (git_is_ancestor($branch, $upstream)) { $update = git_run(['branch', '-f', $branch, $upstream]); $lines[] = '$ git branch -f ' . $branch . ' ' . $upstream; $lines[] = $update['output'] ?: '(fast-forwarded)'; if ($update['code'] !== 0) $exitCode = $update['code']; } elseif (git_is_ancestor($upstream, $branch)) { $lines[] = 'already up to date or ahead'; } else { $lines[] = 'diverged, skipped'; if ($exitCode === 0) $exitCode = 1; } } return ['code' => $exitCode, 'output' => implode("\n", $lines)]; } function resolve_selected_branch_ref(string $ref, array $localBranches, array $remoteBranches, bool $preferLocalForRemote): ?string { if (str_starts_with($ref, 'local:')) { $branch = substr($ref, 6); return in_array($branch, $localBranches, true) ? $branch : null; } if (str_starts_with($ref, 'remote:')) { $remoteBranch = substr($ref, 7); if (!in_array($remoteBranch, $remoteBranches, true)) return null; $localBranch = branch_from_remote($remoteBranch); return $preferLocalForRemote && in_array($localBranch, $localBranches, true) ? $localBranch : $remoteBranch; } return null; } $message = null; $result = null; if ($allowed && $_SERVER['REQUEST_METHOD'] === 'POST') { if (!hash_equals($csrf, $_POST['csrf'] ?? '')) { http_response_code(400); $message = 'Invalid CSRF token.'; } else { $action = $_POST['action'] ?? ''; if ($action === 'fetch') { $result = git_run(['fetch', '--all', '--prune']); $message = 'git fetch --all --prune'; } elseif ($action === 'pull') { $result = git_pull_all_tracked_branches(); $message = 'pull all tracked branches'; } elseif ($action === 'push') { $result = git_run(['push']); $message = 'git push'; } elseif ($action === 'commit') { $commitMessage = trim((string)($_POST['message'] ?? '')); if ($commitMessage === '') { $result = ['code' => 1, 'output' => 'Commit message is required.']; } else { $add = git_run(['add', '-A']); if ($add['code'] !== 0) { $result = $add; $message = 'git add -A'; } else { $result = git_run(['commit', '-m', $commitMessage]); $message = 'git commit'; } } } elseif ($action === 'merge') { $ref = trim((string)($_POST['merge_branch'] ?? '')); git_run(['fetch', '--all', '--prune']); $localBranches = git_local_branches(); $remoteBranches = git_remote_branches(); $branch = resolve_selected_branch_ref($ref, $localBranches, $remoteBranches, false); if ($branch === null) { $result = ['code' => 1, 'output' => 'Unknown branch selection.']; } else { $result = git_run(['merge', '--no-edit', $branch]); $message = 'git merge --no-edit ' . $branch; } } elseif ($action === 'switch') { $ref = trim((string)($_POST['branch'] ?? '')); $localBranches = git_local_branches(); $remoteBranches = git_remote_branches(); if (str_starts_with($ref, 'remote:')) { $remoteBranch = substr($ref, 7); if (!in_array($remoteBranch, $remoteBranches, true)) { $result = ['code' => 1, 'output' => 'Unknown remote branch: ' . $remoteBranch]; } else { $branch = branch_from_remote($remoteBranch); if (in_array($branch, $localBranches, true)) { $result = git_run(['switch', $branch]); $message = 'git switch ' . $branch; } else { $result = git_run(['switch', '--track', $remoteBranch]); $message = 'git switch --track ' . $remoteBranch; } } } else { $branch = resolve_selected_branch_ref($ref, $localBranches, $remoteBranches, true); if ($branch === null) { $result = ['code' => 1, 'output' => 'Unknown branch selection.']; } else { $result = git_run(['switch', $branch]); $message = 'git switch ' . $branch; } } } } } $currentBranch = ''; $status = ''; $branches = []; $remoteBranches = []; $lastCommit = ''; if ($allowed) { $currentBranch = git_current_branch(); $status = git_output(['status', '-sb']); $branches = git_local_branches(); $remoteBranches = git_remote_branches(); $lastCommit = git_last_commit(); } ?> Admin · FFLogs Report Viewer
User nicht verfügbar

Ich konnte deine FFLogs User-ID nicht laden.

Kein Zugriff

Deine FFLogs User-ID ist . Füge diese ID in deiner .env zu ADMIN_USER_IDS hinzu, um diese Seite freizuschalten.

Git Admin
Branch:
Last commit:
Aktionen
Status
· Exit