├── .gitignore ├── LICENSE ├── README.md └── git-size /.gitignore: -------------------------------------------------------------------------------- 1 | *.ignoreme 2 | .idea 3 | abc* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Paul Hammant, 2016 (with an intention to donate to the Git project) 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git sub-command for calculating the size of a repo/clone (history, ignored, checkout, etc) 2 | 3 | This is a Bash command that, if in your path, will be part of the git command ecosystem 4 | 5 | # Installation 6 | 7 | Mac and Linux compatible. 8 | 9 | 1. Copy `git-size` to `/usr/local/bin/` or `/usr/bin/` as applicable 10 | 2. make it executable 'chmod +x /usr/local/bin/git-size', if it wasn't already. 11 | 12 | OR [via the Mac's homebrew](https://github.com/paul-hammant/homebrew-tap) 13 | 14 | # Using git size 15 | 16 | ``` 17 | $ git clone git@github.com:git/git.git 18 | # [...] 19 | $ cd git 20 | $ git size 21 | /scm/oss/git: git size: 22 | .git folder: 6.7M 23 | checkout: 29.4M 24 | ignored: 0K 25 | everything: 36M 26 | ``` 27 | 28 | If you'd done the clone with --no-checkout, the 29MB would have been saved, and the 36M would be closer to 6.7M. 29 | 30 | If you ran a build, 0B would be replaced with a few megabytes, as all that stuff isn't to be checked in (it is typically ignored). 31 | 32 | ## CSV output 33 | 34 | ``` 35 | $ git clone git@github.com:git/git.git 36 | # [...] 37 | $ cd git 38 | $ git size --csv 39 | /scm/oss/git, 6812, 30176, 0, 36988 40 | $ git size --csv --csv-headers 41 | directory_name,dot_git_folder_size,checkout_size,ignored_size,everything_size 42 | /scm/oss/git,6812,30176,0,36988 43 | ``` 44 | 45 | ## help 46 | 47 | ``` 48 | $ git size --help 49 | Usage (v1.0.6): 50 | git size --csv --csv-headers --kilobytes DIRNAME 51 | DIRNAME is optional - defaults to current directory 52 | --csv or -c: output as csv format (optional) 53 | --csv-headers or -H: header row for CSV output (optional) 54 | --sunburst or -s: generate hyperlink for sunburst visual (optional) 55 | --sunburst-html or -sh: generate HTML for sunburst visual (optional) 56 | --absolute-paths or -ap: show absolute paths rather than relative (optional) 57 | --recursive or -r: recurse looking for git clones/repos (always set for CSV output, optional) 58 | --kilobytes or -k: kilobyte blocks instead of human units (always set for CSV output, optional) 59 | ``` 60 | 61 | # LICENSE 62 | 63 | Copyright (c) 2016 Paul Hammant 64 | 65 | Also simplified BSD 2-clause licensed (see LICENSE) 66 | 67 | # Contribtions 68 | 69 | Contributions welcome via pull-request. 70 | -------------------------------------------------------------------------------- /git-size: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage(){ 4 | echo "Usage (v1.0.6):" 5 | echo " git size --csv --csv-headers --kilobytes DIRNAME" 6 | echo " DIRNAME is optional - defaults to current directory" 7 | echo " --csv or -c: output as csv format (optional)" 8 | echo " --csv-headers or -H: header row for CSV output (optional)" 9 | echo " --sunburst or -s: generate hyperlink for sunburst visual (optional)" 10 | echo " --sunburst-html or -sh: generate HTML for sunburst visual (optional)" 11 | echo " --absolute-paths or -ap: show absolute paths rather than relative (optional)" 12 | echo " --recursive or -r: recurse looking for git clones/repos (always set for CSV output, optional)" 13 | echo " --kilobytes or -k: kilobyte blocks instead of human units (always set for CSV output, optional)" 14 | exit 1 15 | } 16 | 17 | function kbytes_for_humans { 18 | local -i bytes=$1; 19 | if [[ $bytes -lt 1024 ]]; then 20 | echo "${bytes}" 21 | elif [[ $bytes -lt 1048576 ]]; then 22 | kbytes=$(echo "scale=1; $bytes / 1024" | bc | sed 's/\.0//') 23 | echo "${kbytes}K" 24 | elif [[ kbytes -lt 1073741824 ]]; then 25 | megs=$(echo "scale=1; $bytes / (1024^2)" | bc | sed 's/\.0//') 26 | echo "${megs}M" 27 | else 28 | gigs=$(echo "scale=1; $bytes / (1024^3)" | bc | sed 's/\.0//') 29 | echo "${gigs}G" 30 | fi 31 | } 32 | 33 | function sum_files { 34 | ssize="0" 35 | while read -r line; do 36 | if [[ ! -z "$line" ]]; then 37 | fsize=$(du -k -d0 "$line" | tail -1 | cut -f 1) 38 | ssize=$((ssize + fsize)) 39 | fi 40 | done <<< "$1" 41 | echo $ssize 42 | } 43 | 44 | process_single () { 45 | dir="$1" 46 | cd "$orig_directory" 47 | if [ "$absolute_paths" -eq "1" ]; then 48 | dir=$(realpath "$dir") 49 | fi 50 | cd "$dir" 51 | 52 | # Can only go ahead if a git repo 53 | not_a_git_repo=$(git status . 2>&1 | grep "Not a git repository" | wc -l) 54 | if [ "$not_a_git_repo" -gt "0" ]; then 55 | echo "Directory $dir isn't a Git repository/clone, can't run 'git size' there" 56 | exit 1 57 | fi 58 | 59 | total_size=$(du $fmt -d0 . | cut -f 1 | sed 's/\.0//') 60 | 61 | git ls-files --ignored --exclude-standard -o | perl -ne 'chomp(); if (-e $_) {print "$_\n"}' > .ls-files 62 | ignoredWithSizes=$(find . -printf "%p %s\n" | grep -F -f .ls-files) 63 | size_of_ignored=$(echo "$ignoredWithSizes" | awk '{sum+=$2} END {print sum}') 64 | if [ "$fmt" == "-h" ]; then 65 | size_of_ignored=$(kbytes_for_humans $size_of_ignored) 66 | fi 67 | 68 | git ls-files | perl -ne 'chomp(); if (-e $_) {print "$_\n"}' > .ls-files 69 | checkoutWithSizes=$(find . -printf "%p %s\n" | grep -F -f .ls-files) 70 | size_of_checkout=$(echo "$checkoutWithSizes" | awk '{sum+=$2} END {print sum}') 71 | if [ "$fmt" == "-h" ]; then 72 | size_of_checkout=$(kbytes_for_humans $size_of_checkout) 73 | fi 74 | rm .ls-files 75 | 76 | size_of_dot_git_folder=$(du $fmt -d0 .git | tail -1 | cut -f 1 | sed 's/\.0//') 77 | 78 | if [ "$csv_format" -eq "0" ]; then 79 | if [ $fmt == "-k" ]; then 80 | format=" (KB)" 81 | else 82 | format="" 83 | fi 84 | echo "$dir: git size${format}:" 85 | echo " .git folder: $size_of_dot_git_folder" 86 | echo " checkout: $size_of_checkout" 87 | echo " ignored: $size_of_ignored" 88 | echo " total: $total_size" 89 | else 90 | if [ "$csv_hdrs" -eq "1" ]; then 91 | echo "directory_name,dot_git_folder_size,checkout_size,ignored_size,total_size" 92 | fi 93 | echo "\"$dir\",$size_of_dot_git_folder,$size_of_checkout,$size_of_ignored,$total_size" 94 | fi 95 | } 96 | 97 | recursive_or_single () { 98 | if [ "$recursive" -eq "1" ]; then 99 | csv_format="1" 100 | fmt="-k" 101 | if [ "$csv_hdrs" -eq "1" ]; then 102 | echo "directory_name,dot_git_folder_size,checkout_size,ignored_size,total_size" 103 | csv_hdrs="0" 104 | fi 105 | git_folders=$(find "$directory" -type d -name .git | sed 's#/\.git$##' | sed 's#^\./##') 106 | while read -r d2; do 107 | if [[ ! -z "$d2" ]]; then 108 | process_single "$d2" 109 | fi 110 | done <<< "$git_folders" 111 | else 112 | # non-recursive 113 | process_single $directory 114 | fi 115 | } 116 | 117 | 118 | orig_directory=$(pwd) 119 | directory="." 120 | csv_format="0" 121 | fmt="-h" 122 | recursive="0" 123 | absolute_paths="0" 124 | csv_hdrs="0" 125 | sunburst="0" 126 | sunburst_html="0" 127 | leftOver="" 128 | until [ -z $1 ] 129 | do 130 | if [ "$1" == "--csv" ] || [ "$1" == "-c" ]; then 131 | csv_format="1" 132 | fmt="-k" 133 | shift 134 | elif [ "$1" == "--kilobytes" ] || [ "$1" == "-k" ]; then 135 | fmt="-k" 136 | shift 137 | elif [ "$1" == "--recursive" ] || [ "$1" == "-r" ]; then 138 | recursive="1" 139 | shift 140 | elif [ "$1" == "--sunburst" ] || [ "$1" == "-s" ]; then 141 | sunburst="1" 142 | csv_hdrs="0" 143 | csv_format="1" 144 | shift 145 | elif [ "$1" == "--sunburst-html" ] || [ "$1" == "-sh" ]; then 146 | sunburst_html="1" 147 | sunburst="1" 148 | csv_hdrs="0" 149 | csv_format="1" 150 | shift 151 | elif [ "$1" == "--absolute-paths" ] || [ "$1" == "-ap" ]; then 152 | absolute_paths="1" 153 | shift 154 | elif [ "$1" == "--csv-headers" ] || [ "$1" == "-H" ]; then 155 | if [ "$sunburst" == "0" ]; then 156 | csv_hdrs="1" 157 | fi 158 | shift 159 | elif [ "$1" == "--help" ] || [ "$1" == "-h" ]; then 160 | usage 161 | else 162 | directory="$1" 163 | if [ ! -d "$directory" ]; then 164 | echo "Error, directory $directory not found" 165 | usage 166 | fi 167 | directory=$(echo "$directory" | sed 's#/$##') 168 | shift 169 | if [ "$#" -gt "0" ]; then 170 | leftOver="${leftOver} $@" 171 | break 172 | fi 173 | fi 174 | done 175 | 176 | if [ ! -z "${leftOver// }" ]; then 177 | echo "Unrecognized params/options: $leftOver" 178 | usage 179 | fi 180 | cd .. 181 | if [ "$sunburst" -eq "1" ]; then 182 | if [ "$sunburst_html" -eq "1" ]; then 183 | echo "
See Sunburst Chart" 190 | fi 191 | else 192 | recursive_or_single 193 | fi --------------------------------------------------------------------------------