Commits vergleichen
2 Commits
8da6ad83f0
...
dad07c7879
| Autor | SHA1 | Datum | |
|---|---|---|---|
| dad07c7879 | |||
| 627beb1353 |
136
CHANGELOG.txt
136
CHANGELOG.txt
@ -1,6 +1,142 @@
|
||||
TASKMATE - CHANGELOG
|
||||
====================
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea: Commit-Autor = eingeloggter Benutzer
|
||||
================================================================================
|
||||
|
||||
BUGFIX: COMMIT-AUTOR WAR FALSCH
|
||||
--------------------------------------------------------------------------------
|
||||
- Problem: Bei Commits wurde "Claude Projekt Manager" als Autor angezeigt
|
||||
(aus der lokalen Git-Konfiguration des Benutzers)
|
||||
- Lösung: Der eingeloggte TaskMate-Benutzer wird jetzt als Autor verwendet
|
||||
|
||||
ÄNDERUNGEN
|
||||
--------------------------------------------------------------------------------
|
||||
- backend/services/gitService.js: commit() akzeptiert jetzt author-Parameter
|
||||
* Verwendet git commit --author="Name <email>" -m "Nachricht"
|
||||
* Email wird generiert: benutzername@taskmate.local
|
||||
- backend/routes/git.js: Commit-Route übergibt req.user als Autor
|
||||
* Verwendet display_name oder username als Autorname
|
||||
- frontend/sw.js: Cache-Version auf 124 erhöht
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea: Branch umbenennen + UI-Aufräumung
|
||||
================================================================================
|
||||
|
||||
FEATURE: LOKALEN BRANCH UMBENENNEN
|
||||
--------------------------------------------------------------------------------
|
||||
- Neuer Stift-Button neben dem Branch-Dropdown
|
||||
- Modal zum Umbenennen des aktuellen Branches (z.B. "master" → "main")
|
||||
- Backend-Endpoint: POST /api/git/rename-branch/:projectId
|
||||
|
||||
UI-AUFRÄUMUNG
|
||||
--------------------------------------------------------------------------------
|
||||
- "Ahead/Behind" Anzeige entfernt (war verwirrend)
|
||||
- Branch-Bereich aufgeräumt mit Rename-Button
|
||||
|
||||
ÄNDERUNGEN
|
||||
--------------------------------------------------------------------------------
|
||||
- frontend/index.html:
|
||||
* Branch-Select-Group mit Rename-Button
|
||||
* Neues Rename-Branch-Modal
|
||||
* Ahead/Behind entfernt
|
||||
- frontend/css/gitea.css:
|
||||
* .branch-select-group, .btn-small, .btn-icon Styles
|
||||
* .status-badge.ahead und #git-ahead-behind entfernt
|
||||
- frontend/js/gitea.js:
|
||||
* openRenameBranchModal(), executeRenameBranch() hinzugefügt
|
||||
* Ahead/Behind-Rendering entfernt
|
||||
- frontend/js/api.js: gitRenameBranch() hinzugefügt
|
||||
- backend/services/gitService.js: renameBranch() Funktion
|
||||
- backend/routes/git.js: rename-branch Endpoint
|
||||
- frontend/sw.js: Cache-Version auf 123 erhöht
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea: Force-Push Option
|
||||
================================================================================
|
||||
|
||||
FEATURE: FORCE-PUSH UM REMOTE ZU ÜBERSCHREIBEN
|
||||
--------------------------------------------------------------------------------
|
||||
- Problem: Push auf Remote-Branch mit unterschiedlicher Historie schlug fehl
|
||||
(z.B. wenn Gitea eine README erstellt hat und man master→main pushen will)
|
||||
- Lösung: Force-Push Option im Push-Modal hinzugefügt
|
||||
|
||||
ÄNDERUNGEN
|
||||
--------------------------------------------------------------------------------
|
||||
- frontend/index.html: Checkbox "Force Push (Remote überschreiben)" im Push-Modal
|
||||
- frontend/css/gitea.css: .form-hint.warning Style für Warnung
|
||||
- frontend/js/gitea.js: Force-Flag wird an API übergeben
|
||||
- frontend/js/api.js: gitInitPush() akzeptiert force Parameter
|
||||
- backend/services/gitService.js: pushWithUpstream() mit --force Flag
|
||||
- backend/routes/git.js: init-push Endpoint akzeptiert force Parameter
|
||||
- frontend/sw.js: Cache-Version auf 122 erhöht
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea: Bugfix Ziel-Branch Auswahl
|
||||
================================================================================
|
||||
|
||||
BUGFIX: PUSH MIT ZIEL-BRANCH FUNKTIONIERTE NICHT
|
||||
--------------------------------------------------------------------------------
|
||||
- Problem: Bei Auswahl eines anderen Ziel-Branches (z.B. "main" statt "master")
|
||||
wurde trotzdem der reguläre Push verwendet, der die Auswahl ignorierte
|
||||
- Ursache: executePush() versuchte immer zuerst den normalen Push, der den
|
||||
bestehenden Upstream verwendet, nicht den ausgewählten Target-Branch
|
||||
|
||||
LÖSUNG
|
||||
--------------------------------------------------------------------------------
|
||||
- frontend/js/gitea.js: executePush() Logik korrigiert
|
||||
* Wenn Ziel-Branch != lokaler Branch → verwendet immer init-push mit Mapping
|
||||
* Nur bei gleichem Branch-Namen → normaler Push mit Fallback
|
||||
* Zeigt Info-Toast mit "Push von X nach Y"
|
||||
- frontend/sw.js: Cache-Version auf 121 erhöht
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea: Ziel-Branch Auswahl beim Push
|
||||
================================================================================
|
||||
|
||||
FEATURE: ZIEL-BRANCH AUSWAHL BEIM PUSH
|
||||
--------------------------------------------------------------------------------
|
||||
- Neues Push-Modal mit Branch-Auswahl vor dem Push
|
||||
- Benutzer können jetzt wählen auf welchen Remote-Branch gepusht wird
|
||||
- Z.B. lokaler Branch "master" kann als "main" auf Gitea gepusht werden
|
||||
- Auswahl: "Gleicher Name wie lokal", "main", "master", "develop"
|
||||
|
||||
ÄNDERUNGEN
|
||||
--------------------------------------------------------------------------------
|
||||
- backend/services/gitService.js: pushWithUpstream() unterstützt jetzt targetBranch
|
||||
* Branch-Mapping: `git push -u origin master:main` möglich
|
||||
* Gibt sowohl localBranch als auch remoteBranch im Ergebnis zurück
|
||||
- backend/routes/git.js: init-push Endpoint akzeptiert targetBranch Parameter
|
||||
- frontend/js/api.js: gitInitPush() mit targetBranch Parameter
|
||||
- frontend/js/gitea.js:
|
||||
* Push-Button öffnet jetzt Modal statt direkt zu pushen
|
||||
* Neue Methoden: openPushModal(), executePush()
|
||||
- frontend/index.html: Neues Push-Modal mit Branch-Auswahl
|
||||
- frontend/css/gitea.css: .form-static-value Style hinzugefügt
|
||||
- frontend/sw.js: Cache-Version auf 120 erhöht
|
||||
|
||||
================================================================================
|
||||
29.12.2025 - Gitea-Integration Bugfix: Branch-Mismatch
|
||||
================================================================================
|
||||
|
||||
BUGFIX: DEFAULT-BRANCH MISMATCH ZWISCHEN GIT UND GITEA
|
||||
--------------------------------------------------------------------------------
|
||||
- Problem: Dateien wurden nach "master" gepusht, aber Gitea zeigte "main"
|
||||
- Benutzer sahen nur die auto-generierte README statt ihrer gepushten Dateien
|
||||
- Ursache: Lokaler Branch "master" != Gitea Default-Branch "main"
|
||||
|
||||
LÖSUNG
|
||||
--------------------------------------------------------------------------------
|
||||
- backend/services/giteaService.js: NEU - updateRepository() Funktion
|
||||
* Erlaubt das Ändern des Default-Branch über Gitea PATCH API
|
||||
* Unterstützt auch Beschreibung und Private-Status Änderungen
|
||||
- backend/services/gitService.js: pushWithUpstream() gibt jetzt Branch-Namen zurück
|
||||
- backend/routes/git.js: init-push Endpoint aktualisiert Default-Branch automatisch
|
||||
* Nach erfolgreichem Push wird Gitea's Default-Branch auf den gepushten Branch gesetzt
|
||||
* Owner/Repo wird automatisch aus der Repository-URL extrahiert
|
||||
- frontend/sw.js: Cache-Version auf 119 erhöht
|
||||
|
||||
================================================================================
|
||||
28.12.2025 - Gitea-Integration
|
||||
================================================================================
|
||||
|
||||
179
GITEA_INTEGRATION_STATUS.md
Normale Datei
179
GITEA_INTEGRATION_STATUS.md
Normale Datei
@ -0,0 +1,179 @@
|
||||
# Gitea-Integration Status - TaskMate
|
||||
|
||||
**Datum:** 29.12.2024
|
||||
**Status:** Vollständig implementiert - Bugfix angewendet
|
||||
|
||||
---
|
||||
|
||||
## Übersicht
|
||||
|
||||
Die Gitea-Integration für TaskMate ist vollständig implementiert. Der kritische Branch-Mismatch Bug wurde behoben - nach einem Push wird der Default-Branch in Gitea automatisch auf den gepushten Branch aktualisiert.
|
||||
|
||||
---
|
||||
|
||||
## Was wurde bereits implementiert
|
||||
|
||||
### Backend (vollständig)
|
||||
|
||||
1. **`backend/server.js`** - Routes registriert:
|
||||
```javascript
|
||||
const gitRoutes = require('./routes/git');
|
||||
const applicationsRoutes = require('./routes/applications');
|
||||
const giteaRoutes = require('./routes/gitea');
|
||||
|
||||
app.use('/api/git', authenticateToken, csrfProtection, gitRoutes);
|
||||
app.use('/api/applications', authenticateToken, csrfProtection, applicationsRoutes);
|
||||
app.use('/api/gitea', authenticateToken, csrfProtection, giteaRoutes);
|
||||
```
|
||||
|
||||
2. **`backend/routes/gitea.js`** - NEU erstellt mit Endpoints:
|
||||
- `GET /test` - Verbindung testen
|
||||
- `GET /repositories` - Alle Repos auflisten
|
||||
- `POST /repositories` - Neues Repo erstellen
|
||||
- `GET /repositories/:owner/:repo` - Repo-Details
|
||||
- `GET /repositories/:owner/:repo/branches` - Branches
|
||||
- `GET /repositories/:owner/:repo/commits` - Commits
|
||||
|
||||
3. **`backend/routes/git.js`** - Erweitert mit:
|
||||
- `POST /set-remote` - Remote setzen
|
||||
- `POST /prepare-for-gitea` - Repository für Gitea vorbereiten
|
||||
|
||||
4. **`backend/services/gitService.js`** - Erweitert mit:
|
||||
- `setRemote()` - Remote-URL setzen
|
||||
- `prepareForGitea()` - Repository für Gitea vorbereiten (remote + initial commit)
|
||||
- `pushWithUpstream()` - Push mit automatischer Branch-Erkennung
|
||||
|
||||
5. **`backend/services/giteaService.js`** - Vorhanden mit:
|
||||
- `listRepositories()` - Organisation-Repositories auflisten
|
||||
- `getRepository()` - Einzelnes Repo abrufen
|
||||
- `createRepository()` - Neues Repo erstellen
|
||||
- `updateRepository()` - Repo-Einstellungen aktualisieren (inkl. default_branch)
|
||||
- `deleteRepository()` - Repo löschen
|
||||
- `testConnection()` - Verbindung testen
|
||||
- `getAuthenticatedCloneUrl()` - Clone-URL mit Token
|
||||
|
||||
6. **`Dockerfile`** - Git-Unterstützung hinzugefügt:
|
||||
```dockerfile
|
||||
RUN apk add --no-cache git
|
||||
RUN git config --system --add safe.directory '*'
|
||||
RUN git config --system user.email "taskmate@local" && \
|
||||
git config --system user.name "TaskMate" && \
|
||||
git config --system init.defaultBranch main
|
||||
```
|
||||
|
||||
### Frontend (vollständig)
|
||||
|
||||
1. **`frontend/js/api.js`** - Erweitert mit allen Gitea/Git API-Methoden
|
||||
|
||||
2. **`frontend/js/gitea.js`** - NEU erstellt:
|
||||
- Kompletter GiteaManager mit allen Funktionen
|
||||
- Konfigurationsansicht
|
||||
- Status-Anzeige
|
||||
- Git-Operationen (Fetch, Pull, Push, Commit)
|
||||
- Commit-Historie
|
||||
- Branch-Wechsel
|
||||
|
||||
3. **`frontend/css/gitea.css`** - NEU erstellt:
|
||||
- Alle Styles für Gitea-Tab
|
||||
|
||||
4. **`frontend/index.html`** - Erweitert:
|
||||
- Gitea-Tab in Navigation
|
||||
- Gitea-View Container
|
||||
- Commit-Modal
|
||||
- Create-Repo-Modal
|
||||
|
||||
5. **`frontend/js/app.js`** - Integriert:
|
||||
- GiteaManager Import
|
||||
- View-Switching für Gitea-Tab
|
||||
|
||||
6. **`frontend/sw.js`** - Cache-Version erhöht
|
||||
|
||||
---
|
||||
|
||||
## Der gelöste Bug: Branch-Mismatch
|
||||
|
||||
### Problem (GELÖST)
|
||||
- 146 Dateien wurden erfolgreich nach Gitea gepusht
|
||||
- Die Dateien landeten im Branch `master`
|
||||
- Gitea zeigte aber `main` als Standard-Branch an
|
||||
- Benutzer sahen nur die auto-generierte README statt ihrer Dateien
|
||||
|
||||
### Ursache
|
||||
1. Gitea erstellt Repositories mit `default_branch: 'main'` (Zeile 179 in giteaService.js)
|
||||
2. Der lokale Git-Branch heißt aber `master`
|
||||
3. Die Dateien wurden nach `master` gepusht
|
||||
4. Gitea zeigte `main` an (leer bis auf README)
|
||||
|
||||
### Implementierte Lösung
|
||||
|
||||
1. **`updateRepository()` Funktion** zu `backend/services/giteaService.js` hinzugefügt
|
||||
- Ändert den Default-Branch über Gitea PATCH API
|
||||
- Unterstützt auch Beschreibung und Private-Status
|
||||
|
||||
2. **`pushWithUpstream()` Funktion** in `backend/services/gitService.js` erweitert
|
||||
- Gibt jetzt den Branch-Namen im Ergebnis zurück
|
||||
|
||||
3. **`init-push` Endpoint** in `backend/routes/git.js` erweitert
|
||||
- Nach erfolgreichem Push wird automatisch der Default-Branch in Gitea aktualisiert
|
||||
- Owner/Repo wird aus der Repository-URL extrahiert
|
||||
|
||||
4. **Cache-Version** auf 119 erhöht in `frontend/sw.js`
|
||||
|
||||
---
|
||||
|
||||
## Gelöste Probleme (zur Referenz)
|
||||
|
||||
1. **"git: not found"** → Git in Dockerfile installiert
|
||||
2. **"dubious ownership in repository"** → `safe.directory '*'` konfiguriert
|
||||
3. **"No configured push destination"** → `setRemote()` und `prepareForGitea()` hinzugefügt
|
||||
4. **"src refspec main does not match any"** → Branch-Erkennung in `pushWithUpstream()` implementiert
|
||||
|
||||
---
|
||||
|
||||
## Wichtige Dateien
|
||||
|
||||
| Datei | Status |
|
||||
|-------|--------|
|
||||
| `backend/server.js` | ✅ Fertig |
|
||||
| `backend/routes/gitea.js` | ✅ Fertig |
|
||||
| `backend/routes/git.js` | ✅ Fertig (inkl. auto Default-Branch Update) |
|
||||
| `backend/services/gitService.js` | ✅ Fertig (inkl. Branch-Name Return) |
|
||||
| `backend/services/giteaService.js` | ✅ Fertig (inkl. updateRepository) |
|
||||
| `Dockerfile` | ✅ Fertig |
|
||||
| `frontend/js/api.js` | ✅ Fertig |
|
||||
| `frontend/js/gitea.js` | ✅ Fertig |
|
||||
| `frontend/css/gitea.css` | ✅ Fertig |
|
||||
| `frontend/index.html` | ✅ Fertig |
|
||||
| `frontend/js/app.js` | ✅ Fertig |
|
||||
| `frontend/sw.js` | ✅ Fertig (v119) |
|
||||
|
||||
---
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
1. ✅ `updateRepository()` zu `backend/services/giteaService.js` hinzugefügt
|
||||
2. ✅ Funktion exportiert
|
||||
3. ✅ Push-Flow erweitert, um Default-Branch nach Push zu aktualisieren
|
||||
4. ✅ Docker-Container neu gebaut
|
||||
5. ⏳ Testen: Projekt mit Gitea verknüpfen → Push → Dateien in Gitea sichtbar
|
||||
|
||||
---
|
||||
|
||||
## Plan-Datei
|
||||
|
||||
Der vollständige Implementierungsplan befindet sich in:
|
||||
`C:\Users\hendr\.claude\plans\rosy-stargazing-scroll.md`
|
||||
|
||||
---
|
||||
|
||||
## Befehle zum Testen
|
||||
|
||||
```bash
|
||||
# Container neu bauen
|
||||
docker compose down
|
||||
docker compose build --no-cache
|
||||
docker compose up -d
|
||||
|
||||
# Browser öffnen
|
||||
start chrome --incognito http://localhost:3000
|
||||
```
|
||||
@ -175,8 +175,14 @@ router.post('/commit/:projectId', (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Commit erstellen
|
||||
const result = gitService.commit(application.local_path, message);
|
||||
// Autor aus eingeloggtem Benutzer
|
||||
const author = req.user ? {
|
||||
name: req.user.display_name || req.user.username,
|
||||
email: req.user.email || `${req.user.username.toLowerCase()}@taskmate.local`
|
||||
} : null;
|
||||
|
||||
// Commit erstellen mit Autor
|
||||
const result = gitService.commit(application.local_path, message, author);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Commit:', error);
|
||||
@ -414,24 +420,58 @@ router.post('/set-remote/:projectId', (req, res) => {
|
||||
/**
|
||||
* POST /api/git/init-push/:projectId
|
||||
* Initialen Push mit Upstream-Tracking
|
||||
* Body: { targetBranch?: string, force?: boolean }
|
||||
* - targetBranch: Optional - Ziel-Branch auf Remote (z.B. "main" auch wenn lokal "master")
|
||||
* - force: Optional - Force-Push um Remote zu überschreiben
|
||||
*/
|
||||
router.post('/init-push/:projectId', (req, res) => {
|
||||
router.post('/init-push/:projectId', async (req, res) => {
|
||||
try {
|
||||
const { projectId } = req.params;
|
||||
const { branch } = req.body;
|
||||
const { targetBranch, force } = req.body;
|
||||
const application = getApplicationForProject(projectId);
|
||||
|
||||
if (!application) {
|
||||
return res.status(404).json({ error: 'Keine Anwendung für dieses Projekt konfiguriert' });
|
||||
}
|
||||
|
||||
const currentBranch = branch || 'main';
|
||||
const result = gitService.pushWithUpstream(application.local_path, currentBranch);
|
||||
// targetBranch kann null sein - dann wird der lokale Branch-Name verwendet
|
||||
// force: boolean - überschreibt Remote-Branch bei Konflikten
|
||||
const result = gitService.pushWithUpstream(application.local_path, targetBranch || null, 'origin', force === true);
|
||||
|
||||
if (result.success) {
|
||||
// Sync-Zeitpunkt aktualisieren
|
||||
const db = getDb();
|
||||
db.prepare('UPDATE applications SET last_sync = CURRENT_TIMESTAMP WHERE project_id = ?').run(projectId);
|
||||
|
||||
// Default-Branch in Gitea aktualisieren wenn der gepushte Branch abweicht
|
||||
if (application.gitea_repo_url && result.branch) {
|
||||
try {
|
||||
// Owner/Repo aus URL extrahieren (z.B. https://gitea.../AegisSight/TaskMate.git)
|
||||
const urlMatch = application.gitea_repo_url.match(/\/([^\/]+)\/([^\/]+?)(?:\.git)?$/);
|
||||
if (urlMatch) {
|
||||
const owner = urlMatch[1];
|
||||
const repoName = urlMatch[2];
|
||||
const actualBranch = result.branch;
|
||||
|
||||
// Default-Branch in Gitea setzen
|
||||
const updateResult = await giteaService.updateRepository(owner, repoName, {
|
||||
defaultBranch: actualBranch
|
||||
});
|
||||
|
||||
if (updateResult.success) {
|
||||
logger.info(`Default-Branch in Gitea auf '${actualBranch}' gesetzt für ${owner}/${repoName}`);
|
||||
result.giteaUpdated = true;
|
||||
result.defaultBranch = actualBranch;
|
||||
} else {
|
||||
logger.warn(`Konnte Default-Branch in Gitea nicht aktualisieren: ${updateResult.error}`);
|
||||
result.giteaUpdated = false;
|
||||
}
|
||||
}
|
||||
} catch (giteaError) {
|
||||
logger.warn('Fehler beim Aktualisieren des Default-Branch in Gitea:', giteaError);
|
||||
result.giteaUpdated = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.json(result);
|
||||
@ -441,4 +481,31 @@ router.post('/init-push/:projectId', (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/git/rename-branch/:projectId
|
||||
* Branch umbenennen
|
||||
* Body: { oldName: string, newName: string }
|
||||
*/
|
||||
router.post('/rename-branch/:projectId', (req, res) => {
|
||||
try {
|
||||
const { projectId } = req.params;
|
||||
const { oldName, newName } = req.body;
|
||||
const application = getApplicationForProject(projectId);
|
||||
|
||||
if (!application) {
|
||||
return res.status(404).json({ error: 'Keine Anwendung für dieses Projekt konfiguriert' });
|
||||
}
|
||||
|
||||
if (!oldName || !newName) {
|
||||
return res.status(400).json({ error: 'oldName und newName sind erforderlich' });
|
||||
}
|
||||
|
||||
const result = gitService.renameBranch(application.local_path, oldName, newName);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
logger.error('Fehler beim Umbenennen des Branches:', error);
|
||||
res.status(500).json({ error: 'Serverfehler' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@ -253,8 +253,11 @@ function stageAll(localPath) {
|
||||
|
||||
/**
|
||||
* Commit erstellen
|
||||
* @param {string} localPath - Pfad zum Repository
|
||||
* @param {string} message - Commit-Nachricht
|
||||
* @param {object} author - Autor-Informationen { name, email }
|
||||
*/
|
||||
function commit(localPath, message) {
|
||||
function commit(localPath, message, author = null) {
|
||||
if (!isGitRepository(localPath)) {
|
||||
return { success: false, error: 'Kein Git-Repository' };
|
||||
}
|
||||
@ -265,7 +268,17 @@ function commit(localPath, message) {
|
||||
|
||||
// Escape für Shell
|
||||
const escapedMessage = message.replace(/"/g, '\\"');
|
||||
return execGitCommand(`git commit -m "${escapedMessage}"`, localPath);
|
||||
|
||||
// Commit-Befehl mit optionalem Autor
|
||||
let commitCmd = `git commit -m "${escapedMessage}"`;
|
||||
if (author && author.name) {
|
||||
const authorName = author.name.replace(/"/g, '\\"');
|
||||
const authorEmail = author.email || `${author.name.toLowerCase().replace(/\s+/g, '.')}@taskmate.local`;
|
||||
commitCmd = `git commit --author="${authorName} <${authorEmail}>" -m "${escapedMessage}"`;
|
||||
logger.info(`Commit mit Autor: ${authorName} <${authorEmail}>`);
|
||||
}
|
||||
|
||||
return execGitCommand(commitCmd, localPath);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -443,7 +456,7 @@ function hasRemote(localPath, remoteName = 'origin') {
|
||||
/**
|
||||
* Initialen Push mit Upstream-Tracking
|
||||
*/
|
||||
function pushWithUpstream(localPath, branch = null, remoteName = 'origin') {
|
||||
function pushWithUpstream(localPath, targetBranch = null, remoteName = 'origin', force = false) {
|
||||
if (!isGitRepository(localPath)) {
|
||||
return { success: false, error: 'Kein Git-Repository' };
|
||||
}
|
||||
@ -477,11 +490,12 @@ function pushWithUpstream(localPath, branch = null, remoteName = 'origin') {
|
||||
}
|
||||
}
|
||||
|
||||
// Aktuellen Branch ermitteln NACH dem Commit
|
||||
// Aktuellen (lokalen) Branch ermitteln NACH dem Commit
|
||||
let localBranch = null;
|
||||
const branchResult = execGitCommand('git branch --show-current', localPath);
|
||||
if (branchResult.success && branchResult.output) {
|
||||
branch = branchResult.output;
|
||||
logger.info(`Aktueller Branch: ${branch}`);
|
||||
localBranch = branchResult.output;
|
||||
logger.info(`Lokaler Branch: ${localBranch}`);
|
||||
} else {
|
||||
// Fallback: Branch aus git branch auslesen
|
||||
const branchListResult = execGitCommand('git branch', localPath);
|
||||
@ -491,29 +505,46 @@ function pushWithUpstream(localPath, branch = null, remoteName = 'origin') {
|
||||
const lines = branchListResult.output.split('\n');
|
||||
for (const line of lines) {
|
||||
if (line.includes('*')) {
|
||||
branch = line.replace('*', '').trim();
|
||||
localBranch = line.replace('*', '').trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!branch) {
|
||||
if (!localBranch) {
|
||||
// Letzter Fallback: Versuche den Branch zu erstellen
|
||||
logger.info('Kein Branch gefunden, erstelle main');
|
||||
execGitCommand('git checkout -b main', localPath);
|
||||
branch = 'main';
|
||||
localBranch = 'main';
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(`Push auf Branch: ${branch}`);
|
||||
// Wenn kein Ziel-Branch angegeben, verwende lokalen Branch-Namen
|
||||
const remoteBranch = targetBranch || localBranch;
|
||||
|
||||
logger.info(`Push: lokaler Branch '${localBranch}' → Remote Branch '${remoteBranch}'${force ? ' (FORCE)' : ''}`);
|
||||
|
||||
// Push mit -u für Upstream-Tracking
|
||||
const pushResult = execGitCommand(`git push -u ${remoteName} ${branch}`, localPath, { timeout: 120000 });
|
||||
// Format: git push -u origin localBranch:remoteBranch
|
||||
const forceFlag = force ? ' --force' : '';
|
||||
let pushCommand;
|
||||
if (localBranch === remoteBranch) {
|
||||
pushCommand = `git push -u${forceFlag} ${remoteName} ${localBranch}`;
|
||||
} else {
|
||||
// Branch-Mapping: lokalen Branch auf anderen Remote-Branch pushen
|
||||
pushCommand = `git push -u${forceFlag} ${remoteName} ${localBranch}:${remoteBranch}`;
|
||||
}
|
||||
|
||||
const pushResult = execGitCommand(pushCommand, localPath, { timeout: 120000 });
|
||||
|
||||
if (!pushResult.success) {
|
||||
logger.error(`Push fehlgeschlagen: ${pushResult.error}`);
|
||||
}
|
||||
|
||||
// Branch-Namen im Ergebnis inkludieren für Default-Branch Aktualisierung
|
||||
pushResult.localBranch = localBranch;
|
||||
pushResult.branch = remoteBranch; // Remote-Branch für Gitea Default-Branch
|
||||
|
||||
return pushResult;
|
||||
}
|
||||
|
||||
@ -561,6 +592,39 @@ function prepareForGitea(localPath, remoteUrl, options = {}) {
|
||||
return { success: true, message: 'Repository für Gitea vorbereitet' };
|
||||
}
|
||||
|
||||
/**
|
||||
* Branch umbenennen
|
||||
*/
|
||||
function renameBranch(localPath, oldName, newName) {
|
||||
if (!isGitRepository(localPath)) {
|
||||
return { success: false, error: 'Kein Git-Repository' };
|
||||
}
|
||||
|
||||
// Validiere neuen Branch-Namen
|
||||
if (!newName || !/^[a-zA-Z0-9_\-]+$/.test(newName)) {
|
||||
return { success: false, error: 'Ungültiger Branch-Name. Nur Buchstaben, Zahlen, Unterstriche und Bindestriche erlaubt.' };
|
||||
}
|
||||
|
||||
// Prüfe ob wir auf dem zu umbenennenden Branch sind
|
||||
const branchResult = execGitCommand('git branch --show-current', localPath);
|
||||
const currentBranch = branchResult.success ? branchResult.output : null;
|
||||
|
||||
if (currentBranch !== oldName) {
|
||||
return { success: false, error: `Bitte wechsle zuerst zum Branch "${oldName}" bevor du ihn umbenennst.` };
|
||||
}
|
||||
|
||||
// Branch umbenennen
|
||||
const renameResult = execGitCommand(`git branch -m ${oldName} ${newName}`, localPath);
|
||||
|
||||
if (!renameResult.success) {
|
||||
logger.error(`Branch umbenennen fehlgeschlagen: ${renameResult.error}`);
|
||||
return renameResult;
|
||||
}
|
||||
|
||||
logger.info(`Branch umbenannt: ${oldName} → ${newName}`);
|
||||
return { success: true, oldName, newName, message: `Branch "${oldName}" zu "${newName}" umbenannt` };
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
windowsToContainerPath,
|
||||
containerToWindowsPath,
|
||||
@ -581,5 +645,6 @@ module.exports = {
|
||||
setRemote,
|
||||
hasRemote,
|
||||
pushWithUpstream,
|
||||
prepareForGitea
|
||||
prepareForGitea,
|
||||
renameBranch
|
||||
};
|
||||
|
||||
@ -284,12 +284,44 @@ function getSafeCloneUrl(cloneUrl) {
|
||||
return cloneUrl.replace(/https:\/\/[^@]+@/, 'https://');
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository-Einstellungen aktualisieren (z.B. default_branch ändern)
|
||||
*/
|
||||
async function updateRepository(owner, repo, options = {}) {
|
||||
try {
|
||||
const updateData = {};
|
||||
if (options.defaultBranch) updateData.default_branch = options.defaultBranch;
|
||||
if (options.description !== undefined) updateData.description = options.description;
|
||||
if (options.private !== undefined) updateData.private = options.private;
|
||||
|
||||
const repoData = await giteaFetch(`/repos/${owner}/${repo}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(updateData)
|
||||
});
|
||||
|
||||
logger.info(`Repository ${owner}/${repo} aktualisiert (default_branch: ${repoData.default_branch})`);
|
||||
return {
|
||||
success: true,
|
||||
repository: {
|
||||
id: repoData.id,
|
||||
name: repoData.name,
|
||||
fullName: repoData.full_name,
|
||||
defaultBranch: repoData.default_branch
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
logger.error(`Fehler beim Aktualisieren des Repositories ${owner}/${repo}:`, error);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
listRepositories,
|
||||
getRepository,
|
||||
getRepositoryBranches,
|
||||
getRepositoryCommits,
|
||||
createRepository,
|
||||
updateRepository,
|
||||
deleteRepository,
|
||||
getCurrentUser,
|
||||
testConnection,
|
||||
|
||||
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
0
backups/backup_2025-12-29T18-03-28-634Z.db-wal
Normale Datei
0
backups/backup_2025-12-29T18-03-28-634Z.db-wal
Normale Datei
Binäre Datei nicht angezeigt.
0
backups/backup_2025-12-29T18-30-58-187Z.db-wal
Normale Datei
0
backups/backup_2025-12-29T18-30-58-187Z.db-wal
Normale Datei
Binäre Datei nicht angezeigt.
0
backups/backup_2025-12-29T18-36-12-724Z.db-wal
Normale Datei
0
backups/backup_2025-12-29T18-36-12-724Z.db-wal
Normale Datei
Binäre Datei nicht angezeigt.
0
backups/backup_2025-12-29T18-46-49-826Z.db-wal
Normale Datei
0
backups/backup_2025-12-29T18-46-49-826Z.db-wal
Normale Datei
BIN
backups/backup_2025-12-29T19-01-37-753Z.db
Normale Datei
BIN
backups/backup_2025-12-29T19-01-37-753Z.db
Normale Datei
Binäre Datei nicht angezeigt.
BIN
backups/backup_2025-12-29T19-01-37-753Z.db-wal
Normale Datei
BIN
backups/backup_2025-12-29T19-01-37-753Z.db-wal
Normale Datei
Binäre Datei nicht angezeigt.
BIN
backups/backup_2025-12-29T19-15-04-246Z.db
Normale Datei
BIN
backups/backup_2025-12-29T19-15-04-246Z.db
Normale Datei
Binäre Datei nicht angezeigt.
0
backups/backup_2025-12-29T19-15-04-246Z.db-wal
Normale Datei
0
backups/backup_2025-12-29T19-15-04-246Z.db-wal
Normale Datei
BIN
data/taskmate.db
BIN
data/taskmate.db
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
Binäre Datei nicht angezeigt.
@ -225,6 +225,12 @@
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.branch-select-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-2);
|
||||
}
|
||||
|
||||
.branch-select {
|
||||
padding: var(--spacing-2) var(--spacing-3);
|
||||
border-radius: var(--radius-md);
|
||||
@ -233,6 +239,7 @@
|
||||
color: var(--text-primary);
|
||||
font-size: var(--text-sm);
|
||||
cursor: pointer;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.branch-select:focus {
|
||||
@ -240,6 +247,24 @@
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.btn-small {
|
||||
padding: var(--spacing-1) var(--spacing-2);
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: var(--spacing-1);
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.btn-icon svg {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@ -259,11 +284,6 @@
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.status-badge.ahead {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
color: var(--info);
|
||||
}
|
||||
|
||||
.status-badge.error {
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
color: var(--error);
|
||||
@ -275,12 +295,6 @@
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
#git-ahead-behind {
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-primary);
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
/* =============================================================================
|
||||
OPERATIONS PANEL
|
||||
============================================================================= */
|
||||
@ -511,6 +525,20 @@
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.form-hint.warning {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.form-static-value {
|
||||
padding: var(--spacing-2) var(--spacing-3);
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-sm);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -606,9 +606,14 @@
|
||||
<div class="status-grid">
|
||||
<div class="status-item">
|
||||
<span class="status-label">Branch</span>
|
||||
<select id="branch-select" class="branch-select">
|
||||
<!-- Branches dynamisch -->
|
||||
</select>
|
||||
<div class="branch-select-group">
|
||||
<select id="branch-select" class="branch-select">
|
||||
<!-- Branches dynamisch -->
|
||||
</select>
|
||||
<button id="btn-rename-branch" class="btn btn-small btn-icon" title="Branch umbenennen">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16"><path d="M17 3a2.85 2.85 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z" stroke="currentColor" stroke-width="2" fill="none"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">Status</span>
|
||||
@ -618,10 +623,6 @@
|
||||
<span class="status-label">Änderungen</span>
|
||||
<span id="git-changes-count" class="changes-count">0</span>
|
||||
</div>
|
||||
<div class="status-item">
|
||||
<span class="status-label">Ahead / Behind</span>
|
||||
<span id="git-ahead-behind">- / -</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1163,6 +1164,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Git Branch Rename Modal -->
|
||||
<div id="git-rename-branch-modal" class="modal modal-small hidden">
|
||||
<div class="modal-header">
|
||||
<h2>Branch umbenennen</h2>
|
||||
<button class="modal-close" data-close-modal>×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="git-rename-branch-form">
|
||||
<div class="form-group">
|
||||
<label>Aktueller Branch</label>
|
||||
<div id="rename-current-branch" class="form-static-value">master</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="rename-new-branch">Neuer Name *</label>
|
||||
<input type="text" id="rename-new-branch" required
|
||||
placeholder="z.B. main" pattern="[a-zA-Z0-9_\-]+"
|
||||
title="Nur Buchstaben, Zahlen, Unterstriche und Bindestriche">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
|
||||
<button type="submit" form="git-rename-branch-form" class="btn btn-primary">Umbenennen</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Git Push Modal -->
|
||||
<div id="git-push-modal" class="modal modal-small hidden">
|
||||
<div class="modal-header">
|
||||
<h2>Push zu Gitea</h2>
|
||||
<button class="modal-close" data-close-modal>×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="git-push-form">
|
||||
<div class="form-group">
|
||||
<label>Lokaler Branch</label>
|
||||
<div id="push-local-branch" class="form-static-value">wird ermittelt...</div>
|
||||
<span class="form-hint">Der aktuelle lokale Branch wird automatisch erkannt</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="push-target-branch">Ziel-Branch auf Remote</label>
|
||||
<select id="push-target-branch">
|
||||
<option value="">Gleicher Name wie lokal</option>
|
||||
<option value="main">main</option>
|
||||
<option value="master">master</option>
|
||||
<option value="develop">develop</option>
|
||||
</select>
|
||||
<span class="form-hint">Wählen Sie den Branch-Namen auf Gitea</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="push-force">
|
||||
Force Push (Remote überschreiben)
|
||||
</label>
|
||||
<span class="form-hint warning">Achtung: Überschreibt alle Änderungen auf dem Remote-Branch!</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-close-modal>Abbrechen</button>
|
||||
<button type="submit" form="git-push-form" class="btn btn-primary">Push starten</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create Repository Modal -->
|
||||
<div id="create-repo-modal" class="modal modal-small hidden">
|
||||
<div class="modal-header">
|
||||
|
||||
@ -820,8 +820,12 @@ class ApiClient {
|
||||
return this.post(`/git/set-remote/${projectId}`, { repoUrl });
|
||||
}
|
||||
|
||||
async gitInitPush(projectId, branch = 'main') {
|
||||
return this.post(`/git/init-push/${projectId}`, { branch });
|
||||
async gitInitPush(projectId, targetBranch = null, force = false) {
|
||||
return this.post(`/git/init-push/${projectId}`, { targetBranch, force });
|
||||
}
|
||||
|
||||
async gitRenameBranch(projectId, oldName, newName) {
|
||||
return this.post(`/git/rename-branch/${projectId}`, { oldName, newName });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -72,6 +72,13 @@ class GiteaManager {
|
||||
|
||||
// Commit Modal
|
||||
$('#git-commit-form')?.addEventListener('submit', (e) => this.handleCommit(e));
|
||||
|
||||
// Push Modal
|
||||
$('#git-push-form')?.addEventListener('submit', (e) => this.executePush(e));
|
||||
|
||||
// Branch umbenennen
|
||||
$('#btn-rename-branch')?.addEventListener('click', () => this.openRenameBranchModal());
|
||||
$('#git-rename-branch-form')?.addEventListener('submit', (e) => this.executeRenameBranch(e));
|
||||
}
|
||||
|
||||
subscribeToStore() {
|
||||
@ -406,27 +413,76 @@ class GiteaManager {
|
||||
}
|
||||
}
|
||||
|
||||
async handlePush() {
|
||||
handlePush() {
|
||||
// Öffne das Push-Modal zur Branch-Auswahl
|
||||
this.openPushModal();
|
||||
}
|
||||
|
||||
openPushModal() {
|
||||
const modal = $('#git-push-modal');
|
||||
if (!modal) return;
|
||||
|
||||
// Aktuellen lokalen Branch anzeigen
|
||||
const currentBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'unbekannt';
|
||||
$('#push-local-branch').textContent = currentBranch;
|
||||
|
||||
// Ziel-Branch zurücksetzen (Standard: gleicher Name wie lokal)
|
||||
$('#push-target-branch').value = '';
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('visible');
|
||||
$('#modal-overlay')?.classList.remove('hidden');
|
||||
|
||||
store.openModal('git-push-modal');
|
||||
}
|
||||
|
||||
async executePush(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const projectId = store.get('currentProjectId');
|
||||
if (!projectId) return;
|
||||
|
||||
// Modal schließen
|
||||
const modal = $('#git-push-modal');
|
||||
modal?.classList.add('hidden');
|
||||
modal?.classList.remove('visible');
|
||||
$('#modal-overlay')?.classList.add('hidden');
|
||||
store.closeModal();
|
||||
|
||||
this.setOperationLoading('push', true);
|
||||
|
||||
try {
|
||||
const branch = $('#branch-select')?.value || 'main';
|
||||
let result = await api.gitPush(projectId, branch);
|
||||
const targetBranch = $('#push-target-branch')?.value || null;
|
||||
const forcePush = $('#push-force')?.checked || false;
|
||||
const localBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'master';
|
||||
|
||||
// Falls Push wegen fehlendem Upstream/Remote fehlschlägt, versuche init-push
|
||||
if (!result.success && result.error &&
|
||||
(result.error.includes('No configured push destination') ||
|
||||
result.error.includes('no upstream') ||
|
||||
result.error.includes('Kein Remote'))) {
|
||||
this.showToast('Kein Upstream konfiguriert, führe initialen Push durch...', 'info');
|
||||
result = await api.gitInitPush(projectId, branch);
|
||||
let result;
|
||||
|
||||
// Wenn ein anderer Target-Branch ausgewählt wurde oder Force-Push, verwende init-push
|
||||
if ((targetBranch && targetBranch !== localBranch) || forcePush) {
|
||||
const forceText = forcePush ? ' (Force)' : '';
|
||||
const branchText = targetBranch && targetBranch !== localBranch
|
||||
? `Push von "${localBranch}" nach "${targetBranch}"${forceText}...`
|
||||
: `Push nach "${localBranch}"${forceText}...`;
|
||||
this.showToast(branchText, 'info');
|
||||
result = await api.gitInitPush(projectId, targetBranch, forcePush);
|
||||
} else {
|
||||
// Normaler Push (gleicher Branch-Name)
|
||||
result = await api.gitPush(projectId, localBranch);
|
||||
|
||||
// Falls Push wegen fehlendem Upstream/Remote fehlschlägt, versuche init-push
|
||||
if (!result.success && result.error &&
|
||||
(result.error.includes('No configured push destination') ||
|
||||
result.error.includes('no upstream') ||
|
||||
result.error.includes('Kein Remote'))) {
|
||||
this.showToast('Kein Upstream konfiguriert, führe initialen Push durch...', 'info');
|
||||
result = await api.gitInitPush(projectId, targetBranch, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.success) {
|
||||
this.showToast('Push erfolgreich', 'success');
|
||||
const pushedBranch = result.branch || targetBranch || localBranch;
|
||||
this.showToast(`Push erfolgreich nach Branch "${pushedBranch}"`, 'success');
|
||||
await this.loadGitData();
|
||||
} else {
|
||||
this.showToast(result.error || 'Push fehlgeschlagen', 'error');
|
||||
@ -438,6 +494,64 @@ class GiteaManager {
|
||||
}
|
||||
}
|
||||
|
||||
openRenameBranchModal() {
|
||||
const modal = $('#git-rename-branch-modal');
|
||||
if (!modal) return;
|
||||
|
||||
const currentBranch = $('#branch-select')?.value || this.gitStatus?.branch || 'master';
|
||||
$('#rename-current-branch').textContent = currentBranch;
|
||||
$('#rename-new-branch').value = '';
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
modal.classList.add('visible');
|
||||
$('#modal-overlay')?.classList.remove('hidden');
|
||||
|
||||
store.openModal('git-rename-branch-modal');
|
||||
|
||||
// Focus auf das Eingabefeld
|
||||
setTimeout(() => $('#rename-new-branch')?.focus(), 100);
|
||||
}
|
||||
|
||||
async executeRenameBranch(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const projectId = store.get('currentProjectId');
|
||||
if (!projectId) return;
|
||||
|
||||
const oldName = $('#rename-current-branch')?.textContent;
|
||||
const newName = $('#rename-new-branch')?.value.trim();
|
||||
|
||||
if (!newName) {
|
||||
this.showToast('Bitte geben Sie einen neuen Branch-Namen ein', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldName === newName) {
|
||||
this.showToast('Der neue Name ist identisch mit dem aktuellen', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Modal schließen
|
||||
const modal = $('#git-rename-branch-modal');
|
||||
modal?.classList.add('hidden');
|
||||
modal?.classList.remove('visible');
|
||||
$('#modal-overlay')?.classList.add('hidden');
|
||||
store.closeModal();
|
||||
|
||||
try {
|
||||
const result = await api.gitRenameBranch(projectId, oldName, newName);
|
||||
|
||||
if (result.success) {
|
||||
this.showToast(`Branch umbenannt: "${oldName}" → "${newName}"`, 'success');
|
||||
await this.loadGitData();
|
||||
} else {
|
||||
this.showToast(result.error || 'Umbenennen fehlgeschlagen', 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showToast(error.message || 'Umbenennen fehlgeschlagen', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
openCommitModal() {
|
||||
const modal = $('#git-commit-modal');
|
||||
if (!modal) return;
|
||||
@ -610,13 +724,11 @@ class GiteaManager {
|
||||
renderStatus() {
|
||||
const statusBadge = $('#git-status-indicator');
|
||||
const changesCount = $('#git-changes-count');
|
||||
const aheadBehind = $('#git-ahead-behind');
|
||||
|
||||
if (!this.gitStatus) {
|
||||
statusBadge.textContent = 'Fehler';
|
||||
statusBadge.className = 'status-badge error';
|
||||
changesCount.textContent = '-';
|
||||
aheadBehind.textContent = '- / -';
|
||||
return;
|
||||
}
|
||||
|
||||
@ -630,9 +742,6 @@ class GiteaManager {
|
||||
} else if (this.gitStatus.hasChanges) {
|
||||
statusBadge.textContent = 'Geändert';
|
||||
statusBadge.className = 'status-badge dirty';
|
||||
} else if (this.gitStatus.ahead > 0) {
|
||||
statusBadge.textContent = 'Voraus';
|
||||
statusBadge.className = 'status-badge ahead';
|
||||
} else {
|
||||
statusBadge.textContent = 'OK';
|
||||
statusBadge.className = 'status-badge clean';
|
||||
@ -641,11 +750,6 @@ class GiteaManager {
|
||||
// Änderungen
|
||||
const changes = this.gitStatus.changes || [];
|
||||
changesCount.textContent = changes.length;
|
||||
|
||||
// Ahead/Behind
|
||||
const ahead = this.gitStatus.ahead || 0;
|
||||
const behind = this.gitStatus.behind || 0;
|
||||
aheadBehind.textContent = `${ahead} / ${behind}`;
|
||||
}
|
||||
|
||||
renderBranches() {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
* Offline support and caching
|
||||
*/
|
||||
|
||||
const CACHE_VERSION = '118';
|
||||
const CACHE_VERSION = '124';
|
||||
const CACHE_NAME = 'taskmate-v' + CACHE_VERSION;
|
||||
const STATIC_CACHE_NAME = 'taskmate-static-v' + CACHE_VERSION;
|
||||
const DYNAMIC_CACHE_NAME = 'taskmate-dynamic-v' + CACHE_VERSION;
|
||||
|
||||
3481
logs/app.log
3481
logs/app.log
Datei-Diff unterdrückt, da er zu groß ist
Diff laden
In neuem Issue referenzieren
Einen Benutzer sperren