Created
February 6, 2012 23:47
-
-
Save carlosmn/1755969 to your computer and use it in GitHub Desktop.
A libgit2 implementation of git fsck --unreachable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'rugged' | |
require 'set' | |
def objects_in_tree(repo, tree, objs) | |
tree.each do |e| | |
objs << e[:oid] | |
if e[:type] == :tree then | |
objects_in_tree(repo, repo.lookup(e[:oid]), objs) | |
end | |
end | |
end | |
def objects_in_commit(repo, cmt, objs) | |
lobjs = Array.new | |
lobjs << cmt.tree.oid | |
objects_in_tree(repo, cmt.tree, lobjs) | |
objs.merge(lobjs) | |
end | |
old = ARGV[0] | |
new = ARGV[1] | |
if old == nil or new == nil then | |
puts "usage: newly-unreachabe.rb <old tip> <new tip>" | |
exit 1 | |
end | |
repo = Rugged::Repository.new('.') | |
walker = Rugged::Walker.new(repo) | |
walker.push(old) | |
walker.hide(new) | |
# If the old commit is in an ancestor of any of the existing branches, | |
# it's not unrefereced, so we need to hide all of the branch tips | |
refs = repo.refs(/heads/).map {|ref| ref.resolve.target} | |
refs.each do |ref| | |
walker.hide(ref) | |
end | |
objects = Set.new | |
# This generates a list of objects that are referenced by the | |
# newly-unreferenced commits. Any of these could become | |
# unreferenced. The unreferenced commits are themselves objects to | |
# prune, so we add them to the list as well | |
walker.each do |cmt| | |
objects << cmt.oid | |
objects_in_commit(repo, cmt, objects) | |
end | |
#objects.uniq! | |
#puts "Objects to look at:" | |
#objects.each do |o| | |
# puts "object #{o}" | |
#end | |
# Do another walk. This time we're listing all the objects referenced | |
# by reachable commits and removing those from the objects array so we | |
# don't consider them targets for deletion | |
walker = Rugged::Walker.new(repo) | |
refs.each do |ref| | |
walker.push(ref) | |
end | |
objs = Set.new | |
walker.each do |cmt| | |
objects_in_commit(repo, cmt, objs) | |
objects -= objs | |
objs.clear | |
break if objects.size == 0 | |
end | |
puts "Unreachable objects:" | |
objects.each do |o| | |
puts "object #{o}" | |
end |
Like the usage string says, this takes the old and new tip of a branch (or any reference, most likely) as it's meant to compute what became unreachable after a particular push. I'm not sure why the description says it's meant to be fsck --unreachable
though.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey! thanks this is super useful! And sorry to ask you a question 10 years after this was posted 😁 but what does old and new represent?
I think I understand that the walker needs to start somewhere but why is there an old and a new?