Skip to content

Commit

Permalink
Improve log with renames (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
dometto committed Mar 14, 2020
1 parent 34ff09a commit 682bd4f
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 58 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ repo.find('959329025f67539fb82e76b02782322fad032821')
repo.find('959329025f67539fb82e76b02782322fad032821', :commit) # Find a specific :commit, :blob, :tree, or :tag
```

### Logs

```ruby
repo.git.log # Returns an Array of Commits constituting the log for the default branch
repo.git.log("follow-rename.txt", "HEAD", follow: true, list_renames: true) # Log for a specific path, tracking the pathname over renames. Returns an Array of TrackingCommits, which store the tracked filename: [#<RJGit::TrackingCommit:0x773014d3 @tracked_pathname="follow-rename.txt" ...>]
```

### Getting diffs
```ruby
sha1 = repo.head.id
Expand Down
11 changes: 10 additions & 1 deletion lib/commit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module RJGit
import 'org.eclipse.jgit.revwalk.RevCommit'
import 'org.eclipse.jgit.diff.DiffFormatter'
import 'org.eclipse.jgit.util.io.DisabledOutputStream'

class Commit

attr_reader :id, :parents, :actor, :committer, :authored_date, :committed_date
Expand Down Expand Up @@ -128,4 +128,13 @@ def self.find_all(repository, ref, options)
end

end

class TrackingCommit < Commit
attr_reader :tracked_pathname # This commit is part of a log for a single pathname. The tracked_pathname attribute tracks the pathname over renames.

def initialize(repository, commit, tracked_pathname = nil)
super(repository, commit)
@tracked_pathname = tracked_pathname
end
end
end
99 changes: 46 additions & 53 deletions lib/git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ module RJGit
import 'org.eclipse.jgit.api.TransportConfigCallback'
import 'org.eclipse.jgit.transport.JschConfigSessionFactory'
import 'org.eclipse.jgit.transport.SshTransport'
import 'org.eclipse.jgit.revwalk.FollowFilter'
import 'org.eclipse.jgit.revwalk.TreeRevFilter'

class PatchApplyException < StandardError; end

Expand Down Expand Up @@ -49,67 +51,58 @@ def log(path = nil, revstring = Constants::HEAD, options = {})
return [] unless ref
jcommits = Array.new

logs = @jgit.log
logs.add(ref)

if path && options[:follow]
current_path = path
start = nil
loop do
logs = @jgit.log.add(ref).addPath(current_path).call
logs.each do |jcommit|
next if jcommits.include?(jcommit)
jcommits << jcommit
start = jcommit
end
current_path = follow_renames(start, current_path) if start
break if current_path.nil?
end
cfg = Configuration.new(nil)
cfg.add_setting('renames', true, 'diffs', nil)
follow = FollowFilter.create(path, cfg.jconfig.get(org.eclipse.jgit.diff.DiffConfig::KEY))
logs.set_rev_filter(TreeRevFilter.new(RevWalk.new(jrepo), follow))
elsif path
logs.addPath(path)
end

else
logs = @jgit.log
logs.add(ref)
logs.addPath(path) if path
logs.setMaxCount(options[:max_count]) if options[:max_count]
logs.setSkip(options[:skip]) if options[:skip]

if (options[:since] && options[:until])
revwalk = RevWalk.new(jrepo)
since_commit = revwalk.parseCommit(jrepo.resolve(options[:since]))
until_commit = revwalk.parseCommit(jrepo.resolve(options[:until]))
logs.addRange(since_commit, until_commit)
end
if options[:not]
revwalk = RevWalk.new(jrepo)
options[:not].each do |ref|
logs.not(revwalk.parseCommit(jrepo.resolve(ref)))
end
end
jcommits = logs.call
logs.setMaxCount(options[:max_count]) if options[:max_count]
logs.setSkip(options[:skip]) if options[:skip]

if (options[:since] && options[:until])
revwalk = RevWalk.new(jrepo)
since_commit = revwalk.parseCommit(jrepo.resolve(options[:since]))
until_commit = revwalk.parseCommit(jrepo.resolve(options[:until]))
logs.addRange(since_commit, until_commit)
end

jcommits.map{ |jcommit| Commit.new(jrepo, jcommit) }
end
if options[:not]
revwalk = RevWalk.new(jrepo)
options[:not].each do |ref|
logs.not(revwalk.parseCommit(jrepo.resolve(ref)))
end
end

def follow_renames(jcommit, path)
commits = @jgit.log.add(jcommit).call
commits.each do |jcommit_prev|
tree_start = jcommit.getTree
tree_prev = jcommit_prev.getTree
treewalk = TreeWalk.new(jrepo)
#treewalk.setFilter(PathFilter.create(File.dirname(path)))
treewalk.addTree(tree_prev)
treewalk.addTree(tree_start)
treewalk.setRecursive(true)
rename_detector = RenameDetector.new(jrepo)
rename_detector.addAll(DiffEntry.scan(treewalk))
diff_entries = rename_detector.compute
diff_entries.each do |entry|
if ((entry.getChangeType == DiffEntry::ChangeType::RENAME || entry.getChangeType == DiffEntry::ChangeType::COPY) && entry.getNewPath.match(path))
return entry.getOldPath
end
if options[:follow] && options[:list_renames]
df = DiffFormatter.new(DisabledOutputStream::INSTANCE)
df.set_repository(jrepo)
df.set_context(0)
df.set_path_filter(follow)
df.set_detect_renames(true)
prev_commit = nil
pathname = path
end

commits = logs.call.map do |jcommit|
if path && options[:follow] && options[:list_renames]
entries = df.scan(jcommit, prev_commit).to_a
pathname = entries.empty? ? pathname : entries.last.get_old_path
prev_commit = jcommit
TrackingCommit.new(jrepo, jcommit, pathname)
else
Commit.new(jrepo, jcommit)
end
end
return nil
end

commits
end

def branch_list
branch = @jgit.branch_list
Expand Down
11 changes: 7 additions & 4 deletions spec/git_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@
expect(logs.map(&:id)).to_not include 'ad982fe7d4787928daba69bf0ba44a59c572ccd7'
end

it "follows renames" do
it "follows renames for specific path" do
repo = Repo.new(TEST_REPO_PATH)
messages = repo.git.log("follow-rename.txt", "HEAD", follow: true)
expect(messages.count).to eq 2
expect(messages[1].message).to match /for following renames/
commits = repo.git.log("follow-rename.txt", "HEAD", follow: true, list_renames: true)
expect(commits[0]).to be_a TrackingCommit
expect(commits[0].tracked_pathname).to eq 'follow-rename.txt'
expect(commits[1].tracked_pathname).to eq 'rename-example.txt'
expect(commits.count).to eq 2
expect(commits[1].message).to match /for following renames/
end

end
Expand Down

0 comments on commit 682bd4f

Please sign in to comment.