summaryrefslogtreecommitdiff
path: root/tissue/git.scm
diff options
context:
space:
mode:
authorArun Isaac2022-06-23 19:07:46 +0530
committerArun Isaac2022-06-23 19:07:46 +0530
commit76d9a3a7c7b2d86060670b3a53210bad66dbc3c8 (patch)
tree6de76b9cee3a273d14ac1214f394e8f3f67868fc /tissue/git.scm
parent49163adccd8ca1b60192dd54770e3525f1a2ad97 (diff)
downloadtissue-76d9a3a7c7b2d86060670b3a53210bad66dbc3c8.tar.gz
tissue-76d9a3a7c7b2d86060670b3a53210bad66dbc3c8.tar.lz
tissue-76d9a3a7c7b2d86060670b3a53210bad66dbc3c8.zip
issue: Lookup commits affecting file using guile-git.
* tissue/git.scm: Import (rnrs hashtables) and (ice-9 match). (commit-deltas): New function. (file-modification-table): New public function. * tissue/issue.scm: Import (git). (file-details): Do not lookup git history for file using `git log'. (issues): Use file-modification-table to lookup git history.
Diffstat (limited to 'tissue/git.scm')
-rw-r--r--tissue/git.scm56
1 files changed, 55 insertions, 1 deletions
diff --git a/tissue/git.scm b/tissue/git.scm
index 4b7f7c7..fcfc6c7 100644
--- a/tissue/git.scm
+++ b/tissue/git.scm
@@ -18,11 +18,13 @@
(define-module (tissue git)
#:use-module (rnrs arithmetic bitwise)
+ #:use-module (rnrs hashtables)
#:use-module (rnrs io ports)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-19)
#:use-module (srfi srfi-26)
#:use-module (srfi srfi-171)
+ #:use-module (ice-9 match)
#:use-module (git)
#:use-module (git types)
;; There are many name conflicts between (system foreign). So, we
@@ -42,7 +44,8 @@
#:export (git-top-level
current-git-repository
commit-date
- git-tracked-files))
+ git-tracked-files
+ file-modification-table))
;; We bind additional functions from libgit2 that are not already
;; bound in guile-git. TODO: Contribute them to guile-git.
@@ -197,3 +200,54 @@ filenames are relative to the top-level directory of REPOSITORY and do
not have a leading slash."
(map index-entry-path
(index-entries (repository-index repository))))
+
+(define (commit-deltas repository commit)
+ "Return the list of <diff-delta> objects created by COMMIT with
+respect to its first parent in REPOSITORY."
+ (match (commit-parents commit)
+ ((parent _ ...)
+ (let ((diff (diff-tree-to-tree repository
+ (commit-tree parent)
+ (commit-tree commit))))
+ (diff-find-similar! diff)
+ (diff-fold (lambda (delta progress result)
+ (cons delta result))
+ (lambda (delta binary result)
+ result)
+ (lambda (delta hunk result)
+ result)
+ (lambda (delta hunk line result)
+ result)
+ (list)
+ diff)))
+ (() (list))))
+
+(define (file-modification-table repository)
+ "Return a hashtable mapping files to the list of commits in REPOSITORY
+that modified them."
+ (let ((result (make-hashtable string-hash string=?))
+ (renames (make-hashtable string-hash string=?)))
+ (fold-commits
+ (lambda (commit _)
+ (map (lambda (delta)
+ ;; Map old filename to current filename if they are
+ ;; different. Note that this manner of following renames
+ ;; requires a linear git history and will not work with
+ ;; branch merges.
+ (unless (string=? (diff-file-path (diff-delta-old-file delta))
+ (diff-file-path (diff-delta-new-file delta)))
+ (hashtable-set! renames
+ (diff-file-path (diff-delta-old-file delta))
+ (diff-file-path (diff-delta-new-file delta))))
+ (hashtable-update! result
+ ;; If necessary, translate old
+ ;; filename to current filename.
+ (hashtable-ref renames
+ (diff-file-path (diff-delta-old-file delta))
+ (diff-file-path (diff-delta-old-file delta)))
+ (cut cons commit <>)
+ (list)))
+ (commit-deltas repository commit)))
+ #f
+ repository)
+ result))