7

Is it possible to configure the ls command so that, when I use ls -l, it appends the git branch name after the directory name, if the directory is a git repository?

This way I can quickly find git repositories under the current directory as well as their working status.

Something like this:

-rw-rw-r--  1 michael michael    8 Aug 26 02:07 a-file
drwxrwxr-x  3 michael michael 4096 Aug 26 02:07 a-repo/ (master)
drwxrwxr-x  2 michael michael 4096 Aug 26 02:07 not-a-repo/

Note: I'm not looking to show git branch for the current directory or as part of the shell prompt, which I already know how.

Byte Commander
  • 110,243

4 Answers4

5

I wrote a little Bash function using mainly awk to process the output of ls and append git branch names to directories, if they are part of repositories.

Installation:

To install the function, simply copy the line below and append it to the end of your ~/.bashrc file. You have to source .bashrc after that or restart the shell session for the change to take effect.

lg (){ ls -alF "$@"|awk '{match($0,/^(\S+\s+){8}(.+)$/,f);b="";c="git -C \""f[2]"\" branch 2>/dev/null";while((c|getline g)>0){if(match(g,/^\* (.+)$/,a)){b="("a[1]")"}};close(c);print$0,b}';}

After that, you will have a new command lg available that behaves like the default ll alias (actually ls -alF), but with the appended current git branch.

Example usage:

Here is some example output, not the branch names in braces behind git1/ and git2/:

$ lg
total 48 
drwxrwxr-x 12 bytecommander bytecommander 4096 Aug 26 14:48 ./ 
drwxr-xr-x 74 bytecommander bytecommander 4096 Aug 26 15:30 ../ 
drwxrwxr-x  6 bytecommander bytecommander 4096 Aug 26 14:43 git1/ (master)
drwxrwxr-x  7 bytecommander bytecommander 4096 Aug 26 14:42 git2/ (develop)
drwxrwxr-x  4 bytecommander bytecommander 4096 Aug 26 14:45 no-git/ 
-rw-rw-r--  1 bytecommander bytecommander    0 Aug 26 14:42 regular-file 

The lg command still accepts all kinds of arguments, just like ls does. You can e.g. run lg -h, lg ~/projects, lg .. etc.

Updates:

  • Fixed issue with filenames containing spaces or starting with #.

Known bugs and drawbacks:

  • The output will not be colored unlike the default ls output (e.g. directories are blue, executables green, symlinks cyan, ...).
  • It can not handle file names with newline characters in them. They will be displayed, but no branch info is shown.
  • The ls output will always be correct and display information about the path you specify as argument (if any, otherwise current directory as default). However, the branch information for the ./ and ../ entries is always relative to the current working directory, not the specified directory.
  • If you run this inside a repository, every subdirectory will also get the branch appended. The function does not distinguish between repository root directories and any repository subdirectories.

If you encounter more problems or happen to know a solution for one of the listed issues, feel free to leave a comment.

Byte Commander
  • 110,243
1

OK... Seeing that there is no built-in way to do it, I went ahead and wrote my own Python program. You can get it with pip:

pip3 install mklibpy-bin

Currently only support Python3.

GitHub link

Paul
  • 7,194
0

I expanded the script form Byte Commander.

My version shows how many commits your branch is ahead or behind remote.

It also first fetches the changes.

lg() {
  ls -alF "$@"|awk '{
    match($0,/^(\S+\s+){8}(.+)$/,f);
    b="";
    d="";
    git -C "f[2]" fetch;
    c="git -C \""f[2]"\" branch -v 2>/dev/null";
    while((c|getline g)>0){
      if(match(g,/^\* (\S+)/,a)){
        b="("a[1]")";
      };
      if(match(g,/^\*(.*)\[(.*)ahead ([0-9]+)(.*)\]/,u)){
        e="+"u[2]" ";
        d=d e
      }
      if(match(g,/^\*(.*)\[(.*)behind ([0-9]+)(.*)\]/,v)){
        e="-"v[2]"";
        d=d e
      }
      if(d == "") {
        d="="
      }
    };
    close(c);
    print$0,b,d
  }';
}

Edit: fixed regex.

muru
  • 207,228
0

This is a bit of a wobbly work around, but it works for nautilus as well. If in branch 'main' of your git repository:

    echo 'branch main' > branch_main
    git add branch_main
    git commit

This creates a small file with the name 'branch_main' in the directory, adds it to staging and commits the change to your repositories branch. Repeat this process for all your branches.

    ls -l
    -rw-rw-r-- 1 username username    12 Jul  9 18:54  branch_main
    -rwxrwxr-x 1 username username 22303 Jul  9 18:54  code
    -rw-rw-r-- 1 username username  3493 Jun 22 10:04  README.md

nautilus screenshot

Edit: If you want to make sure the branch naming file is top of the list prepend with a 0 eg:

echo 'branch main' > 0_branch_main
$ ls -l
-rw-rw-r-- 1 user group 12 Jul 23 16:27 0_branch_main

If you feel that's too much typing just:

echo > 0_branch_main
$ ls -l
-rw-rw-r-- 1 user group  1 Jul 23 16:28 0_branch_main

and if that's just too many bytes of disk space try:

touch 0_branch_main
$ ls -l
-rw-rw-r-- 1 user group  0 Jul 23 16:28 0_branch_main