Skip to content

Instantly share code, notes, and snippets.

@felipec
Last active September 8, 2016 02:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save felipec/10551806 to your computer and use it in GitHub Desktop.
Save felipec/10551806 to your computer and use it in GitHub Desktop.
Tool to check and fix git-remote-hg marks
#!/usr/bin/env ruby
require 'json'
$fix = false
$verbose = false
$git_marks = {}
$r_marks = {}
$note_marks = {}
$mode = 'hg'
# Parse arguments
ARGV.delete_if do |cur|
next false if cur[0] != '-'
case cur
when /^-f$/, /^--fix$/
$fix = true
true
when /^-v$/, /^--verbose$/
$verbose = true
true
when /^-m(.+)$/, /^--mode=(.+)$/
$mode = $1
true
end
end
$remote = ARGV[0] || 'origin'
$dir = File.join('.git', $mode, $remote)
$git_file = File.join($dir, 'marks-git')
$r_file = File.join($dir, 'marks-' + $mode)
# TODO
$r_file = File.join($dir, 'marks-int') if $mode == 'bzr'
# Get git marks
File.open($git_file).each do |l|
if l =~ /:(\d+) (\h+)$/
$git_marks[$1.to_i] = $2
end
end
# Remove non commit objects
File.popen(%w[git cat-file --batch-check], 'r+') do |p|
$git_marks.each do |mark,id|
p.write(id + "\n")
if p.readline =~ /(\h+) (\w+)(?: (\d+))?/
type = $2
$git_marks.delete(mark) unless type == 'commit'
end
end
end
# Remove notes
File.popen(%W[git rev-list refs/notes/#{$mode}], 'r', :err => File::NULL) do |p|
p.each do |l|
mark, id = $git_marks.find { |_,x| x == l.chomp }
if mark
$git_marks.delete(mark)
$note_marks[mark] = id
end
end
end
# Get remote marks
r_data = JSON.parse(File.read($r_file))
$r_marks = r_data['marks'].invert
r_missing = $git_marks.reject { |mark,id| $r_marks[mark] }
git_missing = $r_marks.reject { |mark,id| $git_marks[mark] }
if $verbose
r_missing.each do |mark,id|
puts "Missing %s (%d) from #{$mode}" % [id, mark]
end
git_missing.each do |mark,id|
puts "Missing %s (%d) from git" % [id, mark]
end
end
if $fix
# Fix remote marks
r_data['marks'].delete_if { |mark,id| git_missing.has_key?(id) }
File.write($r_file, r_data.to_json)
# Fix git marks
File.open($git_file, 'w') do |f|
$git_marks.each do |mark,id|
next if r_missing.has_key?(mark)
f.puts ':%d %s' % [mark, id]
end
$note_marks.each do |mark,id|
f.puts ':%d %s' % [mark, id]
end
end
end
if r_missing.empty? and git_missing.empty?
puts 'Everything OK'
else
puts 'Issues detected'
exit 1
end
@xrchz
Copy link

xrchz commented Sep 8, 2016

This is awesome! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment