Listing each branch and its last revision's date in Git

后端 未结 11 715
傲寒
傲寒 2020-11-29 15:07

I need to delete old and unmaintained branches from our remote repository. I\'m trying to find a way with which to list the remote branches by their last modified date, and

相关标签:
11条回答
  • 2020-11-29 15:35

    I did a simple alias, not sure if this is what exactly asked, but it is simple

    I did this as i wanted to list all the branches not just my local branches, which above commands do only

    alias git_brs="git fetch && git branch -av --format='\''%(authordate)%09%(authordate:relative)%09%(refname)'\'"

    You can pipe above to grep origin to get only origins

    This lists all the branches along with the last date modified, helps me decide which one i should pull for latest version

    This results in below type of display

    Wed Feb 4 23:21:56 2019 +0230   8 days ago      refs/heads/foo
    Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/heads/master
    Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/heads/bar
    Wed Feb 11 16:34:00 2019 +0230  2 days ago      refs/heads/xyz
    Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/HEAD
    Mon Feb 9 12:19:33 2019 +0230   4 days ago      refs/remotes/origin/foo
    Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/master
    Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/bar
    Tue Feb 3 12:18:04 2019 +0230   10 days ago     refs/remotes/origin/xyz
    

    Try and let me know if it helped, happy gitting

    0 讨论(0)
  • 2020-11-29 15:42

    commandlinefu has 2 interesting propositions:

    for k in `git branch | perl -pe s/^..//`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r
    

    or:

    for k in `git branch | sed s/^..//`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k --`\\t"$k";done | sort
    

    That is for local branches, in a Unix syntax. Using git branch -r, you can similarly show remote branches:

    for k in `git branch -r | perl -pe 's/^..(.*?)( ->.*)?$/\1/'`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r
    

    Michael Forrest mentions in the comments that zsh requires escapes for the sed expression:

    for k in git branch | perl -pe s\/\^\.\.\/\/; do echo -e git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1\\t$k; done | sort -r 
    

    kontinuity adds in the comments:

    If you want to add it your zshrc the following escape is needed.

    alias gbage='for k in `git branch -r | perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | head -n 1`\\t$k; done | sort -r'
    

    In multiple lines:

    alias gbage='for k in `git branch -r | \
      perl -pe '\''s/^..(.*?)( ->.*)?$/\1/'\''`; \
      do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k -- | \
         head -n 1`\\t$k; done | sort -r'
    

    Note: n8tr's answer, based on git for-each-ref refs/heads is cleaner. And faster.
    See also "Name only option for git branch --list?"

    More generally, tripleee reminds us in the comments:

    • Prefer modern $(command substitution) syntax over obsolescent backtick syntax.

    (I illustrated that point in 2014 with "What is the difference between $(command) and `command` in shell programming?")

    • Don't read lines with for.
    • Probably switch to git for-each-ref refs/remote to get remote branch names in machine-readable format
    0 讨论(0)
  • 2020-11-29 15:46

    I made two variants, based on VonC's answer.

    My first variant:

    for k in `git branch -a | sed -e s/^..// -e 's/(detached from .*)/HEAD/'`; do echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`;done | sort | column -t -s "|"
    

    This handles local and remote branches (-a), handles detached-head state (the longer sed command, though the solution is kind of crude -- it just replaces the detached branch info with the keyword HEAD), adds in the commit subject (%s), and puts things into columns via literal pipe characters in the format string and passing the end result to column -t -s "|". (You could use whatever as the separator, as long as it's something you don't expect in the rest of the output.)

    My second variant is quite hacky, but I really wanted something that still has an indicator of "this is the branch you're currently on" like the branch command does.

    CURRENT_BRANCH=0
    for k in `git branch -a | sed -e 's/\*/CURRENT_BRANCH_MARKER/' -e 's/(detached from .*)/HEAD/'`
    do
        if [ "$k" == 'CURRENT_BRANCH_MARKER' ]; then
            # Set flag, skip output
            CURRENT_BRANCH=1
        elif [ $CURRENT_BRANCH == 0 ]; then
            echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset$k |%s" $k --`
        else
            echo -e `git log -1 --pretty=format:"%Cgreen%ci |%Cblue%cr |%Creset* %Cgreen$k%Creset |%s" $k --`
            CURRENT_BRANCH=0
        fi
    done | sort | column -t -s "|"
    

    This turns the * that marks the current branch into a keyword, and when the loop body sees the keyword it instead sets a flag and outputs nothing. The flag is used to indicate that an alternate formatting should be used for the next line. Like I said, it is totally hacky, but it works! (Mostly. For some reason, my last column is getting outdented on the current branch line.)

    0 讨论(0)
  • 2020-11-29 15:46

    In PowerShell, the following shows branches on the remote that are already merged and at least two weeks old (the author:relative format starts displaying weeks instead of days at two weeks):

    $safeBranchRegex = "origin/(HEAD|master|develop)$";
    $remoteMergedBranches = git branch --remote --merged | %{$_.trim()};
    git for-each-ref --sort='authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/remotes | ?{$_ -match "(weeks|months|years) ago" -and $_ -notmatch "origin/(HEAD|master|qa/)"} | %{$_.substring($_.indexof("origin/"))} | ?{$_ -in $remoteMergedBranches}
    
    0 讨论(0)
  • 2020-11-29 15:47

    Or you can use my PHP script, https://gist.github.com/2780984

    #!/usr/bin/env php
    <?php
        $local = exec("git branch | xargs $1");
        $lines = explode(" ", $local);
        $limit = strtotime("-2 week");
        $exclude = array("*", "master");
        foreach ($exclude as $i) {
            $k = array_search($i, $lines);
            unset($lines[$k]);
        }
        $k = 0;
        foreach ($lines as $line) {
            $output[$k]['name'] = $line;
            $output[$k]['time'] = exec('git log '.$line.' --pretty=format:"%at" -1');
            if ($limit>$output[$k]['time']) {
                echo "This branch should be deleted $line\n";
                exec("git branch -d $line");
            }
            $k++;
        }
    ?>
    
    0 讨论(0)
  • 2020-11-29 15:48

    Building off of Olivier Croquette, I like using a relative date and shortening the branch name like this:

    git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads
    

    Which gives you output:

    21 minutes ago  nathan/a_recent_branch
    6 hours ago        master
    27 hours ago    nathan/some_other_branch
    29 hours ago    branch_c
    6 days ago      branch_d
    

    I recommend making a Bash file for adding all your favorite aliases and then sharing the script out to your team. Here's an example to add just this one:

    #!/bin/sh
    
    git config --global alias.branches "!echo ' ------------------------------------------------------------' && git for-each-ref --sort='-authordate:iso8601' --format=' %(authordate:relative)%09%(refname:short)' refs/heads && echo ' ------------------------------------------------------------'"
    

    Then you can just do this to get a nicely formatted and sorted local branch list:

    git branches
    
    0 讨论(0)
提交回复
热议问题