Skip to content

Instantly share code, notes, and snippets.

@felipec
Last active June 5, 2026 16:59
Show Gist options
  • Select an option

  • Save felipec/10551806 to your computer and use it in GitHub Desktop.

Select an option

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

xrchz commented Sep 8, 2016

Copy link
Copy Markdown

This is awesome! Thanks

@avinasmk599-tech

Copy link
Copy Markdown

git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=sourcetree fetch origin
fatal: mark :26940 not declared
fast-import: dumping crash report to .git/fast_import_crash_15105
fatal: Error while running fast-import
Traceback (most recent call last):
File "/usr/local/bin/git-remote-hg", line 1311, in
sys.exit(main(sys.argv))
File "/usr/local/bin/git-remote-hg", line 1295, in main
do_import(parser)
File "/usr/local/bin/git-remote-hg", line 721, in do_import
export_branch(repo, branch)
File "/usr/local/bin/git-remote-hg", line 613, in export_branch
export_ref(repo, branch, 'branches', head)
File "/usr/local/bin/git-remote-hg", line 547, in export_ref
modified_final = export_files(c.filectx(f) for f in modified)
File "/usr/local/bin/git-remote-hg", line 288, in export_files
print d
IOError: [Errno 32] Broken pipe
Completed with errors, see above

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