all repos — dotfiles @ 3668cec0ad0e05a9d43432250db33d27935c7b37

my *nix dotfiles

bin/git-vanity-sha (view raw)

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
#!/usr/bin/env ruby
require 'digest'

module VanitySha
  extend self

  COMMITTER_PATTERN = /^committer .* \<.*\> (?<timestamp>\d+)(?<timezone>.*$)/

  TIMESTAMP_DELTA_MAX = 10 * 24 * 60 * 60

  DELTAS = Enumerator.new do |enumerator|
    for i in 0..TIMESTAMP_DELTA_MAX
      enumerator << i
      enumerator << -i
    end
  end

  def get_commit_info()
    `git cat-file commit HEAD`
  end

  def extract_committer(commit_info)
    committer = commit_info
    .split("\n")
    .map {|line| line.match(COMMITTER_PATTERN)}
    .compact
    .first

    [committer.string, committer[:timestamp].to_i, committer[:timezone]]
  end

  def search(commit_info, hex_prefix)
    committer_line, commit_ts = extract_committer(commit_info)

    DELTAS.each do |delta|
      new_committer_line = committer_line.sub(commit_ts.to_s, (commit_ts + delta).to_s)
      new_commit = commit_info.sub(committer_line, new_committer_line)
      new_sha = get_sha(new_commit)
      return [delta, new_sha] if new_sha.start_with?(hex_prefix)
    end
    nil
  end

  def get_sha(commit_info)
    Digest::SHA1.hexdigest "#{commit_header(commit_info)}#{commit_info}"
  end

  def amend_commit(new_ts, original_tz)
    `LC_ALL=C GIT_COMMITTER_DATE=\"#{new_ts}#{original_tz}\" git commit --amend --no-edit`
  end

  def commit_header(commit_info)
    "commit #{commit_info.length}\0"
  end
end

if ARGV.length != 1 || ARGV[0].length < 1
  puts "usage: git vanity-sha prefix"
  puts "example: git vanity-sha CAFE"
  exit(1)
end

target_prefix = ARGV[0].downcase
original_commit_info = VanitySha.get_commit_info()
_, original_ts, original_tz = VanitySha.extract_committer(original_commit_info)

puts "Searching for new SHA...\n"

result = VanitySha.search(original_commit_info, target_prefix)

if result
  delta, sha = result
  new_ts = original_ts + delta

  puts "SHA found: #{sha.sub(target_prefix, "\e[32m#{target_prefix}\e[0m")}"
  puts "Change committer timestamp to #{Time.at(new_ts)}? This will amend your commit."
  print "(y/n): "

  if STDIN.gets.chomp == "y"
    VanitySha.amend_commit(new_ts, original_tz)
    puts "\n" + "-" * 47
    puts `git show --quiet --format=short HEAD`
  else
    puts "Aborting."
  end
else
  puts "Failed to generate a sha with prefix #{target_prefix}."
end