2012/08/27

[GIT] 根据文件内容快速定位该文件在哪次历史提交中引入

今天一位同事找到我说到,如何能快速的定位一个文件的某个版本是在哪一次历史提交里引入的。

解决方案如下:
首先根据文件内容确定该文件对应的blob对象的object ID
git hash-object path/to/file
或者直接使用几个shell命令生成:
(echo -e -n "blob $(wc -c path/to/file | awk '{print $1}')\0" ; cat path/to/file) | shasum

得到对应blob对象的object ID以后,使用whatchanged查看该文件的变更历史,默认情况下whatchanged不会输出merge中修改的文件,为了避免遗漏,此处还是用-m来告诉whatchanged还要输出merge的结果:
git whatchanged -m -- path/to/file

此时可以搜索刚刚得到的blob的object ID。需要注意的是由于whatchanged默认显示blob变化信息时只使用blob ID的前7位,因此搜索时也要注意不能使用完整的object ID,也应该使用object ID的前几位。

ruby写了个脚本实现查找:

注:你看到此文章时,该脚本可能已经不是最新版本,需要最新的code请移步loveky's GITHUB

#!/usr/bin/ruby

# Author: loveky <ylzcylx@gmail.com>
# Blog  : http://loveky2012.blogspot.com

#Usage: find_it_in_history.rb --file <file> --repo <path/to/repo> --path_in_repo <file/path/in/repo>

require 'digest/sha1'
require 'optparse'

found   = false
commit  = nil
options = {}
OptionParser.new do |opts|
    opts.banner = "Find the commit who first introduced the specified version of a file"
    opts.on('--file FILE', 'Which file to check') do |value|
        options[:file] = value
    end
    opts.on('--repo REPO', 'which repo to check') do |value|
        options[:repo] = value
    end
    opts.on('--path_in_repo PATH', 'the path of the file in repo') do |value|
        options[:path_in_repo] = value
    end
end.parse!

file_content = File.open(options[:file]) {|f| f.read}
file_sha1    = Digest::SHA1.hexdigest("blob #{file_content.length}\0" + file_content)

puts("#{options[:file]} => #{file_sha1}")

Dir.chdir(options[:repo])

IO.popen("git whatchanged --oneline -m -- #{options[:path_in_repo]}") do |git_whatchanged|
    git_whatchanged.each_line do |line|
        if line[0,1] == ':'
            new_blob = (/\.\.\. ([0-9a-fA-F]{7})\.\.\./.match(line))[1]
            
            if new_blob == file_sha1[0,7]
                puts "Found blob(#{file_sha1[0,7]}) in commit " + commit
                found = true
            elsif found == true
                exit 0
            end
        else
            commit = line[0,7]   
        end
    end
end

没有评论:

发表评论