diff --git a/Backlog.md b/Backlog.md index bc1cfac..0edba29 100644 --- a/Backlog.md +++ b/Backlog.md @@ -590,12 +590,15 @@ Example: ## Actions -- [ ] Status -- [ ] View Changes -- [ ] Commit -- [ ] Pull -- [ ] Push -- [ ] Fetch +- [x] Status +- [x] View Changes +- [x] Diff +- [x] Commit +- [x] Stage / Unstage / Discard +- [x] Merge (ours / theirs / continue / abort) +- [x] Pull +- [x] Push +- [x] Fetch - [x] Open terminal here - [x] Open in Cursor @@ -696,13 +699,9 @@ Potential: ## Git -`WindowsGitStatusProvider` (`IGitStatusProvider`) +`WindowsGitStatusProvider` (`IGitStatusProvider`, `IGitCommandProvider`) -Discovery: Settings path, then Program Files, then PATH. Missing git.exe means no badge. Git is not bundled. Workbench does not commit, push, or pull. - -Potential later: - -`IGitCommandProvider` +Discovery: Settings path, then Program Files, then PATH. Missing git.exe means no badge. Git is not bundled. Status / View Changes lists porcelain paths. Diff is unified `git diff`. Commit stages checked files then `git commit --only`. Stage / unstage / discard, ours / theirs / mark resolved, continue / abort wrap `git.exe`. Fetch / fast-forward pull / merge pull / push use `GIT_TERMINAL_PROMPT=0`. No mergetool, stash, branch UI, or credential dialog. Failed fast-forward pull offers merge pull or a terminal. --- diff --git a/docs/Documentation.md b/docs/Documentation.md index 3017bde..f95bbda 100644 --- a/docs/Documentation.md +++ b/docs/Documentation.md @@ -24,18 +24,18 @@ Workbench **does**: Workbench **does not**: - Two-way sync -- Commit, push, or pull - Convert media (no FFmpeg in this build) - Hydrate online-only cloud files just to look at them - Change Windows drive mappings or cloud client folders +- Replace Git (no stash, branch UI, mergetool, or credential dialog) -Specialized tools still do specialized jobs. 7-Zip compresses. Git reports status. Workbench orchestrates. +Specialized tools still do specialized jobs. 7-Zip compresses. Git reports status, shows diffs, commits selected files, resolves conflicts, and runs fetch, pull, and push. Workbench orchestrates. --- ## First launch -1. This PC lists local and removable volumes Windows already knows. +The window opens immediately. Locations fill in a moment later — Workbench does not wait for slow network shares or a second instance locking the index. 2. Browsing works with an empty index. 3. Folder sizes, search, duplicates, and storage analysis need an index. Use the banner **Build index**, **Tools → Locations → Index this location**, or the toolbar **Index** control. 4. Data lives under `%LocalAppData%\ExplorerWorkbench\` — never beside the executable. @@ -273,9 +273,17 @@ Never auto-reorganizes. No MIME/content sniffing (that would hydrate cloud files ## Git -Workbench detects repositories and shows a badge (branch, modified, untracked, ahead/behind). **Tools → Development → Open terminal here** and **Open in Cursor** are available when a folder is in context. +Workbench detects repositories and shows a badge (branch, modified, untracked, ahead/behind, merging/rebasing). **Tools → Development** (and the folder context menu) offers **View changes…**, **Commit…**, **Fetch**, **Pull (fast-forward)**, **Pull (merge)**, **Push**, **Open terminal here**, and **Open in Cursor** when a folder is in a repository. -Missing `git.exe` means no badge. Path can be set in Settings. Git is not bundled. There is no commit, push, pull, or diff viewer. Profiles can require a clean working tree. +**View changes** lists staged, unstaged, untracked, and unmerged paths from `git status`. Double-click opens a unified **diff** (`git diff` / `git diff --cached`). **Open in Cursor** opens the file. Online-only cloud files are not opened or diffed (that would download them). Stage, unstage, and discard call the matching `git` commands. Discard asks first. + +**Commit** asks for a message and which files to include. Unmerged paths, online-only cloud files, and folders are skipped. A merge, rebase, cherry-pick, or revert in progress blocks a normal commit — use **Continue** or **Abort**. Workbench runs `git add` then `git commit --only` for the checked paths, so other staged files stay staged. + +**Merge** is conflict resolution, not a mergetool: **Use ours**, **Use theirs**, **Mark resolved**, then **Continue** (`git commit --no-edit` / `rebase --continue`). **Abort** restores the previous state. Incoming rebase/cherry-pick/revert from a terminal can be finished the same way. + +**Pull (fast-forward)** is `git pull --ff-only --no-rebase`. If that cannot fast-forward, Workbench offers **Pull (merge)** (`git pull --no-rebase`) or a terminal. Fetch and push are the matching `git` commands. There is no stash, branch UI, mergetool, or credential dialog (`GIT_TERMINAL_PROMPT=0`). + +Missing `git.exe` means no badge and no Git actions. Path can be set in Settings. Git is not bundled. Profiles can require a clean working tree. --- diff --git a/src/Explorer.App/App.xaml.cs b/src/Explorer.App/App.xaml.cs index 84bd34c..2a3edc5 100644 --- a/src/Explorer.App/App.xaml.cs +++ b/src/Explorer.App/App.xaml.cs @@ -35,11 +35,21 @@ public partial class App : System.Windows.Application .Build(); var vm = _host.Services.GetRequiredService(); - await vm.InitializeAsync().ConfigureAwait(true); - await _host.StartAsync().ConfigureAwait(true); var window = _host.Services.GetRequiredService(); + vm.PrepareUi(); window.DataContext = vm; window.Show(); + try + { + await vm.InitializeAsync().ConfigureAwait(true); + } + catch (Exception ex) + { + Log.Error(ex, "Startup initialization failed"); + vm.Footer = "Started with errors. See logs."; + } + + await _host.StartAsync().ConfigureAwait(true); } protected override async void OnExit(ExitEventArgs e) diff --git a/src/Explorer.App/AppServices.cs b/src/Explorer.App/AppServices.cs index ce721a5..9e0b229 100644 --- a/src/Explorer.App/AppServices.cs +++ b/src/Explorer.App/AppServices.cs @@ -42,7 +42,9 @@ public static class AppServices services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(sp => sp.GetRequiredService()); + services.AddSingleton(sp => sp.GetRequiredService()); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -115,7 +117,7 @@ public sealed class WatcherHostedService : BackgroundService await _hub.RefreshAsync(stoppingToken).ConfigureAwait(false); while (await timer.WaitForNextTickAsync(stoppingToken).ConfigureAwait(false)) { - await _sources.RefreshOnlineStateAsync(stoppingToken).ConfigureAwait(false); + await _sources.RefreshOnlineStateAsync(forceRefresh: true, stoppingToken).ConfigureAwait(false); _transfers.NotifyAvailability(); await _sync.TryAutoRunAsync(stoppingToken).ConfigureAwait(false); await _profiles.TryAutoRunAsync(stoppingToken).ConfigureAwait(false); diff --git a/src/Explorer.App/GitChangesWindow.xaml b/src/Explorer.App/GitChangesWindow.xaml new file mode 100644 index 0000000..3a13ac0 --- /dev/null +++ b/src/Explorer.App/GitChangesWindow.xaml @@ -0,0 +1,80 @@ + + + +