├── README.md ├── git-ar ├── git-comm ├── git-finda ├── git-ig ├── git-iglist ├── git-logjson ├── git-releasenext ├── git-semnext ├── git-sign ├── git-ver ├── git-whyig └── useful-git-aliases.conf /README.md: -------------------------------------------------------------------------------- 1 | # Brett's Git Commands 2 | 3 | Just some simple git commands that made more sense as 4 | scripts than as aliases. 5 | 6 | ## Installation 7 | 8 | Clone this repo and copy or link the directory into your 9 | $PATH and call them like `git ar` or `git finda ci`. Make 10 | sure the scripts are executable. 11 | 12 | More complex commands will display usage instruction 13 | with `-h`. 14 | 15 | ## Dependencies 16 | 17 | Some scripts require external tools: 18 | 19 | - [gum] 20 | - [fzf] 21 | - [hub] 22 | 23 | All easily installed with Homebrew. 24 | 25 | ## Commands 26 | 27 | - `git ar` - Add all new files to staging and remove deleted files 28 | - `git comm []` - Pretty commit message input using [gum] 29 | - `git finda ` - Find a git alias using pattern matching 30 | - `git ig []` - Add contents of an ignore file from gitignore.io, uses [fzf] 31 | - `git iglist` - List all available ignore files 32 | - `git logjson` - Output a JSON-formatted git log 33 | - `git releasenext [major|minor|*patch]` - Creates a release using [hub] for the next semantic version (based on tags) 34 | - `git semnext [major|minor|*patch]` - Output the next semantic version number 35 | - `git sign` - Enable/disable GPG signing, assign key for repo or globally 36 | - `git ver` - Display the current semantic version (based on tags) 37 | - `git whyig` - Show ignored files and explain why/how they're ignored 38 | 39 | [gum]: https://github.com/charmbracelet/gum 40 | [fzf]: https://github.com/junegunn/fzf 41 | [hub]: https://github.com/mislav/hub 42 | 43 | ## Aliases 44 | 45 | `useful-git-aliases.conf` contains a collection of useful aliases. 46 | 47 | ### Usage 48 | 49 | Save `useful-git-aliases.conf` somewhere on your system. I 50 | like to put it in a folder I sync with Dropbox between my 51 | machines: 52 | 53 | ~/.local/share/git/useful-git-aliases.conf 54 | 55 | Edit ~/.gitconfig to include this file: 56 | 57 | vim ~/.gitconfig 58 | 59 | Include the path to the alias file: 60 | 61 | [include] 62 | path = ~/.local/share/git/useful-git-aliases.conf 63 | 64 | The file includes some aliases from [@durdn](https://www.durdn.com/blog/2012/11/22/must-have-git-aliases-advanced-examples/). 65 | 66 | 67 | Once installed, `git la` will list all your aliases. 68 | 69 | ## License 70 | 71 | This repo is licensed under the MIT License. 72 | 73 | See for details. 74 | -------------------------------------------------------------------------------- /git-ar: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Add all new files and remove all deleted files 4 | # 5 | # $ git ar 6 | 7 | update_git_index() { 8 | git ls-files -d -m -o -z --exclude-standard | xargs -0 git update-index --add --remove 9 | } 10 | 11 | update_git_index -------------------------------------------------------------------------------- /git-comm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Create a commit message using gum 4 | # Prompt for summary first, then list modified files and request details 5 | # 6 | # $ git comm [] 7 | # 8 | STATUS=$(git status --porcelain --untracked-files=no) 9 | 10 | if [[ -z "$STATUS" ]]; then 11 | echo "No changes to commit" 12 | else 13 | echo "Modified files:" 14 | echo -e "$STATUS" 15 | 16 | SUMMARY=$* 17 | if [[ -z $SUMMARY ]]; then 18 | SUMMARY=$(gum input --placeholder "Summary of this change" --width 50 --placeholder.foreground="240") 19 | fi 20 | 21 | if [[ -n "$SUMMARY" ]]; then 22 | DETAILS=$(gum write --placeholder "Details of this change" --width $(tput cols) --height 10 --show-cursor-line --show-line-numbers --char-limit 2000) 23 | git commit -a -m "$SUMMARY" -m "$DETAILS" 24 | else 25 | echo "Empty commit message, canceling" 26 | fi 27 | fi 28 | -------------------------------------------------------------------------------- /git-finda: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Search for a git alias 4 | # $ git finda 5 | # 6 | # Match with wildcard pattern 7 | # $ git finda '*' 8 | 9 | aliases = {} 10 | `git config --get-regexp alias`.split("\n").each do |line| 11 | name, value = line.split(" ", 2) 12 | aliases[name.sub(/^alias\./, "")] = value 13 | end 14 | 15 | class ::String 16 | def wildcard_to_rx 17 | /#{gsub(/\*/, ".*").gsub(/\?/, ".")}/ 18 | end 19 | 20 | def trunc(max) 21 | str = gsub(/ +/, " ") 22 | length = str.length 23 | if length > max 24 | "#{str[0..max-4]}..." 25 | else 26 | str 27 | end 28 | end 29 | end 30 | 31 | COLS = `tput cols`.to_i 32 | 33 | COLORS = { 34 | "red" => "\033[31m", 35 | "green" => "\033[32m", 36 | "yellow" => "\033[33m", 37 | "blue" => "\033[34m", 38 | "magenta" => "\033[35m", 39 | "cyan" => "\033[36m", 40 | "white" => "\033[37m", 41 | "boldwhite" => "\033[1;37m", 42 | "reset" => "\033[0;39m" 43 | } 44 | 45 | pattern = ARGV[0] ? ARGV[0].wildcard_to_rx : /.*/ 46 | 47 | aliases.filter! { |name, _| name.match(pattern) } 48 | 49 | longest_alias = aliases.keys.map(&:length).max 50 | 51 | if aliases.empty? 52 | puts "#{COLORS["red"]}No matching aliases found#{COLORS["reset"]}" 53 | exit 54 | end 55 | 56 | aliases.sort_by { |name, _| name }.each do |name, value| 57 | if name.match(pattern) 58 | color = COLORS["green"] 59 | else 60 | color = COLORS["red"] 61 | end 62 | 63 | formatted_alias = "#{color}#{name.ljust(longest_alias)}#{COLORS["boldwhite"]} #{value.trunc(COLS - longest_alias - 2)}#{COLORS["reset"]}" 64 | puts formatted_alias 65 | end -------------------------------------------------------------------------------- /git-ig: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Curls ignore files for various languages from gitignore.io 3 | # Appends to (or creates) .gitignore in top level directory 4 | # 5 | # $ git ig [] 6 | # 7 | 8 | __fzf() { 9 | local query list 10 | list=$1 11 | shift 12 | if test $# == 0; then 13 | echo -e "$list" | fzf 14 | else 15 | echo -e "$list" | fzf -q $@ 16 | fi 17 | } 18 | 19 | __ig() { 20 | # Retrieve a list of all available ignore files 21 | local list hasmatch result 22 | 23 | list=$(curl -L https://www.gitignore.io/api/list \ 24 | 2> /dev/null | tr ',' "\n") 25 | 26 | # 1 Argument required: name of language 27 | if test $# == 0; then 28 | result=$(__fzf "$list") 29 | else 30 | # See if there's an exact match in the list of ignore files 31 | hasmatch=$(echo -e "$list" | grep -ce "^$@$") 32 | if test $hasmatch == 0; then 33 | echo "Language not found: $@" 34 | result=$(__fzf "$list" $@) 35 | else 36 | result=$@ 37 | fi 38 | fi 39 | 40 | if [[ -z "$result" ]]; then 41 | echo "Missing target language" 42 | echo "Usage: git ig LANG" 43 | exit 0 44 | fi 45 | 46 | # cd to the top level of the current repository 47 | cd $(git rev-parse --show-toplevel) 48 | # Append API output to .gitignore 49 | curl -sSL http://www.gitignore.io/api/$result >> .gitignore 50 | echo "Appended ignore for $@ to $(pwd)/.gitignore" 51 | } 52 | 53 | __ig $@ 54 | -------------------------------------------------------------------------------- /git-iglist: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Retrieves a list of available ignore files from gitignore.io 3 | # If an argument is passed, use it as a search term to 4 | # narrow the list 5 | # 6 | # $ git iglist [] 7 | # 8 | __iglist() { 9 | local list=$(curl -L https://www.gitignore.io/api/list \ 10 | 2> /dev/null | tr ',' "\n") 11 | 12 | if [[ $# > 0 ]]; then 13 | list=$(echo -e "$list"|grep -i $@) 14 | fi 15 | 16 | echo -e "$list" 17 | } 18 | 19 | __iglist $@ 20 | -------------------------------------------------------------------------------- /git-logjson: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Output git log in JSON format 3 | # 4 | # $ git logjson 5 | # 6 | require 'json' 7 | 8 | log = `git log --pretty=format:'---%s%+ci%+h%+b___'`.strip 9 | entries = log.scan(/(?mi)(?<=^---)([\s\S]*?)(?=___)/) 10 | json = {'commits' => []} 11 | entries.each do |entry| 12 | lines = entry[0].split(/\n/) 13 | title = lines[0] 14 | date = lines[1] 15 | commit_hash = lines[2] 16 | note = '' 17 | if lines.length > 3 18 | note = lines[3..-1].join("\n").strip 19 | end 20 | json['commits'] << { 21 | 'title' => title, 22 | 'date' => date, 23 | 'hash' => commit_hash, 24 | 'note' => note 25 | } 26 | end 27 | 28 | print JSON.pretty_generate(json) 29 | -------------------------------------------------------------------------------- /git-releasenext: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Uses hub to create a release with next semantic version 3 | # 4 | # $ git releasenext [major|minor|*build] 5 | # 6 | 7 | # main class 8 | class ReleaseNext 9 | # initialize 10 | # @type can be :major, :minor, or :build 11 | # @raise 'Working directory dirty' if working directory is dirty 12 | # @raise 'Out of sync with origin' unless synced 13 | # @raise 'Not semantic versioning' unless current version is semantic 14 | # @param type [String] type of version to increment 15 | # @return [ReleaseNext] new ReleaseNext object 16 | def initialize(type = nil) 17 | type ||= 'build' 18 | @type = case type 19 | when /^maj/ 20 | :major 21 | when /^min/ 22 | :minor 23 | else 24 | :build 25 | end 26 | @branch = branch 27 | 28 | raise 'Working directory dirty' if dirty? 29 | 30 | raise 'Out of sync with origin' unless synced? 31 | end 32 | 33 | # check if working directory is dirty 34 | # @return true if working directory is dirty 35 | def dirty? 36 | stat = `git diff --shortstat 2> /dev/null | tail -n1`.strip 37 | return stat !~ /^\s*$/ 38 | end 39 | 40 | # get current branch 41 | # @return current branch name 42 | def branch 43 | `git remote show origin | sed -n '/HEAD branch/s/.*: //p'`.strip 44 | end 45 | 46 | # check if local branch is in sync with origin 47 | # @return true if local branch is in sync with origin 48 | def synced? 49 | status = `git rev-list --left-right --count origin/#{@branch}...#{@branch}`.strip.gsub(/[\s\t]/, '') 50 | return status =~ /00/ 51 | end 52 | 53 | # get current version number 54 | # @return current semantic version number 55 | def version 56 | current = `git tag| sed 's/[^0-9\.]//' | awk -F. '{printf("%04d.%04d.%04d\\n",$1,$2,$3);}'|sort|tail -1|awk -F. '{printf ("%d.%d.%d",$1 + 0, $2 + 0, $3 + 0);}'`.strip 57 | 58 | raise 'Not semantic versioning' unless current =~ /^\d+\.\d+\.\d+$/ 59 | current 60 | end 61 | 62 | # increment version number 63 | # @type can be :major, :minor, or :build 64 | # @return new semantic version number 65 | def next_version 66 | maj, min, build = version.split(/\./) 67 | 68 | case @type 69 | when :major 70 | maj.next! 71 | min = 0 72 | build = 0 73 | when :minor 74 | min.next! 75 | build = 0 76 | else 77 | build.next! 78 | end 79 | 80 | "#{maj}.#{min}.#{build}" 81 | end 82 | 83 | # create a release with the next version number 84 | def release 85 | n = next_version 86 | puts `hub release create -m "v#{n}" #{n}` 87 | puts `git pull` 88 | puts "Release v#{n} created successfully." # Added feedback on success 89 | end 90 | end 91 | 92 | if ARGV.length > 1 93 | puts "Usage: git releasenext [major|minor|*build]" 94 | Process.exit 1 95 | end 96 | 97 | rn = ReleaseNext.new(ARGV[0]) 98 | rn.release 99 | -------------------------------------------------------------------------------- /git-semnext: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # Get next semantic version 3 | # 4 | # $ git next [major|minor|*build] 5 | # 6 | type = ARGV[0] 7 | RX = /^v?(?\d+)\.(?\d+)\.(?\d+)(?
\S+)?/i
 8 | 
 9 | current = `git ver`
10 | 
11 | raise 'Not semantic versioning' unless current =~ RX
12 | 
13 | m = current.match(RX)
14 | major = m['major'].to_i
15 | minor = m['minor'].to_i
16 | inc = m['inc'].to_i
17 | pre = m['pre']
18 | 
19 | case type
20 | when /^maj/
21 |   major += 1
22 |   minor = 0
23 |   inc = 0
24 | when /^min/
25 |   minor += 1
26 |   inc = 0
27 | when /^(pat|inc)/
28 |   pre = ''
29 |   inc += 1
30 | else
31 |   if type =~ /^pre/
32 |     if pre.nil? || pre.empty?
33 |       inc += 1
34 |       pre = 'pre'
35 |     else
36 |       pre.next!
37 |     end
38 |   elsif pre && !pre.empty?
39 |     pre.next!
40 |   else
41 |     inc += 1
42 |   end
43 | end
44 | 
45 | $stdout.print "#{major}.#{minor}.#{inc}#{pre}"
46 | 


--------------------------------------------------------------------------------
/git-sign:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env ruby
 2 | # Set up GPG signing
 3 | #
 4 | # $ git sign [false|key]
 5 | #
 6 | # Add keys with
 7 | #   key: [GPG id, "description"]
 8 | available = {}
 9 | default_key = nil
10 | 
11 | `git config --global --get-regex "sign\.*\."`.strip.split("\n").each do |k|
12 |   type = k.match(/sign\.(?[^\.]+)\..*/)&.captures
13 |   next unless type
14 | 
15 |   available[type[0]] ||= {}
16 | 
17 |   key = k.match(/sign\.#{type[0]}\.key\s(?.*)/)&.captures
18 |   available[type[0]][:key] = key[0] if key
19 | 
20 |   id = k.match(/sign\.#{type[0]}\.id\s(?.*)/)&.captures
21 |   available[type[0]][:id] = id[0] if id
22 | 
23 |   default = k.match(/sign\.#{type[0]}\.default\s(.*)/)&.captures
24 |   default_key = type if default && default[1] =~ /^[ty]/i
25 | end
26 | 
27 | if available.empty?
28 |   puts 'No GPG signing keys found'
29 |   puts 'Please define keys in ~/.gitconfig'
30 |   puts
31 |   puts 'Example:'
32 |   puts
33 |   puts '[sign "GitHub"]'
34 |   puts '  key = g'
35 |   puts '  id = XXXXXXXXXXXX'
36 |   puts '  default = true'
37 |   Process.exit 1
38 | end
39 | 
40 | default_key ||= available.keys.first
41 | 
42 | if ARGV[0] =~ /^-*(h(elp)?|(ls|list)?)$/
43 |   puts "Set up GPG signing"
44 |   puts "Disable signing: git sign false"
45 |   available.each do |k, v|
46 |     puts "Sign with #{k}: git sign #{v[:key]}"
47 |   end
48 |   puts "Use '--global' as first argument to make change global"
49 |   Process.exit 0
50 | end
51 | 
52 | global = ''
53 | if ARGV[0] =~ /^-+g/
54 |   global = ' --global'
55 |   ARGV.shift
56 | end
57 | 
58 | if ARGV[0] =~ /^(fa|no)/
59 |   `git config#{global} commit.gpgSign false`
60 |   `git config#{global} tag.gpgSign false`
61 |   puts "Disabled GPG signing"
62 | else
63 |   key = ARGV[0] ? ARGV[0].downcase : default_key.downcase
64 |   type = nil
65 |   id = nil
66 |   available.each do |k, v|
67 |     next unless v[:key].downcase == key || k.downcase == key
68 | 
69 |     type = k
70 |     id = v[:id]
71 |   end
72 |   raise "No key found for #{ARGV[0]}" unless id
73 | 
74 |   `git config#{global} user.signingkey #{id}`
75 | 
76 |   `git config#{global} commit.gpgSign true`
77 |   `git config#{global} tag.gpgSign true`
78 |   puts "Enabled GPG signing and set signing key to #{type} ID (#{id})"
79 | end


--------------------------------------------------------------------------------
/git-ver:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Show current git version based on tags
3 | #
4 | # $ git ver
5 | # 1.2.3
6 | #
7 | git tag | sed 's/[^0-9\.]//' | awk -F. '{printf("%04d.%04d.%04d\n",$1,$2,$3);}' | sort | tail -1 | awk -F. '{printf ("%d.%d.%d",$1 + 0, $2 + 0, $3 + 0);}'
8 | 


--------------------------------------------------------------------------------
/git-whyig:
--------------------------------------------------------------------------------
  1 | #!/usr/bin/env ruby
  2 | # frozen_string_literal: true
  3 | 
  4 | # Show why files are ignored
  5 | # $ git whyig
  6 | 
  7 | VERSION = '1.0.1'
  8 | # Just including term-ansicolor by @flori and avoiding all the
  9 | # rigamarole of requiring multiple files when it's not a gem... - Brett
 10 | #
 11 | # ansicolor Copyright: Florian Frank
 12 | # License: 
 13 | # Home: 
 14 | module Term
 15 |   # The ANSIColor module can be used for namespacing and mixed into your own
 16 |   # classes.
 17 |   module ANSIColor
 18 |     # require 'term/ansicolor/version'
 19 | 
 20 |     # :stopdoc:
 21 |     ATTRIBUTES = [
 22 |       [:clear,   0],     # String#clear is already used to empty string in Ruby 1.9
 23 |       [:reset,   0],     # synonym for :clear
 24 |       [:bold,   1],
 25 |       [:dark,   2],
 26 |       [:italic, 3], # not widely implemented
 27 |       [:underline, 4],
 28 |       [:underscore, 4], # synonym for :underline
 29 |       [:blink, 5],
 30 |       [:rapid_blink, 6], # not widely implemented
 31 |       [:negative, 7], # no reverse because of String#reverse
 32 |       [:concealed, 8],
 33 |       [:strikethrough, 9], # not widely implemented
 34 |       [:black, 30],
 35 |       [:red, 31],
 36 |       [:green, 32],
 37 |       [:yellow, 33],
 38 |       [:blue, 34],
 39 |       [:magenta, 35],
 40 |       [:cyan, 36],
 41 |       [:white, 37],
 42 |       [:on_black, 40],
 43 |       [:on_red, 41],
 44 |       [:on_green, 42],
 45 |       [:on_yellow, 43],
 46 |       [:on_blue, 44],
 47 |       [:on_magenta, 45],
 48 |       [:on_cyan, 46],
 49 |       [:on_white, 47],
 50 |       [:intense_black, 90], # High intensity, aixterm (works in OS X)
 51 |       [:intense_red, 91],
 52 |       [:intense_green, 92],
 53 |       [:intense_yellow, 93],
 54 |       [:intense_blue, 94],
 55 |       [:intense_magenta, 95],
 56 |       [:intense_cyan, 96],
 57 |       [:intense_white, 97],
 58 |       [:on_intense_black, 100], # High intensity background, aixterm (works in OS X)
 59 |       [:on_intense_red, 101],
 60 |       [:on_intense_green, 102],
 61 |       [:on_intense_yellow, 103],
 62 |       [:on_intense_blue, 104],
 63 |       [:on_intense_magenta, 105],
 64 |       [:on_intense_cyan, 106],
 65 |       [:on_intense_white, 107]
 66 |     ].freeze
 67 | 
 68 |     ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
 69 |     # :startdoc:
 70 | 
 71 |     # Returns true if Term::ANSIColor supports the +feature+.
 72 |     #
 73 |     # The feature :clear, that is mixing the clear color attribute into String,
 74 |     # is only supported on ruby implementations, that do *not* already
 75 |     # implement the String#clear method. It's better to use the reset color
 76 |     # attribute instead.
 77 |     def support?(feature)
 78 |       case feature
 79 |       when :clear
 80 |         !String.instance_methods(false).map(&:to_sym).include?(:clear)
 81 |       end
 82 |     end
 83 | 
 84 |     # Returns true, if the coloring function of this module
 85 |     # is switched on, false otherwise.
 86 |     def self.coloring?
 87 |       @coloring
 88 |     end
 89 | 
 90 |     # Turns the coloring on or off globally, so you can easily do
 91 |     # this for example:
 92 |     #  Term::ANSIColor::coloring = STDOUT.isatty
 93 |     def self.coloring=(val)
 94 |       @coloring = val
 95 |     end
 96 |     self.coloring = true
 97 | 
 98 |     ATTRIBUTES.each do |c, v|
 99 |       eval <<~EODEFS
100 |         def #{c}(string = nil)
101 |           result = ''
102 |           result << "\e[#{v}m" if Term::ANSIColor.coloring?
103 |           if block_given?
104 |             result << yield
105 |           elsif string.respond_to?(:to_str)
106 |             result << string.to_str
107 |           elsif respond_to?(:to_str)
108 |             result << to_str
109 |           else
110 |             return result #only switch on
111 |           end
112 |           result << "\e[0m" if Term::ANSIColor.coloring?
113 |           result
114 |         end
115 |       EODEFS
116 |     end
117 | 
118 |     # Regular expression that is used to scan for ANSI-sequences while
119 |     # uncoloring strings.
120 |     COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m/.freeze
121 | 
122 |     # Returns an uncolored version of the string, that is all
123 |     # ANSI-sequences are stripped from the string.
124 |     def uncolored(string = nil) # :yields:
125 |       if block_given?
126 |         yield.to_str.gsub(COLORED_REGEXP, '')
127 |       elsif string.respond_to?(:to_str)
128 |         string.to_str.gsub(COLORED_REGEXP, '')
129 |       elsif respond_to?(:to_str)
130 |         to_str.gsub(COLORED_REGEXP, '')
131 |       else
132 |         ''
133 |       end
134 |     end
135 | 
136 |     class << self
137 |       # Returns an array of all Term::ANSIColor attributes as symbols.
138 |       def attributes
139 |         ATTRIBUTE_NAMES
140 |       end
141 |     end
142 |   end
143 | end
144 | 
145 | class WhyIgnore
146 |   include Term::ANSIColor
147 | 
148 |   def initialize
149 |     @ignores = get_ignores
150 |     @reasons = parse_ignores
151 |   end
152 | 
153 |   def get_ignores
154 |     Dir.chdir(`git rev-parse --show-toplevel`.strip)
155 |     `git check-ignore -v -- *`
156 |   end
157 | 
158 |   def parse_ignores
159 |     lines = @ignores.split(/\n/)
160 |     ignore_files = {}
161 |     lines.each do |line|
162 |       reason, line, pattern, file = line.match(/(\S+):(\d+):(.*?)\t(.*?)$/)[1,4]
163 |       ignore_files[reason] = [] unless ignore_files.key?(reason)
164 |       ignore_files[reason].push({ pattern: pattern, file: file, line: line })
165 |     end
166 |     ignore_files
167 |   end
168 | 
169 |   def print_reasons
170 |     @reasons.each do |parent, files|
171 |       puts "#{blue}#{parent}:"
172 |       files.each do |file|
173 |         puts "\t#{green}#{format('% 4d', file[:line])}: #{reset}#{intense_cyan}#{file[:file]} #{dark}#{white}(#{file[:pattern]})#{reset}"
174 |       end
175 |     end
176 |   end
177 | end
178 | 
179 | wi = WhyIgnore.new
180 | wi.print_reasons
181 | 


--------------------------------------------------------------------------------
/useful-git-aliases.conf:
--------------------------------------------------------------------------------
  1 | # ## Usage
  2 | #
  3 | # Usage for a typical user is easy.
  4 | #
  5 | # Save this file somewhere on your system. I like to put it
  6 | # in a folder I sync with Dropbox between my machines:
  7 | #
  8 | #      ~/.local/share/git/useful-git-aliases.conf
  9 | #
 10 | # Edit ~/.gitconfig to include this file:
 11 | #
 12 | #      vim ~/.gitconfig
 13 | #
 14 | # Include the path to the alias file:
 15 | #
 16 | #     [include]
 17 | #     path = ~/.local/share/git/useful-git-aliases.conf
 18 | #
 19 | ## License
 20 | #
 21 | # Created by Brett Terpstra
 22 | # This file is licensed under the MIT License.
 23 | # See  for details.
 24 | #
 25 | # Includes aliases from 
 26 | 
 27 | [alias]
 28 | 	init = init --template ~/.git_template
 29 | 
 30 | 	# add
 31 | 	a = add             # add
 32 | 	chunk = add --patch # stage commits chunk by chunk
 33 | 
 34 | 	# assume
 35 | 
 36 | 	assume = update-index --assume-unchanged           # assume file unchanged
 37 | 	unassume = update-index --no-assume-unchanged      # unassume file
 38 | 	assumed = "!git ls-files -v | grep ^h | cut -c 3-" # show assumed files
 39 | 
 40 | 	## Unassume all the assumed files
 41 | 	unassumeall = "!git assumed | xargs git update-index --no-assume-unchanged"
 42 | 
 43 | 	## assume all unchanged
 44 | 	assumeall = "!git st -s | awk {'print $2'} | xargs git assume"
 45 | 
 46 | 	# branch
 47 | 	b = branch -v                     # branch (verbose)
 48 | 	br = branch                       # branch shortcut
 49 | 
 50 | 	# checkout
 51 | 	co = checkout                 # checkout shortcut
 52 | 	dev = checkout develop        # checkout develop branch
 53 | 	discard = checkout --         # discard changes
 54 | 	main = checkout main          # checkout main branch
 55 | 	mast = checkout master        # checkout master branch
 56 | 	mine = checkout --ours        # resolve conflicts with local copy
 57 | 	nb = checkout -b              # create and switch to a new branch (mnemonic: "git new branch branchname...")
 58 | 	theirs = checkout --theirs    # resolve conflicts with remote copy
 59 | 
 60 | 	cl = clone                    # clone shortcut
 61 | 
 62 | 	# cherry pick
 63 |   	cp = cherry-pick
 64 | 	cpa = cherry-pick --abort     # abort the picking process
 65 | 	cpc = cherry-pick --continue  # continue the picking process
 66 | 	cpn = cherry-pick --no-commit # cherry-pick without making a commit
 67 | 
 68 | 	# commit
 69 | 	amend = commit --amend                 # amend your last commit
 70 | 	ammend = commit --amend                # Because I always forget how many `m`s
 71 | 	c = comm                               # commit with git-comm
 72 | 	ca = commit -am                        # commit all with message
 73 | 	ci = commit                            # commit file
 74 | 	cm = commit -m                         # commit with message
 75 |   	cam = commit --amend --message         # amend and edit the message.
 76 |   	caa = commit --amend --all             # amend all changes
 77 |   	caam = commit --amend --all --message  # amend all changes and edit the message
 78 | 	caane = commit --amend --all --no-edit # amend all changes without editing the message
 79 | 
 80 | 	# help
 81 | 	## Opens man page in VS Code
 82 | 	shelp = "!shelp() { MANWIDTH=80 MANPAGER='col -bx' git help \"$@\" | code - ;}; shelp"
 83 | 	whelp = help -w                        # Opens web-based man page
 84 | 
 85 | 	# log
 86 | 	bullets = log --pretty=format:\" * %s\" # Markdown bullet list of commit messages
 87 | 	changes = log --oneline --reverse       # List of commit messages with hash
 88 | 	fl = log -u                             # See all the commits related to a file, with the diff of the changes
 89 | 
 90 | 	## Pretty history graph
 91 | 	h = log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
 92 | 	l = log --graph --date=short            # history graph with short dates
 93 | 
 94 | 	## Log with changed files
 95 | 	ll = log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\" --name-status
 96 | 	dl = "!git ll -1"                       # show changed files for last commit
 97 | 
 98 | 	## Log with hash, relative date, committer, and message
 99 | 	short = log --pretty=format:\"%h %cr %cn %Cgreen%s%Creset\"
100 | 
101 | 	# merge
102 | 
103 |     ma = merge --abort    # merge abort - cancel the merging process
104 |     mc = merge --continue # continue the merging process
105 | 
106 | 	# misc
107 | 	cleancopy = !git archive $1 | tar -x -C "$2" # export a clean copy of repo
108 | 
109 | 	dc = diff --cached    # diff cached
110 | 
111 | 	## Show diff up to X commits back
112 | 	## $1 number of commits to diff back
113 | 	## $2 [optional] path to show diff for
114 | 	diffto = "!diffto() { local count=$1; shift; git diff HEAD~$count $*; }; diffto"
115 | 
116 | 	dump = cat-file -p            # dump file contents
117 | 	filelog = log -u              # show changes to a file
118 | 	f = "!git ls-files | grep -i" # find file path in codebase
119 | 	gr = grep -Ii                 # grep entire codebase for string
120 | 
121 | 	## Grep from root folder
122 | 	gra = "!f() { A=$(pwd) && TOPLEVEL=$(git rev-parse --show-toplevel) && cd $TOPLEVEL && git grep --full-name -In $1 | xargs -I{} echo $TOPLEVEL/{} && cd $A; }; f"
123 | 
124 | 	gt = "!gtcd() { cd $(git rev-parse --show-toplevel);}; gtcd" # cd to top level (go top)
125 | 	top = rev-parse --show-toplevel                              # Show top level folder of repo
126 | 	ignored = status --ignored                                   # show ignored files
127 | 
128 | 	la = "!git config -l | grep alias | cut -c 7-" # list all aliases
129 | 
130 | 	ls = ls-files
131 | 	lsi = ls-files --ignored --exclude-standard           # list ignored files
132 | 	lsio = ls-files --ignored --others --exclude-standard # list ignored and unstaged files
133 | 	mt = mergetool                                        # fire up the merge tool
134 | 	origin = remote show origin                           # show origin(s) for repo
135 | 	p = pull                     # pull shortcut
136 | 	pp = push                    # push shortcut
137 | 	pulld = pull origin develop  # pull develop branch
138 | 	pullm = pull origin main     # pull main branch
139 | 	pushd = push origin develop  # push develop branch
140 | 	pushm = push origin main     # push main branch
141 | 	rmc = "rm -r --cached"       # remove file from git cache
142 | 
143 | 	type = cat-file -t # show file type
144 | 
145 | 	## Undo X commits and create new branch
146 | 	## $1 new branch name
147 | 	## $2 number of commits to move to new branch
148 | 	undo = "!git branch $1 && git reset --hard HEAD~$2 && git switch $1"
149 | 
150 | 	what = whatchanged           # show commits and what files changed
151 | 
152 | 	## Rename branch as done-[branch]
153 | 	done = "!f() { git branch | grep "$1" | cut -c 3- | grep -v done | xargs -I{} git branch -m {} done-{}; }; f"
154 | 
155 | 	# rebase
156 | 	rb = rebase
157 | 	rba = rebase --abort              # rebase - abort the rebasing process
158 | 	rbc = rebase --continue           # rebase - continue the rebasing process
159 | 	rbs = rebase --skip               # rebase - skip the current patch
160 | 	rbi = rebase --interactive        # rebase - interactive rebase
161 | 
162 | 	# remotes
163 | 	r = remote -v                     # show remotes (verbose)
164 | 
165 | 	# reset
166 | 
167 | 	r = reset                         # basic reset
168 | 	r1 = reset HEAD^                  # reset head to last commit
169 | 	r2 = reset HEAD^^                 # reset head two commits back
170 | 	rh = reset --hard                 # hard reset
171 | 	rh1 = reset HEAD^ --hard          # erase changes back to last commit
172 | 	rh2 = reset HEAD^^ --hard         # erase changes back to parent of last commit
173 | 	uncommit = reset --soft HEAD^     # go back before last commit, with files in uncommitted state
174 | 	unstage = reset HEAD              # remove files from index (tracking)
175 | 
176 | 	# stash
177 | 	sa = stash apply                  # apply stash (restore changes)
178 | 	sd = stash drop                   # drop stashes (destory changes)
179 | 	sl = stash list                   # list stashes
180 | 	ss = stash save                   # stash changes
181 | 
182 | 	# status
183 | 	s = status      # status shortcut
184 | 	st = status -sb
185 | 	#            │└ short format
186 | 	#            └ show branch and tracking info
187 | 
188 | 	# submodules
189 | 	subinit = submodule update --init         # init submodules
190 | 	subup = submodule foreach git pull origin # update all submodules
191 | 
192 | 	# tags
193 | 	tags = tag -n1 -l                             # list all tags
194 | 	lasttag = describe --always --tag --abbrev=0  # show last tag
195 | 
196 | 	# Execute shell scripts in the top directory.
197 | 	exec = ! exec
198 | 
199 | 


--------------------------------------------------------------------------------