Jump to content
deanishe

Find, filter, open Git repositories

Recommended Posts

Alfred Git Repos Workflow
 
Browse, search and open Git repositories from within Alfred.
 
demo.gif
 
Download
 
Get the workflow from GitHub or Packal.
 
Usage
 
This workflow requires some configuration before use. See Configuration for details.

  • repos [<query>] — Show a list of your Git repos filtered by <query>
    • — Open selected repo in app_1 (see configuration)
    • ⌘+↩ — Open selected repo in app_2 (see configuration)
    • ⌥+↩ — Open selected repo in app_3 (requires configuration)
    • ^+↩ — Open selected repo in app_4 (requires configuration)
    • ⇧+↩ — Open selected repo in app_5 (requires configuration)
    • fn+↩ — Open selected repo in app_6 (requires configuration)
    • reposettings — Open settings.json in default JSON editor
  • reposupdate — Force workflow to update its cached list of repositories. (By default, the list will only be updated every 3 hours.)
  • reposhelp — Open this file in your browser

Configuration
 
Before you can use this workflow, you have to configure one or more folders in which the workflow should search for Git repos. The workflow uses find to search for .git directories, so you shouldn't add huge directory trees to it, and use the depth option to restrict the search depth. Typically, a depth of 2 will be what you want (i.e. search within subdirectories of specified directory, but no lower). Add directories to search to the search_dir array in settings.json (see below).
 
The default settings.json file looks like this:


{
  "app_1": "Finder",             // ↩ to open in this/these app(s)
  "app_2": "Terminal",           // ⌘+↩ to open in this/these app(s)
  "app_3": null,                 // ⌥+↩ to open in this/these app(s)
  "app_4": null,                 // ^+↩ to open in this/these app(s)
  "app_5": null,                 // ⇧+↩ to open in this/these app(s)
  "app_6": null,                 // fn+↩ to open in this/these app(s)
  "global_exclude_patterns": [],      // Exclude from all searches
  "search_dirs": [
{
  "path": "~/delete/this/example",   // Path to search. ~/ is expanded
  "depth": 2,                        // Search subdirs of `path`
  "name_for_parent": 1,              // Name Alfred entry after parent of `.git`. 2 = grandparent of `.git` etc.
  "excludes": [                      // Excludes specific to this path
    "tmp",                           // Directories named `tmp`
    "bad/smell/*"                    // Subdirs of `bad/smell` directory
  ]
}
  ]
}

 
This is my settings.json:
 

{
  "app_1": "Finder",
  "app_2": ["Finder", "Sublime Text", "SourceTree", "iTerm"],
  "app_3": "Sublime Text",
  "app_4": "SourceTree",
  "app_5": "iTerm",
  "app_6": "GitHub",
  "global_exclude_patterns": [],
  "search_dirs": [
    {
      "path": "~/Code"
    },
    {
      "path": "~/Sites"
    }
  ]
} 

  
Search Directories
 
Each entry in the search_dirs list must be a mapping.
 
Only path is required. depth will default to 2 if not specified. excludes are globbing patterns, like in .gitignore.
 
name_for_parent defaults to 1, which means the entry in Alfred's results should be named after the directory containing the .git directory. If you want Alfred to show the name of the grandparent, set name_for_parent to 2 etc.

This is useful if your projects are structured, for example, like this and src is the actual repo:
 

Code
  Project_1
    src
    other_stuff
  Project_2
    src
    other_stuff
  …
  …

 
Open in Applications
 
The applications specified by the app_N options are all called using open -a AppName path/to/directory. You can configure any application that can open a directory in this manner. Some recommendations are Sublime Text, SourceTree, GitHub or iTerm.
 

Note: As you can see from my settings.json, you can also set an app_N value to a list of applications to open the selected repo in more than one app at once:
 

…
  "app_2": ["Finder", "Sublime Text", "SourceTree", "iTerm"],
…

 
You can also use on a result to access Alfred's default File Actions menu.
 
License, Thanks
 
This workflow is released under the MIT Licence.
 
It uses the Alfred-Workflow and docopt libraries (both MIT Licence).
 
The icon is by Jason Long, from git-scm.com, released under the Creative Commons Attribution 3.0 Unported Licence.

Edited by deanishe

Share this post


Link to post

Cheeky update today.

 

It's very handy being able to open your Git repos in your editor, terminal, Finder and SCM app from Alfred. Now you can open the repo in all of them at once!

 

Just set an app_N option to a list of applications.

 

Also fixed a bug with app_6 / fn+↩ not working.

Share this post


Link to post

Is it normal if it takes long time to initialise the database? It says few seconds but it is still on that step.

Debug information:

Starting debug for 'Git Repos'
 
[ERROR: alfred.workflow.input.scriptfilter] Code 0: 17:10:19 repos.py:89 DEBUG    args: {u'--edit': False,
 u'--helpfile': False,
 u'--open': False,
 u'--update': False,
 u'<appnum>': None,
 u'<path>': None,
 u'<query>': u''}
17:10:19 background.py:215 DEBUG    Calling [u'/usr/bin/python', 'XXXXXXXXXXXXXXXX/background.pyc', u'update'] ...
17:10:19 background.py:220 DEBUG    Executing task `update` in background...
 
I've updated the settings file
 
Thanks

Share this post


Link to post

It depends on how big/deep the directories you specify are.
 
As noted in the OP, it uses the find command, so if you try to search a huge directory, like ~/, it will take a very, very long time.

Share this post


Link to post

If you have added a huge directory, it'd be better to replace it with multiple, more precise entries and/or fiddle with the depth parameter. It's not ideal to have the workflow crawl half the HD every few hours.

Share this post


Link to post

Another update today.

 

Now you can specify an arbitrary level of the file tree after which a repo is named in Alfred, e.g.:

 

If your directory looks like this:

Websites
    Project 1
        htdocs
            .git
        other_stuff
    Project 2
        htdocs
            .git
        other_stuff
    ...

You can set name_for_parent to 2, so the workflow shows "Project 1", "Project 2" etc. in Alfred, not "htdocs", "htdocs", "htdocs" etc.

Share this post


Link to post

Symbolic link to other directory seems to be not updated correctly.

 

jmjeong.com -> /Users/jmjeong/Dropbox/Documents/jmjeong.com

Share this post


Link to post

Indeed, it didn't follow symlinks (which is find's default behaviour).

 

I've added a new version (1.3) that does follow symlinks. Give that one a go.

Share this post


Link to post

Indeed, it didn't follow symlinks (which is find's default behaviour).

 

I've added a new version (1.3) that does follow symlinks. Give that one a go.

 

v1.3 follow symlinks, but global_exclude_pattern doesn't work. 

 

I set 'global_exclude_patterns": ["old*"] '  in settings.json, but old.jmjeong.com repo still appears. In the previous version, it doesn't

Share this post


Link to post

I didn't touch the code that filters the results, and you're not giving me much information to work with.

Could you at least post the full path and whether or not it's a symlink.

Share this post


Link to post
~/Dropbox/Apps/Alfred.alfredpreferences/workflows/user.workflow.BAF71062-A6BA-40A6-A1A0-09B8628D42E5 $ python update.py 

Excludes setting - [u'tmp', u'bad/smell/*', u'old*']

20:46:17 update.py:89 DEBUG    repo `alfred-extension` at `/Users/jmjeong/git/alfred-extension`

20:46:17 update.py:89 DEBUG    repo `bobby` at `/Users/jmjeong/git/bobby`

20:46:17 update.py:89 DEBUG    repo `CCMask` at `/Users/jmjeong/git/CCMask`

20:46:17 update.py:89 DEBUG    repo `cocos-samples` at `/Users/jmjeong/git/cocos-samples`

20:46:17 update.py:89 DEBUG    repo `django-appsales` at `/Users/jmjeong/git/django-appsales`

20:46:17 update.py:89 DEBUG    repo `Hyde` at `/Users/jmjeong/git/Hyde`

20:46:17 update.py:89 DEBUG    repo `ihd2` at `/Users/jmjeong/git/ihd2`

20:46:17 update.py:89 DEBUG    repo `iLink` at `/Users/jmjeong/git/iLink`

20:46:17 update.py:89 DEBUG    repo `jmjeong.com` at `/Users/jmjeong/git/jmjeong.com`

20:46:17 update.py:89 DEBUG    repo `old.jmjeong.com` at `/Users/jmjeong/git/old.jmjeong.com`

20:46:17 update.py:89 DEBUG    repo `old.jmjeong.github.com` at `/Users/jmjeong/git/old.jmjeong.github.com`

20:46:17 update.py:89 DEBUG    repo `PlanBeQuickAdd` at `/Users/jmjeong/git/PlanBeQuickAdd`

20:46:17 update.py:89 DEBUG    repo `todo.txt-ios` at `/Users/jmjeong/git/todo.txt-ios`

20:46:17 update.py:89 DEBUG    repo `vitae` at `/Users/jmjeong/git/vitae`

20:46:17 update.py:89 DEBUG    repo `weatherrecord.new` at `/Users/jmjeong/git/weatherrecord.new`

20:46:17 update.py:94 DEBUG    15 repos found in `/Users/jmjeong/git` in 3.95 s

20:46:17 workflow.py:970 DEBUG    Cached data saved at : /Users/jmjeong/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/net.deanishe.alfred-git-repos/repos.cache

20:46:17 update.py:141 INFO     15 repos found in 4.03 s

20:46:17 update.py:142 INFO     Update finished

 

old.jmjeong.com and old.jmjeong.github.com is not symbolic link. 

I thought these directories is not included in the result set because of 'excludes' setting. 

Share this post


Link to post

Thanks. I've looked into it, and frankly, I don't understand why the previous version did match old*: it shouldn't have.

*/old* would be the right pattern.

I'll see about including pathspec, which does proper .gitignore style matching.

Share this post


Link to post

Somehow I can't get it to recognise a simple git repo. My settings are:

{
  "app_1": "Finder", 
  "app_2": "Terminal", 
  "app_3": null, 
  "app_4": null, 
  "app_5": null, 
  "app_6": null, 
  "global_exclude_patterns": [], 
  "search_dirs": [
    {
      "path": "~/develop/_sites/_webhook/aesite"
    },
    {
      "path": "~/_arm-new/arm_lib/"
    }
  ]
}

It just sits there and says No known git repos..

 

Any idea? Thanks!

Share this post


Link to post

Have you tried forcing an update with reposupdate?

 

Can you try repos workflow:openlog, run reposupdate, then post or PM me the log?

 

(Alfred's debugger can't capture the output from the update script.)

Share this post


Link to post

Yes, I did a reposupdate a few times. Here is the last log snippet, which says no repos found..

15:34:17 repos.py:90 DEBUG    args: {u'--edit': False,
 u'--helpfile': False,
 u'--open': False,
 u'--update': True,
 u'<appnum>': None,
 u'<path>': None,
 u'<query>': None}
15:34:17 background.py:215 DEBUG    Calling [u'/usr/bin/python', '/Users/ae/Library/Application Support/Alfred 2/Alfred.alfredpreferences/workflows/user.workflow.A4C6E503-62A4-476D-8B6D-80CF94FE0DC8/workflow/background.pyc', u'update'] ...
15:34:18 background.py:259 DEBUG    Task `update` running
15:34:18 background.py:260 DEBUG    cmd : [u'/usr/bin/python', u'update.py']
15:34:18 background.py:220 DEBUG    Executing task `update` in background...
15:34:18 update.py:94 DEBUG    0 repos found in `/Users/ae/_arm-new/arm_lib/` in 0.02 s
15:34:18 update.py:94 DEBUG    0 repos found in `/Users/ae/develop/_sites/_webhook/aesite` in 0.04 s
15:34:18 workflow.py:970 DEBUG    Cached data saved at : /Users/ae/Library/Caches/com.runningwithcrayons.Alfred-2/Workflow Data/net.deanishe.alfred-git-repos/repos.cache
15:34:18 update.py:139 INFO     0 repos found in 0.10 s
15:34:18 update.py:140 INFO     Update finished
15:34:18 background.py:270 DEBUG    Task `update` finished
 

Share this post


Link to post

Can you run these commands:

find -L /Users/ae/_arm-new/arm_lib -type d -name .git -depth 1
find -L /Users/ae/develop/_sites/_webhook/aesite -type d -name .git -depth 1

Those are the commands the workflow will use to find your repos.

You might need to adjust the depth setting if the repos aren't direct subdirectories of the search_dirs.

Share this post


Link to post

Ok, one good one error. The first one finds the .git directory, the second my mistake, no repos in there. I removed the erronous path and setting the depth to 2 made of course no diff as it found the repos.. Any other ideas? Thanks for looking into this!

Share this post


Link to post

Is the git repo actually /Users/ae/_arm-new/arm_lib, not a subdirectory thereof?
 
The workflow only searches subdirectories of the search_dirs. It won't match the search_dirs themselves.
 
Can you change the path to /Users/ae/_arm-new instead, or is that directory tree too big?

Share this post


Link to post

Updated to 1.5.

  • Fixed a bug where repos with the same name would not be shown (by upgrading Alfred-Workflow)
  • Added ability to self-update from GitHub

Share this post


Link to post

Awesome workflow, found a "bug" though. If your json file is incorrect the workflow completely stops working without any visible errors. What's worse, you can't open the settings anymore since that also crashes ;)

Here's the backtrace:

[ERROR: alfred.workflow.action.script] Code 1: Traceback (most recent call last):
  File "repos.py", line 232, in <module>
    help_url=HELP_URL)
  File "workflow/workflow.py", line 944, in __init__
    self.check_update()
  File "workflow/workflow.py", line 2168, in check_update
    if not force and not self.settings.get('__workflow_autoupdate', True):
  File "workflow/workflow.py", line 1378, in settings
    self._default_settings)
  File "workflow/workflow.py", line 802, in __init__
    self._load()
  File "workflow/workflow.py", line 813, in _load
    for key, value in json.load(file_obj, encoding='utf-8').items():
  File "json/__init__.py", line 290, in load
    **kw)
  File "json/__init__.py", line 351, in loads
    return cls(encoding=encoding, **kw).decode(s)
  File "json/decoder.py", line 365, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "json/decoder.py", line 383, in raw_decode
    raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×