Version 1.2.0 of my Compose Desktop git repository...
# feed
r
Version 1.2.0 of my Compose Desktop git repository management tool was released. Thanks to some users here for early feedback, this version got some Mac platform-specific scaling fixes, improvements to worktree handling, and some bug fixes and general UX improvements. https://github.com/rocketraman/gitvantage/releases/tag/v1.2.0
K 2
d
I added 37 repos to it, and it became VERY slow and the ui is getting stuck... @rocketraman
r
@dave08 That's odd, I have 36 in mind and it is working fine. Do you have any repos that are particularly large or unusual in any way? I have identified some things that shouldn't be on the UI thread -- will fix and see if that solves your problem. But in the meantime, can you bisect your repo list and see if we can narrow it down to a specific repo that is the problem? Also: are any of your added repos on a network filesystem? e.g. NFS/SMB/sshfs or iCloud? When you notice the freeze is there anything going on in one of the repos? A build or npm install or anything like that? Could be an issue with filesystem watches.
@dave08 Also I don't use Mac regularly, but Claude suggests:
sample <pid>
and Instruments' Time Profiler attach to the shipped binary with no build flags, and a spindump during a freeze will show the blocked UI thread directly.
d
the ui isn't really responding... it would be very painful to start trying out things... also, when selecting one card the remove... in red means remove from the app not from the fs right? (maybe there should be some descriptions on hover for various buttons...) no network fs. most aren't be actively changed (only one or two at a time) I could maybe run those as soon as I have a chance...
r
Yes, remove in red just removes from GV, not from the filesystem. Yeah that should be clear from a tooltip or something. Let me try out some things. If you are willing to help debug a bit, one thing you could try is make a backup of the JSON config file
.config/gitvantage/registry.json
. Then you can bisect via that by deleting half the repos from the config file, seeing if the problems still reproduces, if yes, delete the other half, etc.
@dave08 Can you run from source with a
./gradlew run
? If so, can you try it with the latest code in the repo and see if your issue reproduces? If yes, please run it with env var
GITVANTAGE_PERF=1
which should report some performance counters to standard output.
d
gradlew run didn't start anything... it just printed this. @rocketraman
Copy code
> Task :run
Aug 18, 2026 12:30:56 PM dev.nucleusframework.notification.NotificationCenter isAvailable_delegate$lambda$0
WARNING: Notifications require a packaged .app bundle with a bundle identifier. Use ./gradlew runDistributable or ./gradlew runGraalvmNative instead of ./gradlew run.
Error was captured in composition.
java.lang.NullPointerException
        at androidx.compose.ui.res.ClassLoaderResourceLoader.load(Resources.desktop.kt:59)
        at androidx.compose.ui.res.Resources_desktopKt.openResource(Resources.desktop.kt:50)
        at androidx.compose.ui.res.PainterResources_desktopKt.rememberBitmapResource(PainterResources.desktop.kt:115)
        at androidx.compose.ui.res.PainterResources_desktopKt.painterResource(PainterResources.desktop.kt:61)
        at com.gitvantage.ui.ComposableSingletons$MainKt.lambda__1831394558$lambda$0$5(Main.kt:113)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.window.NucleusDecoratedWindowThemeKt.NucleusDecoratedWindowTheme$lambda$0(NucleusDecoratedWindowTheme.kt:45)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.window.NucleusDecoratedWindowThemeKt.NucleusDecoratedWindowTheme(NucleusDecoratedWindowTheme.kt:40)
        at com.gitvantage.ui.ComposableSingletons$MainKt.lambda__1831394558$lambda$0(Main.kt:104)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:131)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0$0$0(TaoLauncher.kt:51)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0$0(TaoLauncher.kt:39)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:428)
        at dev.nucleusframework.application.ProvideNucleusSystemThemeKt.ProvideNucleusSystemTheme(ProvideNucleusSystemTheme.kt:27)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0(TaoLauncher.kt:38)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:131)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend$lambda$0$0(TaoApplicationCompose.kt:83)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend$lambda$0(TaoApplicationCompose.kt:79)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.internal.Expect_jvmKt.invokeComposable(Expect.jvmAndAndroid.kt:26)
        at androidx.compose.runtime.GapComposer.doCompose-aFTiNEg(GapComposer.kt:2643)
        at androidx.compose.runtime.GapComposer.composeContent--ZbOJvo$runtime(GapComposer.kt:2545)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:895)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1178)
        at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:732)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:699)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend(TaoApplicationCompose.kt:72)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
        at dev.nucleusframework.window.tao.dispatch.TaoMainDispatcher.pump(TaoMainDispatcher.kt:285)
        at dev.nucleusframework.window.tao.TaoApplication$EventDispatcher.onEvent(TaoApplication.kt:139)
Exception in thread "Thread-2" java.lang.NullPointerException
        at androidx.compose.ui.res.ClassLoaderResourceLoader.load(Resources.desktop.kt:59)
        at androidx.compose.ui.res.Resources_desktopKt.openResource(Resources.desktop.kt:50)
        at androidx.compose.ui.res.PainterResources_desktopKt.rememberBitmapResource(PainterResources.desktop.kt:115)
        at androidx.compose.ui.res.PainterResources_desktopKt.painterResource(PainterResources.desktop.kt:61)
        at com.gitvantage.ui.ComposableSingletons$MainKt.lambda__1831394558$lambda$0$5(Main.kt:113)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.window.NucleusDecoratedWindowThemeKt.NucleusDecoratedWindowTheme$lambda$0(NucleusDecoratedWindowTheme.kt:45)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.window.NucleusDecoratedWindowThemeKt.NucleusDecoratedWindowTheme(NucleusDecoratedWindowTheme.kt:40)
        at com.gitvantage.ui.ComposableSingletons$MainKt.lambda__1831394558$lambda$0(Main.kt:104)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:131)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0$0$0(TaoLauncher.kt:51)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0$0(TaoLauncher.kt:39)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:428)
        at dev.nucleusframework.application.ProvideNucleusSystemThemeKt.ProvideNucleusSystemTheme(ProvideNucleusSystemTheme.kt:27)
        at dev.nucleusframework.application.internal.TaoLauncher.run$lambda$0(TaoLauncher.kt:38)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:131)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend$lambda$0$0(TaoApplicationCompose.kt:83)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:408)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend$lambda$0(TaoApplicationCompose.kt:79)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:122)
        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.kt:52)
        at androidx.compose.runtime.internal.Expect_jvmKt.invokeComposable(Expect.jvmAndAndroid.kt:26)
        at androidx.compose.runtime.GapComposer.doCompose-aFTiNEg(GapComposer.kt:2643)
        at androidx.compose.runtime.GapComposer.composeContent--ZbOJvo$runtime(GapComposer.kt:2545)
        at androidx.compose.runtime.CompositionImpl.composeContent(Composition.kt:895)
        at androidx.compose.runtime.Recomposer.composeInitial$runtime(Recomposer.kt:1178)
        at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:732)
        at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:699)
        at dev.nucleusframework.window.tao.TaoApplicationComposeKt$taoApplication$2$2.invokeSuspend(TaoApplicationCompose.kt:72)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:34)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:100)
        at dev.nucleusframework.window.tao.dispatch.TaoMainDispatcher.pump(TaoMainDispatcher.kt:285)
        at dev.nucleusframework.window.tao.TaoApplication$EventDispatcher.onEvent(TaoApplication.kt:139)
        Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [dev.nucleusframework.window.tao.TaoFrameClock@65086dfc, StandaloneCoroutine{Cancelling}@4f0d426a, TaoMainDispatcher@129b391b]

BUILD SUCCESSFUL in 3s
r
@dave08 Fixed that, please try it again, commit
6c0eb11
d
MUCH better... now it might also be nice to have a way to fold sections like the stashes section and the worktree section (also on the cards...?). Or maybe be able to jump to according sections in the side pane?
๐Ÿ‘ 1
@rocketraman Are you planning a release soon? I'd be nice to not have to pull up a terminal every run. Also, it would be nice to have code highlighting (especially for kotlin) in the diff view and possibly a separate window for those diffs (when one wants to pull up multiple diffs). Also, grouping repos might be nice... I'm not sure if that was the intention of tagging, but the namespace part is a bit funny since it doesn't seem to be selectable.
r
I released v1.3.0 a few days ago and it contains the fixes for the perf problem you identified, plus some other random cleanup.
Also, it would be nice to have code highlighting (especially for kotlin) in the diff view and possibly a separate window for those diffs (when one wants to pull up multiple diffs)
Good suggestions, thanks.
Also, grouping repos might be nice... I'm not sure if that was the intention of tagging, but the namespace part is a bit funny since it doesn't seem to be selectable.
Yes, tags are the way to group repos. The namespace part allows you to tag in different dimensions, and thus group by these. For example: say you had tags
lang:kotlin
and
lang:python
(namespace
lang
) and you had tags
client:foo
,
client:bar
. Now, the "Group by" selector at the top (right next to the filter box) will allow you to group repos by "lang" or "client". You can as usual filter repos by tags as well (negative filters with shift click).
๐Ÿ‘๐Ÿผ 1
๐Ÿš€ 1
d
Another nice thing would be to be able to copy the path to the repo or worktree... sometimes you need to paste it into an llm.
๐Ÿ‘ 1
r
@dave08 @Sebastian Schuberth not sure if you guys are still using GitVantage or not, but FYI I released v1.4.0 with a few fixes for work trees, improvements in cross-platform "Open In" support and related configurability, and some other minor fixes and improvements.
๐Ÿ‘๐Ÿผ 1
s
I'm still using it! A little bit less than I should, as I'm a bit stuck in my workflow with my usual tools, but I'm excited about the new release! I'm watching the GitHub releases, but thanks for letting me know anyway ๐Ÿ™‚
d
I was also using it, it has nice features... but it starting getting vvery slow again on my mac...
r
@dave08 thanks for that feedback. Two questions: โ€ข Is it slow from launch, or does it degrade with uptime? โ€ข Is it the whole window (scroll/click lag), or specific actions (opening a repo, log, diff)? Can you run it with perf logging on, reproduce the issue, and then send me the performance log?
Copy code
GITVANTAGE_PERF=1 /Applications/GitVantage.app/Contents/MacOS/GitVantage 2> ~/gitvantage-perf.log
Also @dave08 try it with 1.4.0 because Nucleus shipped some file watcher improvements for MacOS.
@dave08 Did you have a chance to try that out?
d
I tried 1.4.0... still slow. I have a bunch of things to finish now, so I can't really play around w/ it, but your efforts are appreciated! I had to update a few projects manually recently and felt that GitVantage could have sped that up ๐Ÿ˜Š.
๐Ÿ‘ 1
r
Thanks @dave08, when you get a chance the performance log from 1.4.0 would be great. https://kotlinlang.slack.com/archives/C0BJ0GTE2/p1791895377023659?thread_ts=1786626014.648529&amp;cid=C0BJ0GTE2