- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 2.3k
 
Show active branch for recent repo #2005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show active branch for recent repo #2005
Conversation
| 
           I just tested this out locally and it took quite a while to render the menu when dealing with 76 recent repos (admittedly a lot but I'm sure others have more!). We should prioritise speed here given that the typical use case for opening the recent repos menu is to quickly switch to another repo (often the first repo in the list). There are a few things we could consider doing: I'm not really keen on option 3 just because it's one more thing we'd need to refresh in the background, and it sounds like it's pretty costly to keep things up to date. At the very least I think the two-phase rendering approach is a good idea. As for rendering the menu, I'd have three separate columns: one for name, one for branch info, and one for path, in that order. Some repo paths are really long so it's better to have those on the end. What are your thoughts? Also, not necessarily related to this PR, but at some point it would be cool if our recent repos panel was a fully-fledged panel where there were keybindings for pulling/fetching. If we find it's hard to do the double-render thing with the menu panel, it might be easier to just create a standalone repos panel (which still appears as a popup)  | 
    
          
 I wonder which part exactly takes up so long. You wouldn't happen to be in the mood for profiling, would you? 🥺 
 Out of the three it definitely sounds like the most reasonable. But I'm still a bit perplexed as to why is such a thing even necessary. 
 That was my initial approach, but I quickly realized I couldn't have three columns because all of the panels have 2 panels hardcoded, and this was a hack, basically. I'll do a more thorough analysis next time. 
 I mean I guess, but... I don't know, feels kinda icky fetching and pulling all willy-nilly from a different repo. I'll let it stew for a bit.  | 
    
          
 @jesseduffield how's this? Parallelized fetching the branches and storing it in  I tried it with   | 
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work, I hadn't come across sync.Map before. I've left some more feedback
        
          
                pkg/utils/formatting.go
              
                Outdated
          
        
      | } | ||
| return slices.Map(lo.Range(maxWidth-1), func(i int) int { | ||
| return slices.MaxBy(stringArrays, func(stringArray []string) int { | ||
| // the `cancel` button has only one column so this avoids a crash if maxWidth > 2 | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon that this function should be able to safely assume all the rows have the same number of columns. I would instead update the code that adds the cancel option to the menu to ensure it has the same number of columns as other rows.
Reason being that we want this function to catch bugs from elsewhere in the code that cause mismatched columns sizes
        
          
                pkg/gui/recent_repos_panel.go
              
                Outdated
          
        
      | 
               | 
          ||
| func (gui *Gui) getCurrentBranch(path string) string { | ||
| if branch, err := gui.os.Cmd.New( | ||
| fmt.Sprintf("git -C %s rev-parse --abbrev-ref HEAD", gui.os.Quote(path)), | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add .DontLog() to this because we typically only log git commands that change something.
| func (gui *Gui) handleCreateRecentReposMenu() error { | ||
| recentRepoPaths := gui.c.GetAppState().RecentRepos | ||
| 
               | 
          ||
| currentBranches := sync.Map{} | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's one hell of an improvement! Nice work. Nonetheless, it still takes about a second on my end for 77 repos. Given that people typically expect menus to open instantly for the sake of muscle-memory (e.g. I might go to the status panel, hit enter then immediately hit enter again to go to the previous repo), I reckon we need to find a way to first render the menu without branches, then after it's been rendered, re-render it with the branches. I admittedly don't know how to do this off the top of my head but for all we know it's very straight-forward. I can dig into this deeper if you want.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nonetheless, it still takes about a second on my end for 77 repos.
I'm really curious as to why is this the case. Is it always the same repo that's causing the issue or is something else amidst?
I reckon we need to find a way to first render the menu without branches, then after it's been rendered, re-render it with the branches.
That might look a bit janky if the branch name is the middle column, since we don't know the exact width of the longest branch, unless the second render shows both the branches and the paths.
I admittedly don't know how to do this off the top of my head but for all we know it's very straight-forward. I can dig into this deeper if you want.
I'd like to take a stab at it first then if I don't manage to find anything out I'll tug at your sleeve, deal? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure which repo is the culprit, but even if it is a random repo causing the issue, I reckon it's better to just assume that some users are going to have their repo branches load slower than others, so we should try to make it smooth for everyone.
It might look a bit janky but I think it should be fine: users are typically going to be looking at the left column for the actual repo name so at least that will remain unchanged.
deal? :)
Deal :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should try to make it smooth for everyone.
Of course, couldn't agree more, I was just curious because I'm stumped, is all 😄
        
          
                pkg/gui/recent_repos_panel.go
              
                Outdated
          
        
      | wg := sync.WaitGroup{} | ||
| wg.Add(len(recentRepoPaths[1:])) | ||
| 
               | 
          ||
| for _, path := range recentRepoPaths[1:] { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we assign recentRepoPaths[1:] to a new variable so that we don't need to do the [1:] more than once?
But non-git directories should
Split recent repo menu into three columns
          
 Would you kindly test once more? :)  | 
    
| 
           @mark2185 THE ABSOLUTE MADMAN. Nice!!  | 
    
        
          
                pkg/gui/recent_repos_panel.go
              
                Outdated
          
        
      | } | ||
| } | ||
| 
               | 
          ||
| return "HEAD" | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it actually mean if we reach here? Does it meant that there is no branch and the repo is also not on a detached head? It might be better to make it clear e.g. 'not on branch' or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that:
- there were either errors along the way (shouldn't happen, the paths are verified 
gitrepos for sure, unless reading the file fails) - or that repo is in 
detached HEADstate 
I could put the short SHA here, actually.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah that works for me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, it appears that currently the entire SHA was printed instead of HEAD.
So, HEAD will appear only if there's an error with reading the file.
But I presume we still don't need the entire SHA, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we know that it is indeed a SHA then yeah we can truncate it. There's a helper method for that that we use when rendering commits.
If there's an error reading a file we're better off saying 'unknown branch'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a helper method for that that we use when rendering commits.
I think fileContent[:8] should suffice? It just contains the hash.
If there's an error reading a file we're better off saying 'unknown branch'
Good point. I18n needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I18n needed?
Just this tidbit remains, but I presume you're gonna say "Yes, of course!" :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah yes, of course! i18n is indeed needed
| 
               | 
          ||
| func isDirectoryAGitRepository(dir string) (bool, error) { | ||
| info, err := os.Stat(filepath.Join(dir, ".git")) | ||
| return info != nil && info.IsDir(), err | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we removing this because the path may not actually be a directory? If so we should change the function / arg names
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The arg is the path to the repo which is definitely a dir.
The <dir>/.git may be a:
- directory ( ordinary git repository )
 - file ( an additional worktree git repository )
 
It's a repo whichever way you look at it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ah cool, that makes sense
| 
           Code looks good to me  | 
    
| 
           great work 🚀  | 
    
This should close #1949.
It shows
HEADif the repo is indetached HEADstate, but I guess showing the branch name when not indetached HEADstate is better than nothing.