Patchsets
Range Diff ↕
1: 778bcd8 ! 1: 0f86231 feat: range diff
@@ fixtures/a_b.patch +From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:07:57 -0400 +Subject: [PATCH] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) +-- +2.45.2 + @@ fixtures/a_b_reorder.patch +From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:07:57 -0400 +Subject: [PATCH 1/2] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) +-- +2.45.2 + + +From 22dde1259c34a166d5a9335ebe5236e79541cc63 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:14:37 -0400 +Subject: [PATCH 2/2] docs: readme + +--- + README.md | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/README.md b/README.md +index 8f3a780..3043953 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,5 @@ + # Let's build an RNN + +-This repo demonstrates building an RNN using `pytorch` ++This repo demonstrates building an RNN using `pytorch`. ++ ++Here is some more readme information. +-- +2.45.2 + @@ fixtures/a_c.patch +From 166848469e0b954c2e14233233f3824a46dcddb8 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:06:00 -0400 +Subject: [PATCH] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) + +base-commit: 59456574a0bfee9f71c91c13046173c820152346 +-- +2.45.2 + @@ fixtures/a_c_added_commit.patch +From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:07:57 -0400 +Subject: [PATCH 1/3] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) +-- +2.45.2 + + +From 22dde1259c34a166d5a9335ebe5236e79541cc63 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:14:37 -0400 +Subject: [PATCH 2/3] docs: readme + +--- + README.md | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/README.md b/README.md +index 8f3a780..3043953 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,5 @@ + # Let's build an RNN + +-This repo demonstrates building an RNN using `pytorch` ++This repo demonstrates building an RNN using `pytorch`. ++ ++Here is some more readme information. +-- +2.45.2 + + +From b248060488df529b850060b3c86417bb87d490cc Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:20:44 -0400 +Subject: [PATCH 3/3] chore: make tensor 6x6 + +--- + train.py | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/train.py b/train.py +index d21dac3..8cd47e0 100644 +--- a/train.py ++++ b/train.py +@@ -2,4 +2,6 @@ import torch + + if __name__ == "__main__": + print("train!") +- torch.rand(3,6) ++ # let's create a 6x6 tensor! ++ tensor = torch.rand(6,6) ++ print(tensor) +-- +2.45.2 + @@ fixtures/a_c_changed_commit.patch +From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:07:57 -0400 +Subject: [PATCH 1/2] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) +-- +2.45.2 + + +From dce20e70280d92aeb88c3d603ad67043ead772fb Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:14:37 -0400 +Subject: [PATCH 2/2] docs: readme + +--- + README.md | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/README.md b/README.md +index 8f3a780..ba0293b 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,10 @@ + # Let's build an RNN + +-This repo demonstrates building an RNN using `pytorch` ++This repo demonstrates building an RNN using `pytorch`. ++ ++Here is some more readme information. ++ ++Here is how to run this project locally: ++ ++- install python and pip ++- `pip install -r requirements.txt` +-- +2.45.2 + @@ fixtures/a_c_reorder.patch +From 7dbb94ca1bc8cadf1ce17dacb89172217d88de07 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:15:23 -0400 +Subject: [PATCH 1/2] docs: readme + +--- + README.md | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/README.md b/README.md +index 8f3a780..3043953 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,5 @@ + # Let's build an RNN + +-This repo demonstrates building an RNN using `pytorch` ++This repo demonstrates building an RNN using `pytorch`. ++ ++Here is some more readme information. +-- +2.45.2 + + +From ad175875e2bf320859554bae73743675cc5ce444 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:06:00 -0400 +Subject: [PATCH 2/2] chore: add torch and create random tensor + +--- + requirements.txt | 1 + + train.py | 3 +++ + 2 files changed, 4 insertions(+) + create mode 100644 requirements.txt + +diff --git a/requirements.txt b/requirements.txt +new file mode 100644 +index 0000000..4968a39 +--- /dev/null ++++ b/requirements.txt +@@ -0,0 +1 @@ ++torch==2.3.1 +diff --git a/train.py b/train.py +index 5c027f4..d21dac3 100644 +--- a/train.py ++++ b/train.py +@@ -1,2 +1,5 @@ ++import torch ++ + if __name__ == "__main__": + print("train!") ++ torch.rand(3,6) +-- +2.45.2 + @@ fixtures/a_c_rm_commit.patch +From 7dbb94ca1bc8cadf1ce17dacb89172217d88de07 Mon Sep 17 00:00:00 2001 +From: Eric Bower <me@erock.io> +Date: Tue, 23 Jul 2024 10:15:23 -0400 +Subject: [PATCH] docs: readme + +--- + README.md | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/README.md b/README.md +index 8f3a780..3043953 100644 +--- a/README.md ++++ b/README.md +@@ -1,3 +1,5 @@ + # Let's build an RNN + +-This repo demonstrates building an RNN using `pytorch` ++This repo demonstrates building an RNN using `pytorch`. ++ ++Here is some more readme information. +-- +2.45.2 + @@ fixtures/expected_commit_changed.txt +1: 33c682a = 1: 33c682a chore: add torch and create random tensor +2: 22dde12 ! 2: 0185f34 docs: readme + @@ README.md + +This repo demonstrates building an RNN using `pytorch`. + + + +Here is some more readme information. + ++ + ++Here is how to run this project locally: + ++ + ++- install python and pip + ++- `pip install -r requirements.txt` @@ go.mod github.com/knadh/koanf/providers/env v0.1.0 github.com/knadh/koanf/providers/file v1.0.0 github.com/knadh/koanf/v2 v2.1.1 + github.com/sergi/go-diff v1.1.0 github.com/urfave/cli/v2 v2.27.2 golang.org/x/crypto v0.21.0 modernc.org/sqlite v1.27.0 @@ go.sum github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/bluekeyes/go-gitdiff v0.7.2 h1:42jrcVZdjjxXtVsFNYTo/I6T1ZvIiQL+iDDLiH904hw= -github.com/bluekeyes/go-gitdiff v0.7.2/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM= github.com/bluekeyes/go-gitdiff v0.7.4-0.20240715034416-0a4e55f9a190 h1:k6Ep4yQtmsoP/St4bf7ofXyWc6ITB/FyGy9ewaAn5os= github.com/bluekeyes/go-gitdiff v0.7.4-0.20240715034416-0a4e55f9a190/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM= github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/knadh/koanf/providers/file v1.0.0/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI= github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM= github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI= @@ pr.go _ = tx.Rollback() }() - patches, err := parsePatchset(patchset) + patches, err := ParsePatchset(patchset) if err != nil { return nil, err } _ = tx.Rollback() }() - patches, err := parsePatchset(patchset) + patches, err := ParsePatchset(patchset) if err != nil { return fin, err } @@ range_diff.go +package git + +import ( + "fmt" + "math" + + "github.com/sergi/go-diff/diffmatchpatch" +) + +var COST_MAX = 65536 +var RANGE_DIFF_CREATION_FACTOR_DEFAULT = 60 + +type PatchRange struct { + *Patch + Matching int + Diff string + DiffSize int + Shown bool +} + +func NewPatchRange(patch *Patch) *PatchRange { + diff := patch.CalcDiff() + return &PatchRange{ + Patch: patch, + Patch: patch, + Matching: -1, + Diff: diff, + DiffSize: len(diff), + Shown: false, + } +} + +func output(a []*PatchRange, b []*PatchRange) string { + out := "" + for _, patchB := range b { + for i, patchA := range a { + if patchA.Matching == -1 { + out += outputPairHeader(patchA, nil, i+1, -1) + } + } + + for j, patchB := range b { + if patchB.Matching == -1 { + out += outputPairHeader(nil, patchB, -1, j+1) + continue + } + patchA := a[patchB.Matching] + if patchB.ContentSha == patchA.ContentSha { + out += outputPairHeader(patchA, patchB, patchB.Matching+1, patchA.Matching+1) + } + } + return out +} + +func outputPairHeader(a *PatchRange, b *PatchRange, aIndex, bIndex int) string { + if a == nil { + return fmt.Sprintf("-: ------- > %d: %s %s\n", bIndex, truncateSha(b.CommitSha), b.Title) + } + if b == nil { + return fmt.Sprintf("%d: %s < -: ------- %s\n", aIndex, truncateSha(a.CommitSha), a.Title) + } + return fmt.Sprintf("%d: %s = %d: %s %s\n", aIndex, truncateSha(a.CommitSha), bIndex, truncateSha(b.CommitSha), a.Title) +} + +func RangeDiff(a []*Patch, b []*Patch) string { + aPatches := []*PatchRange{} + for _, patch := range a { + aPatches = append(aPatches, NewPatchRange(patch)) + } + bPatches := []*PatchRange{} + for _, patch := range b { + bPatches = append(bPatches, NewPatchRange(patch)) + } + findExactMatches(aPatches, bPatches) + getCorrespondences(aPatches, bPatches, RANGE_DIFF_CREATION_FACTOR_DEFAULT) + return output(aPatches, bPatches) +} + +func findExactMatches(a []*PatchRange, b []*PatchRange) { + for i, patchA := range a { + for j, patchB := range b { + if patchA.ContentSha == patchB.ContentSha { + patchA.Matching = j + patchB.Matching = i + } + } + } +} + +func createMatrix(rows, cols int) [][]int { + mat := make([][]int, rows) + for i := range mat { + mat[i] = make([]int, cols) + } + return mat +} + +func diffsize(a *PatchRange, b *PatchRange) int { + dmp := diffmatchpatch.New() + diffs := dmp.DiffMain(a.RawText, b.RawText, false) + diffs := dmp.DiffMain(a.Diff, b.Diff, false) + return len(dmp.DiffPrettyText(diffs)) +} + +func getCorrespondences(a []*PatchRange, b []*PatchRange, creationFactor int) { + // n := len(a) + len(b) + fmt.Println(len(a), len(b)) + cost := createMatrix(len(a), len(b)) + n := len(a) + len(b) + fmt.Println("rows", len(a), "cols", len(b)) + cost := createMatrix(n, n) + + for i, patchA := range a { + var c int + for j, patchB := range b { + if patchA.Matching == j { + c = 0 + } else if patchA.Matching == 0 && patchB.Matching == 0 { + } else if patchA.Matching == -1 && patchB.Matching == -1 { + c = diffsize(patchA, patchB) + } else { + c = COST_MAX + } + cost[i][j] = c + } + } + + assignment := computeAssignment(cost, len(a), len(b)) + for i, j := range assignment { + if j < len(b) { + a[i].Matching = j + b[j].Matching = i + for j, patchB := range b { + creationCost := (patchB.DiffSize * creationFactor) / 100 + if patchB.Matching >= 0 { + creationCost = math.MaxInt32 + } + for i := len(a); i < n; i++ { + cost[i][j] = creationCost + } + } + + fmt.Println(cost, assignment) + fmt.Println("A==") + for _, patch := range a { + fmt.Println("matches", b[patch.Matching].Title) + for i := len(a); i < n; i++ { + for j := len(b); j < n; j++ { + cost[i][j] = 0 + } + } + + fmt.Println("B==") + for _, patch := range b { + fmt.Println("matches", a[patch.Matching].Title) + assignment := computeAssignment(cost, n, n) + for i, j := range assignment { + if i < len(a) && j < len(b) { + a[i].Matching = j + b[j].Matching = i + } + } + + fmt.Println("cost", cost, "assignment", assignment) +} + +// computeAssignment assigns patches using the Hungarian algorithm. +func computeAssignment(costMatrix [][]int, m, n int) []int { + u := make([]int, m+1) // potential for workers + v := make([]int, n+1) // potential for jobs + p := make([]int, n+1) // job assignment + way := make([]int, n+1) + + for i := 1; i <= m; i++ { + links := make([]int, n+1) + minV := make([]int, n+1) + used := make([]bool, n+1) + for j := 0; j <= n; j++ { + minV[j] = math.MaxInt32 + used[j] = false + } + + j0 := 0 + p[0] = i + + for { + used[j0] = true + i0 := p[j0] + delta := math.MaxInt32 + j1 := 0 + + for j := 1; j <= n; j++ { + if !used[j] { + cur := costMatrix[i0-1][j-1] - u[i0] - v[j] + if cur < minV[j] { + minV[j] = cur + links[j] = j0 + } + if minV[j] < delta { + delta = minV[j] + j1 = j + } + } + } + + for j := 0; j <= n; j++ { + if used[j] { + u[p[j]] += delta + v[j] -= delta + } else { + minV[j] -= delta + } + } + + j0 = j1 + if p[j0] == 0 { + break + } + } + + for { + j1 := way[j0] + p[j0] = p[j1] + j0 = j1 + if j0 == 0 { + break + } + } + } + + assignment := make([]int, m) + for j := 1; j <= n; j++ { + if p[j] > 0 { + assignment[p[j]-1] = j - 1 + } + } + return assignment +} @@ range_diff_test.go +package git + +import ( + "fmt" + "testing" + + "github.com/picosh/git-pr/fixtures" +) + +func bail(err error) { + if err != nil { + panic(bail) + } +} + +func cmp(afile, bfile string) string { + a, err := fixtures.Fixtures.Open(afile) + bail(err) + b, err := fixtures.Fixtures.Open(bfile) + bail(err) + aPatches, err := ParsePatchset(a) + bail(err) + bPatches, err := ParsePatchset(b) + bail(err) + actual := RangeDiff(aPatches, bPatches) + return actual +} + +func fail(expected, actual string) string { + return fmt.Sprintf("expected:[%s] actual:[%s]", expected, actual) +} + +// https://git.kernel.org/tree/t/t3206-range-diff.sh?id=d19b6cd2dd72dc811f19df4b32c7ed223256c3ee + +// simple A..B A..C (unmodified) +/* + 1: $(test_oid t1) = 1: $(test_oid u1) s/5/A/ + 2: $(test_oid t2) = 2: $(test_oid u2) s/4/A/ + 3: $(test_oid t3) = 3: $(test_oid u3) s/11/B/ + 4: $(test_oid t4) = 4: $(test_oid u4) s/12/B/ +*/ +func TestRangeDiffUnmodified(t *testing.T) { + actual := cmp("a_b.patch", "a_c.patch") + expected := "1: 33c682a = 1: 1668484 chore: add torch and create random tensor\n" + if expected != actual { + t.Fatalf(fail(expected, actual)) + } +} + +// trivial reordering +/* + 1: $(test_oid t1) = 1: $(test_oid r1) s/5/A/ + 3: $(test_oid t3) = 2: $(test_oid r2) s/11/B/ + 4: $(test_oid t4) = 3: $(test_oid r3) s/12/B/ + 2: $(test_oid t2) = 4: $(test_oid r4) s/4/A/ +*/ +func TestRangeDiffTrivialReordering(t *testing.T) { + actual := cmp("a_b_reorder.patch", "a_c_reorder.patch") + expected := `2: 22dde12 = 1: 7dbb94c docs: readme +1: 33c682a = 2: ad17587 chore: add torch and create random tensor +` + if expected != actual { + t.Fatalf(fail(expected, actual)) + } +} + +// removed commit +/* + 1: $(test_oid t1) = 1: $(test_oid d1) s/5/A/ + 2: $(test_oid t2) < -: $(test_oid __) s/4/A/ + 3: $(test_oid t3) = 2: $(test_oid d2) s/11/B/ + 4: $(test_oid t4) = 3: $(test_oid d3) s/12/B/ +*/ +func TestRangeDiffRemovedCommit(t *testing.T) { + actual := cmp("a_b_reorder.patch", "a_c_reorder.patch") + actual := cmp("a_b_reorder.patch", "a_c_rm_commit.patch") + expected := `1: 33c682a < -: ------- chore: add torch and create random tensor +2: 22dde12 = 1: 7dbb94c docs: readme` +2: 22dde12 = 1: 7dbb94c docs: readme +` + if expected != actual { + t.Fatalf(fail(expected, actual)) + } +} + +// added commit +/* + 1: $(test_oid t1) = 1: $(test_oid a1) s/5/A/ + 2: $(test_oid t2) = 2: $(test_oid a2) s/4/A/ + -: $(test_oid __) > 3: $(test_oid a3) s/6/A/ + 3: $(test_oid t3) = 4: $(test_oid a4) s/11/B/ + 4: $(test_oid t4) = 5: $(test_oid a5) s/12/B/ +*/ +/* func TestRangeDiffAddedCommit(t *testing.T) { + actual := "" +func TestRangeDiffAddedCommit(t *testing.T) { + actual := cmp("a_b_reorder.patch", "a_c_added_commit.patch") + expected := `1: 33c682a = 1: 33c682a chore: add torch and create random tensor +2: 22dde12 = 2: 22dde12 docs: readme +-: ------- > 3: b248060 chore: make tensor 6x6` +-: ------- > 3: b248060 chore: make tensor 6x6 +` + if expected != actual { + t.Fatalf("expected:%s actual:%s", expected, actual) + t.Fatalf(fail(expected, actual)) + } +} */ +} + +// changed commit +/* + 1: $(test_oid t1) = 1: $(test_oid c1) s/5/A/ + 2: $(test_oid t2) = 2: $(test_oid c2) s/4/A/ + 3: $(test_oid t3) ! 3: $(test_oid c3) s/11/B/ + @@ file: A + 9 + 10 + -11 + -+B + ++BB + 12 + 13 + 14 + 4: $(test_oid t4) ! 4: $(test_oid c4) s/12/B/ + @@ file + @@ file: A + 9 + 10 + - B + + BB + -12 + +B + 13 +*/ +/* func TestRangeDiffChangedCommit(t *testing.T) { + actual := "" + fp, err := fixtures.Fixtures.ReadFile("extected_commit_changed.txt") +func TestRangeDiffChangedCommit(t *testing.T) { + actual := cmp("a_b_reorder.patch", "a_c_changed_commit.patch") + fp, err := fixtures.Fixtures.ReadFile("expected_commit_changed.txt") + if err != nil { + t.Fatalf("file not found") + } + expected := string(fp) + if expected != actual { + t.Fatalf("expected:%s actual:%s", expected, actual) + t.Fatalf(fail(expected, actual)) + } +} */ +} + +// renamed file +/* + 1: $(test_oid t1) = 1: $(test_oid n1) s/5/A/ + 2: $(test_oid t2) ! 2: $(test_oid n2) s/4/A/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/4/A/ + + s/4/A/ + rename file + Z + - ## file ## + + ## file => renamed-file ## + Z@@ + Z 1 + Z 2 + 3: $(test_oid t3) ! 3: $(test_oid n3) s/11/B/ + @@ Metadata + Z ## Commit message ## + Z s/11/B/ + Z + - ## file ## + -@@ file: A + + ## renamed-file ## + +@@ renamed-file: A + Z 8 + Z 9 + Z 10 + 4: $(test_oid t4) ! 4: $(test_oid n4) s/12/B/ + @@ Metadata + Z ## Commit message ## + Z s/12/B/ + Z + - ## file ## + -@@ file: A + + ## renamed-file ## + +@@ renamed-file: A + Z 9 + Z 10 + Z B +*/ +// func TestRangeDiffRenamedFile(t *testing.T) {} + +// file with mode only change +/* + 1: $(test_oid t2) ! 1: $(test_oid o1) s/4/A/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/4/A/ + + s/4/A/ + add other-file + Z + Z ## file ## + Z@@ + @@ file + Z A + Z 6 + Z 7 + + + + ## other-file (new) ## + 2: $(test_oid t3) ! 2: $(test_oid o2) s/11/B/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/11/B/ + + s/11/B/ + mode change other-file + Z + Z ## file ## + Z@@ file: A + @@ file: A + Z 12 + Z 13 + Z 14 + + + + ## other-file (mode change 100644 => 100755) ## + 3: $(test_oid t4) = 3: $(test_oid o3) s/12/B/ +*/ +// func TestRangeDiffFileWithModeOnlyChange(t *testing.T) {} + +// file added and later removed +/* + 1: $(test_oid t1) = 1: $(test_oid s1) s/5/A/ + 2: $(test_oid t2) ! 2: $(test_oid s2) s/4/A/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/4/A/ + + s/4/A/ + new-file + Z + Z ## file ## + Z@@ + @@ file + Z A + Z 6 + Z 7 + + + + ## new-file (new) ## + 3: $(test_oid t3) ! 3: $(test_oid s3) s/11/B/ + @@ Metadata + ZAuthor: Thomas Rast <trast@inf.ethz.ch> + Z + Z ## Commit message ## + - s/11/B/ + + s/11/B/ + remove file + Z + Z ## file ## + Z@@ file: A + @@ file: A + Z 12 + Z 13 + Z 14 + + + + ## new-file (deleted) ## + 4: $(test_oid t4) = 4: $(test_oid s4) s/12/B/ +*/ +// func TestRangeDiffFileAddedThenRemoved(t *testing.T) {} + +// changed message +/* + 1: $(test_oid t1) = 1: $(test_oid m1) s/5/A/ + 2: $(test_oid t2) ! 2: $(test_oid m2) s/4/A/ + @@ Metadata + Z ## Commit message ## + Z s/4/A/ + Z + + Also a silly comment here! + + + Z ## file ## + Z@@ + Z 1 + 3: $(test_oid t3) = 3: $(test_oid m3) s/11/B/ + 4: $(test_oid t4) = 4: $(test_oid m4) s/12/B/ +*/ +// func TestRangeDiffChangedMessage(t *testing.T) {} @@ util.go return str[idx:], nil } -func parsePatchset(patchset io.Reader) ([]*Patch, error) { +func ParsePatchset(patchset io.Reader) ([]*Patch, error) { patches := []*Patch{} buf := new(strings.Builder) _, err := io.Copy(buf, patchset) ContentSha: contentSha, RawText: patchStr, BaseCommitSha: sql.NullString{String: baseCommit}, + Files: diffFiles, }) } authorEmail = header.Author.Email } content := fmt.Sprintf( - "%s\n%s\n%s\n%s\n%s\n", + "%s\n%s\n%s\n%s\n", header.Title, header.Body, authorName, authorEmail, - header.AuthorDate, ) for _, diff := range diffFiles { // we need to ignore diffs with base commit because that depends @@ util_test.go if err != nil { t.Fatalf(err.Error()) } - actual, err := parsePatchset(file) + actual, err := ParsePatchset(file) if err != nil { t.Fatalf(err.Error()) }
Patchset ps-51
feat: range diff
Eric Bower
db.go
+6
-0
fixtures/a_b.patch
+31
-0
fixtures/a_b_reorder.patch
+55
-0
fixtures/a_c.patch
+33
-0
fixtures/a_c_reorder.patch
+55
-0
fixtures/a_c_rm_commit.patch
+23
-0
go.mod
+1
-0
go.sum
+13
-2
pr.go
+2
-2
range_diff.go
+219
-0
range_diff_test.go
+276
-0
util.go
+3
-3
util_test.go
+1
-1
feat: range diff
db.go
link
+6
-0
+6
-0
1diff --git a/db.go b/db.go
2index 291ccc6..7323e8a 100644
3--- a/db.go
4+++ b/db.go
5@@ -6,6 +6,7 @@ import (
6 "log/slog"
7 "time"
8
9+ "github.com/bluekeyes/go-gitdiff/gitdiff"
10 "github.com/jmoiron/sqlx"
11 _ "modernc.org/sqlite"
12 )
13@@ -67,6 +68,11 @@ type Patch struct {
14 BaseCommitSha sql.NullString `db:"base_commit_sha"`
15 RawText string `db:"raw_text"`
16 CreatedAt time.Time `db:"created_at"`
17+ Files []*gitdiff.File
18+}
19+
20+func (p *Patch) CalcDiff() string {
21+ return p.RawText
22 }
23
24 // EventLog is a event log for RSS or other notification systems.
fixtures/a_b.patch
link
+31
-0
+31
-0
1diff --git a/fixtures/a_b.patch b/fixtures/a_b.patch
2new file mode 100644
3index 0000000..c2c5167
4--- /dev/null
5+++ b/fixtures/a_b.patch
6@@ -0,0 +1,31 @@
7+From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:07:57 -0400
10+Subject: [PATCH] chore: add torch and create random tensor
11+
12+---
13+ requirements.txt | 1 +
14+ train.py | 3 +++
15+ 2 files changed, 4 insertions(+)
16+ create mode 100644 requirements.txt
17+
18+diff --git a/requirements.txt b/requirements.txt
19+new file mode 100644
20+index 0000000..4968a39
21+--- /dev/null
22++++ b/requirements.txt
23+@@ -0,0 +1 @@
24++torch==2.3.1
25+diff --git a/train.py b/train.py
26+index 5c027f4..d21dac3 100644
27+--- a/train.py
28++++ b/train.py
29+@@ -1,2 +1,5 @@
30++import torch
31++
32+ if __name__ == "__main__":
33+ print("train!")
34++ torch.rand(3,6)
35+--
36+2.45.2
37+
fixtures/a_b_reorder.patch
link
+55
-0
+55
-0
1diff --git a/fixtures/a_b_reorder.patch b/fixtures/a_b_reorder.patch
2new file mode 100644
3index 0000000..2524df9
4--- /dev/null
5+++ b/fixtures/a_b_reorder.patch
6@@ -0,0 +1,55 @@
7+From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:07:57 -0400
10+Subject: [PATCH 1/2] chore: add torch and create random tensor
11+
12+---
13+ requirements.txt | 1 +
14+ train.py | 3 +++
15+ 2 files changed, 4 insertions(+)
16+ create mode 100644 requirements.txt
17+
18+diff --git a/requirements.txt b/requirements.txt
19+new file mode 100644
20+index 0000000..4968a39
21+--- /dev/null
22++++ b/requirements.txt
23+@@ -0,0 +1 @@
24++torch==2.3.1
25+diff --git a/train.py b/train.py
26+index 5c027f4..d21dac3 100644
27+--- a/train.py
28++++ b/train.py
29+@@ -1,2 +1,5 @@
30++import torch
31++
32+ if __name__ == "__main__":
33+ print("train!")
34++ torch.rand(3,6)
35+--
36+2.45.2
37+
38+
39+From 22dde1259c34a166d5a9335ebe5236e79541cc63 Mon Sep 17 00:00:00 2001
40+From: Eric Bower <me@erock.io>
41+Date: Tue, 23 Jul 2024 10:14:37 -0400
42+Subject: [PATCH 2/2] docs: readme
43+
44+---
45+ README.md | 4 +++-
46+ 1 file changed, 3 insertions(+), 1 deletion(-)
47+
48+diff --git a/README.md b/README.md
49+index 8f3a780..3043953 100644
50+--- a/README.md
51++++ b/README.md
52+@@ -1,3 +1,5 @@
53+ # Let's build an RNN
54+
55+-This repo demonstrates building an RNN using `pytorch`
56++This repo demonstrates building an RNN using `pytorch`.
57++
58++Here is some more readme information.
59+--
60+2.45.2
61+
fixtures/a_c.patch
link
+33
-0
+33
-0
1diff --git a/fixtures/a_c.patch b/fixtures/a_c.patch
2new file mode 100644
3index 0000000..4960260
4--- /dev/null
5+++ b/fixtures/a_c.patch
6@@ -0,0 +1,33 @@
7+From 166848469e0b954c2e14233233f3824a46dcddb8 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:06:00 -0400
10+Subject: [PATCH] chore: add torch and create random tensor
11+
12+---
13+ requirements.txt | 1 +
14+ train.py | 3 +++
15+ 2 files changed, 4 insertions(+)
16+ create mode 100644 requirements.txt
17+
18+diff --git a/requirements.txt b/requirements.txt
19+new file mode 100644
20+index 0000000..4968a39
21+--- /dev/null
22++++ b/requirements.txt
23+@@ -0,0 +1 @@
24++torch==2.3.1
25+diff --git a/train.py b/train.py
26+index 5c027f4..d21dac3 100644
27+--- a/train.py
28++++ b/train.py
29+@@ -1,2 +1,5 @@
30++import torch
31++
32+ if __name__ == "__main__":
33+ print("train!")
34++ torch.rand(3,6)
35+
36+base-commit: 59456574a0bfee9f71c91c13046173c820152346
37+--
38+2.45.2
39+
fixtures/a_c_added_commit.patch
link
+80
-0
+80
-0
1diff --git a/fixtures/a_c_added_commit.patch b/fixtures/a_c_added_commit.patch
2new file mode 100644
3index 0000000..f5ce9f3
4--- /dev/null
5+++ b/fixtures/a_c_added_commit.patch
6@@ -0,0 +1,80 @@
7+From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:07:57 -0400
10+Subject: [PATCH 1/3] chore: add torch and create random tensor
11+
12+---
13+ requirements.txt | 1 +
14+ train.py | 3 +++
15+ 2 files changed, 4 insertions(+)
16+ create mode 100644 requirements.txt
17+
18+diff --git a/requirements.txt b/requirements.txt
19+new file mode 100644
20+index 0000000..4968a39
21+--- /dev/null
22++++ b/requirements.txt
23+@@ -0,0 +1 @@
24++torch==2.3.1
25+diff --git a/train.py b/train.py
26+index 5c027f4..d21dac3 100644
27+--- a/train.py
28++++ b/train.py
29+@@ -1,2 +1,5 @@
30++import torch
31++
32+ if __name__ == "__main__":
33+ print("train!")
34++ torch.rand(3,6)
35+--
36+2.45.2
37+
38+
39+From 22dde1259c34a166d5a9335ebe5236e79541cc63 Mon Sep 17 00:00:00 2001
40+From: Eric Bower <me@erock.io>
41+Date: Tue, 23 Jul 2024 10:14:37 -0400
42+Subject: [PATCH 2/3] docs: readme
43+
44+---
45+ README.md | 4 +++-
46+ 1 file changed, 3 insertions(+), 1 deletion(-)
47+
48+diff --git a/README.md b/README.md
49+index 8f3a780..3043953 100644
50+--- a/README.md
51++++ b/README.md
52+@@ -1,3 +1,5 @@
53+ # Let's build an RNN
54+
55+-This repo demonstrates building an RNN using `pytorch`
56++This repo demonstrates building an RNN using `pytorch`.
57++
58++Here is some more readme information.
59+--
60+2.45.2
61+
62+
63+From b248060488df529b850060b3c86417bb87d490cc Mon Sep 17 00:00:00 2001
64+From: Eric Bower <me@erock.io>
65+Date: Tue, 23 Jul 2024 10:20:44 -0400
66+Subject: [PATCH 3/3] chore: make tensor 6x6
67+
68+---
69+ train.py | 4 +++-
70+ 1 file changed, 3 insertions(+), 1 deletion(-)
71+
72+diff --git a/train.py b/train.py
73+index d21dac3..8cd47e0 100644
74+--- a/train.py
75++++ b/train.py
76+@@ -2,4 +2,6 @@ import torch
77+
78+ if __name__ == "__main__":
79+ print("train!")
80+- torch.rand(3,6)
81++ # let's create a 6x6 tensor!
82++ tensor = torch.rand(6,6)
83++ print(tensor)
84+--
85+2.45.2
86+
fixtures/a_c_changed_commit.patch
link
+60
-0
+60
-0
1diff --git a/fixtures/a_c_changed_commit.patch b/fixtures/a_c_changed_commit.patch
2new file mode 100644
3index 0000000..259a434
4--- /dev/null
5+++ b/fixtures/a_c_changed_commit.patch
6@@ -0,0 +1,60 @@
7+From 33c682ac27479f501924cf159d0a75ad91deb589 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:07:57 -0400
10+Subject: [PATCH 1/2] chore: add torch and create random tensor
11+
12+---
13+ requirements.txt | 1 +
14+ train.py | 3 +++
15+ 2 files changed, 4 insertions(+)
16+ create mode 100644 requirements.txt
17+
18+diff --git a/requirements.txt b/requirements.txt
19+new file mode 100644
20+index 0000000..4968a39
21+--- /dev/null
22++++ b/requirements.txt
23+@@ -0,0 +1 @@
24++torch==2.3.1
25+diff --git a/train.py b/train.py
26+index 5c027f4..d21dac3 100644
27+--- a/train.py
28++++ b/train.py
29+@@ -1,2 +1,5 @@
30++import torch
31++
32+ if __name__ == "__main__":
33+ print("train!")
34++ torch.rand(3,6)
35+--
36+2.45.2
37+
38+
39+From dce20e70280d92aeb88c3d603ad67043ead772fb Mon Sep 17 00:00:00 2001
40+From: Eric Bower <me@erock.io>
41+Date: Tue, 23 Jul 2024 10:14:37 -0400
42+Subject: [PATCH 2/2] docs: readme
43+
44+---
45+ README.md | 9 ++++++++-
46+ 1 file changed, 8 insertions(+), 1 deletion(-)
47+
48+diff --git a/README.md b/README.md
49+index 8f3a780..ba0293b 100644
50+--- a/README.md
51++++ b/README.md
52+@@ -1,3 +1,10 @@
53+ # Let's build an RNN
54+
55+-This repo demonstrates building an RNN using `pytorch`
56++This repo demonstrates building an RNN using `pytorch`.
57++
58++Here is some more readme information.
59++
60++Here is how to run this project locally:
61++
62++- install python and pip
63++- `pip install -r requirements.txt`
64+--
65+2.45.2
66+
fixtures/a_c_reorder.patch
link
+55
-0
+55
-0
1diff --git a/fixtures/a_c_reorder.patch b/fixtures/a_c_reorder.patch
2new file mode 100644
3index 0000000..bc90f03
4--- /dev/null
5+++ b/fixtures/a_c_reorder.patch
6@@ -0,0 +1,55 @@
7+From 7dbb94ca1bc8cadf1ce17dacb89172217d88de07 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:15:23 -0400
10+Subject: [PATCH 1/2] docs: readme
11+
12+---
13+ README.md | 4 +++-
14+ 1 file changed, 3 insertions(+), 1 deletion(-)
15+
16+diff --git a/README.md b/README.md
17+index 8f3a780..3043953 100644
18+--- a/README.md
19++++ b/README.md
20+@@ -1,3 +1,5 @@
21+ # Let's build an RNN
22+
23+-This repo demonstrates building an RNN using `pytorch`
24++This repo demonstrates building an RNN using `pytorch`.
25++
26++Here is some more readme information.
27+--
28+2.45.2
29+
30+
31+From ad175875e2bf320859554bae73743675cc5ce444 Mon Sep 17 00:00:00 2001
32+From: Eric Bower <me@erock.io>
33+Date: Tue, 23 Jul 2024 10:06:00 -0400
34+Subject: [PATCH 2/2] chore: add torch and create random tensor
35+
36+---
37+ requirements.txt | 1 +
38+ train.py | 3 +++
39+ 2 files changed, 4 insertions(+)
40+ create mode 100644 requirements.txt
41+
42+diff --git a/requirements.txt b/requirements.txt
43+new file mode 100644
44+index 0000000..4968a39
45+--- /dev/null
46++++ b/requirements.txt
47+@@ -0,0 +1 @@
48++torch==2.3.1
49+diff --git a/train.py b/train.py
50+index 5c027f4..d21dac3 100644
51+--- a/train.py
52++++ b/train.py
53+@@ -1,2 +1,5 @@
54++import torch
55++
56+ if __name__ == "__main__":
57+ print("train!")
58++ torch.rand(3,6)
59+--
60+2.45.2
61+
fixtures/a_c_rm_commit.patch
link
+23
-0
+23
-0
1diff --git a/fixtures/a_c_rm_commit.patch b/fixtures/a_c_rm_commit.patch
2new file mode 100644
3index 0000000..c6a4c5e
4--- /dev/null
5+++ b/fixtures/a_c_rm_commit.patch
6@@ -0,0 +1,23 @@
7+From 7dbb94ca1bc8cadf1ce17dacb89172217d88de07 Mon Sep 17 00:00:00 2001
8+From: Eric Bower <me@erock.io>
9+Date: Tue, 23 Jul 2024 10:15:23 -0400
10+Subject: [PATCH] docs: readme
11+
12+---
13+ README.md | 4 +++-
14+ 1 file changed, 3 insertions(+), 1 deletion(-)
15+
16+diff --git a/README.md b/README.md
17+index 8f3a780..3043953 100644
18+--- a/README.md
19++++ b/README.md
20+@@ -1,3 +1,5 @@
21+ # Let's build an RNN
22+
23+-This repo demonstrates building an RNN using `pytorch`
24++This repo demonstrates building an RNN using `pytorch`.
25++
26++Here is some more readme information.
27+--
28+2.45.2
29+
fixtures/expected_commit_changed.txt
link
+11
-0
+11
-0
1diff --git a/fixtures/expected_commit_changed.txt b/fixtures/expected_commit_changed.txt
2new file mode 100644
3index 0000000..ac4499c
4--- /dev/null
5+++ b/fixtures/expected_commit_changed.txt
6@@ -0,0 +1,11 @@
7+1: 33c682a = 1: 33c682a chore: add torch and create random tensor
8+2: 22dde12 ! 2: 0185f34 docs: readme
9+ @@ README.md
10+ +This repo demonstrates building an RNN using `pytorch`.
11+ +
12+ +Here is some more readme information.
13+ ++
14+ ++Here is how to run this project locally:
15+ ++
16+ ++- install python and pip
17+ ++- `pip install -r requirements.txt`
go.mod
link
+1
-0
+1
-0
1diff --git a/go.mod b/go.mod
2index 4dc95e6..53504d3 100644
3--- a/go.mod
4+++ b/go.mod
5@@ -14,6 +14,7 @@ require (
6 github.com/knadh/koanf/providers/env v0.1.0
7 github.com/knadh/koanf/providers/file v1.0.0
8 github.com/knadh/koanf/v2 v2.1.1
9+ github.com/sergi/go-diff v1.1.0
10 github.com/urfave/cli/v2 v2.27.2
11 golang.org/x/crypto v0.21.0
12 modernc.org/sqlite v1.27.0
go.sum
link
+13
-2
+13
-2
1diff --git a/go.sum b/go.sum
2index 1ec46c6..5bc1160 100644
3--- a/go.sum
4+++ b/go.sum
5@@ -8,8 +8,6 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFI
6 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
7 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
8 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
9-github.com/bluekeyes/go-gitdiff v0.7.2 h1:42jrcVZdjjxXtVsFNYTo/I6T1ZvIiQL+iDDLiH904hw=
10-github.com/bluekeyes/go-gitdiff v0.7.2/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM=
11 github.com/bluekeyes/go-gitdiff v0.7.4-0.20240715034416-0a4e55f9a190 h1:k6Ep4yQtmsoP/St4bf7ofXyWc6ITB/FyGy9ewaAn5os=
12 github.com/bluekeyes/go-gitdiff v0.7.4-0.20240715034416-0a4e55f9a190/go.mod h1:QpfYYO1E0fTVHVZAZKiRjtSGY9823iCdvGXBcEzHGbM=
13 github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
14@@ -36,6 +34,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lV
15 github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
16 github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
17 github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
18+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
20 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
21 github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
22@@ -74,8 +73,11 @@ github.com/knadh/koanf/providers/file v1.0.0 h1:DtPvSQBeF+N0QLPMz0yf2bx0nFSxUcnc
23 github.com/knadh/koanf/providers/file v1.0.0/go.mod h1:/faSBcv2mxPVjFrXck95qeoyoZ5myJ6uxN8OOVNJJCI=
24 github.com/knadh/koanf/v2 v2.1.1 h1:/R8eXqasSTsmDCsAyYj+81Wteg8AqrV9CP6gvsTsOmM=
25 github.com/knadh/koanf/v2 v2.1.1/go.mod h1:4mnTRbZCK+ALuBXHZMjDfG9y714L7TykVnZkXbMU3Es=
26+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
27 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
28 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
29+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
30+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
31 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
32 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
33 github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
34@@ -107,6 +109,7 @@ github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo
35 github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
36 github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
37 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
38+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
39 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
40 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
41 github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
42@@ -119,6 +122,10 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
43 github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
44 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
45 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
46+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
47+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
48+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
49+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
50 github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
51 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
52 github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
53@@ -143,6 +150,10 @@ golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
54 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
55 golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8=
56 golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
57+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
58+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
59+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
60+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
61 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
62 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
63 lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
pr.go
link
+2
-2
+2
-2
1diff --git a/pr.go b/pr.go
2index 9e535a0..984fe92 100644
3--- a/pr.go
4+++ b/pr.go
5@@ -447,7 +447,7 @@ func (cmd PrCmd) SubmitPatchRequest(repoID string, userID int64, patchset io.Rea
6 _ = tx.Rollback()
7 }()
8
9- patches, err := parsePatchset(patchset)
10+ patches, err := ParsePatchset(patchset)
11 if err != nil {
12 return nil, err
13 }
14@@ -541,7 +541,7 @@ func (cmd PrCmd) SubmitPatchset(prID int64, userID int64, op PatchsetOp, patchse
15 _ = tx.Rollback()
16 }()
17
18- patches, err := parsePatchset(patchset)
19+ patches, err := ParsePatchset(patchset)
20 if err != nil {
21 return fin, err
22 }
range_diff.go
link
+219
-0
+219
-0
1diff --git a/range_diff.go b/range_diff.go
2new file mode 100644
3index 0000000..0df9b3e
4--- /dev/null
5+++ b/range_diff.go
6@@ -0,0 +1,219 @@
7+package git
8+
9+import (
10+ "fmt"
11+ "math"
12+
13+ "github.com/sergi/go-diff/diffmatchpatch"
14+)
15+
16+var COST_MAX = 65536
17+var RANGE_DIFF_CREATION_FACTOR_DEFAULT = 60
18+
19+type PatchRange struct {
20+ *Patch
21+ Matching int
22+ Diff string
23+ DiffSize int
24+ Shown bool
25+}
26+
27+func NewPatchRange(patch *Patch) *PatchRange {
28+ diff := patch.CalcDiff()
29+ return &PatchRange{
30+ Patch: patch,
31+ Matching: -1,
32+ Diff: diff,
33+ DiffSize: len(diff),
34+ Shown: false,
35+ }
36+}
37+
38+func output(a []*PatchRange, b []*PatchRange) string {
39+ out := ""
40+ for i, patchA := range a {
41+ if patchA.Matching == -1 {
42+ out += outputPairHeader(patchA, nil, i+1, -1)
43+ }
44+ }
45+
46+ for j, patchB := range b {
47+ if patchB.Matching == -1 {
48+ out += outputPairHeader(nil, patchB, -1, j+1)
49+ continue
50+ }
51+ patchA := a[patchB.Matching]
52+ if patchB.ContentSha == patchA.ContentSha {
53+ out += outputPairHeader(patchA, patchB, patchB.Matching+1, patchA.Matching+1)
54+ }
55+ }
56+ return out
57+}
58+
59+func outputPairHeader(a *PatchRange, b *PatchRange, aIndex, bIndex int) string {
60+ if a == nil {
61+ return fmt.Sprintf("-: ------- > %d: %s %s\n", bIndex, truncateSha(b.CommitSha), b.Title)
62+ }
63+ if b == nil {
64+ return fmt.Sprintf("%d: %s < -: ------- %s\n", aIndex, truncateSha(a.CommitSha), a.Title)
65+ }
66+ return fmt.Sprintf("%d: %s = %d: %s %s\n", aIndex, truncateSha(a.CommitSha), bIndex, truncateSha(b.CommitSha), a.Title)
67+}
68+
69+func RangeDiff(a []*Patch, b []*Patch) string {
70+ aPatches := []*PatchRange{}
71+ for _, patch := range a {
72+ aPatches = append(aPatches, NewPatchRange(patch))
73+ }
74+ bPatches := []*PatchRange{}
75+ for _, patch := range b {
76+ bPatches = append(bPatches, NewPatchRange(patch))
77+ }
78+ findExactMatches(aPatches, bPatches)
79+ getCorrespondences(aPatches, bPatches, RANGE_DIFF_CREATION_FACTOR_DEFAULT)
80+ return output(aPatches, bPatches)
81+}
82+
83+func findExactMatches(a []*PatchRange, b []*PatchRange) {
84+ for i, patchA := range a {
85+ for j, patchB := range b {
86+ if patchA.ContentSha == patchB.ContentSha {
87+ patchA.Matching = j
88+ patchB.Matching = i
89+ }
90+ }
91+ }
92+}
93+
94+func createMatrix(rows, cols int) [][]int {
95+ mat := make([][]int, rows)
96+ for i := range mat {
97+ mat[i] = make([]int, cols)
98+ }
99+ return mat
100+}
101+
102+func diffsize(a *PatchRange, b *PatchRange) int {
103+ dmp := diffmatchpatch.New()
104+ diffs := dmp.DiffMain(a.Diff, b.Diff, false)
105+ return len(dmp.DiffPrettyText(diffs))
106+}
107+
108+func getCorrespondences(a []*PatchRange, b []*PatchRange, creationFactor int) {
109+ n := len(a) + len(b)
110+ fmt.Println("rows", len(a), "cols", len(b))
111+ cost := createMatrix(n, n)
112+
113+ for i, patchA := range a {
114+ var c int
115+ for j, patchB := range b {
116+ if patchA.Matching == j {
117+ c = 0
118+ } else if patchA.Matching == -1 && patchB.Matching == -1 {
119+ c = diffsize(patchA, patchB)
120+ } else {
121+ c = COST_MAX
122+ }
123+ cost[i][j] = c
124+ }
125+ }
126+
127+ for j, patchB := range b {
128+ creationCost := (patchB.DiffSize * creationFactor) / 100
129+ if patchB.Matching >= 0 {
130+ creationCost = math.MaxInt32
131+ }
132+ for i := len(a); i < n; i++ {
133+ cost[i][j] = creationCost
134+ }
135+ }
136+
137+ for i := len(a); i < n; i++ {
138+ for j := len(b); j < n; j++ {
139+ cost[i][j] = 0
140+ }
141+ }
142+
143+ assignment := computeAssignment(cost, n, n)
144+ for i, j := range assignment {
145+ if i < len(a) && j < len(b) {
146+ a[i].Matching = j
147+ b[j].Matching = i
148+ }
149+ }
150+
151+ fmt.Println("cost", cost, "assignment", assignment)
152+}
153+
154+// computeAssignment assigns patches using the Hungarian algorithm.
155+func computeAssignment(costMatrix [][]int, m, n int) []int {
156+ u := make([]int, m+1) // potential for workers
157+ v := make([]int, n+1) // potential for jobs
158+ p := make([]int, n+1) // job assignment
159+ way := make([]int, n+1)
160+
161+ for i := 1; i <= m; i++ {
162+ links := make([]int, n+1)
163+ minV := make([]int, n+1)
164+ used := make([]bool, n+1)
165+ for j := 0; j <= n; j++ {
166+ minV[j] = math.MaxInt32
167+ used[j] = false
168+ }
169+
170+ j0 := 0
171+ p[0] = i
172+
173+ for {
174+ used[j0] = true
175+ i0 := p[j0]
176+ delta := math.MaxInt32
177+ j1 := 0
178+
179+ for j := 1; j <= n; j++ {
180+ if !used[j] {
181+ cur := costMatrix[i0-1][j-1] - u[i0] - v[j]
182+ if cur < minV[j] {
183+ minV[j] = cur
184+ links[j] = j0
185+ }
186+ if minV[j] < delta {
187+ delta = minV[j]
188+ j1 = j
189+ }
190+ }
191+ }
192+
193+ for j := 0; j <= n; j++ {
194+ if used[j] {
195+ u[p[j]] += delta
196+ v[j] -= delta
197+ } else {
198+ minV[j] -= delta
199+ }
200+ }
201+
202+ j0 = j1
203+ if p[j0] == 0 {
204+ break
205+ }
206+ }
207+
208+ for {
209+ j1 := way[j0]
210+ p[j0] = p[j1]
211+ j0 = j1
212+ if j0 == 0 {
213+ break
214+ }
215+ }
216+ }
217+
218+ assignment := make([]int, m)
219+ for j := 1; j <= n; j++ {
220+ if p[j] > 0 {
221+ assignment[p[j]-1] = j - 1
222+ }
223+ }
224+ return assignment
225+}
range_diff_test.go
link
+276
-0
+276
-0
1diff --git a/range_diff_test.go b/range_diff_test.go
2new file mode 100644
3index 0000000..3a67952
4--- /dev/null
5+++ b/range_diff_test.go
6@@ -0,0 +1,276 @@
7+package git
8+
9+import (
10+ "fmt"
11+ "testing"
12+
13+ "github.com/picosh/git-pr/fixtures"
14+)
15+
16+func bail(err error) {
17+ if err != nil {
18+ panic(bail)
19+ }
20+}
21+
22+func cmp(afile, bfile string) string {
23+ a, err := fixtures.Fixtures.Open(afile)
24+ bail(err)
25+ b, err := fixtures.Fixtures.Open(bfile)
26+ bail(err)
27+ aPatches, err := ParsePatchset(a)
28+ bail(err)
29+ bPatches, err := ParsePatchset(b)
30+ bail(err)
31+ actual := RangeDiff(aPatches, bPatches)
32+ return actual
33+}
34+
35+func fail(expected, actual string) string {
36+ return fmt.Sprintf("expected:[%s] actual:[%s]", expected, actual)
37+}
38+
39+// https://git.kernel.org/tree/t/t3206-range-diff.sh?id=d19b6cd2dd72dc811f19df4b32c7ed223256c3ee
40+
41+// simple A..B A..C (unmodified)
42+/*
43+ 1: $(test_oid t1) = 1: $(test_oid u1) s/5/A/
44+ 2: $(test_oid t2) = 2: $(test_oid u2) s/4/A/
45+ 3: $(test_oid t3) = 3: $(test_oid u3) s/11/B/
46+ 4: $(test_oid t4) = 4: $(test_oid u4) s/12/B/
47+*/
48+func TestRangeDiffUnmodified(t *testing.T) {
49+ actual := cmp("a_b.patch", "a_c.patch")
50+ expected := "1: 33c682a = 1: 1668484 chore: add torch and create random tensor\n"
51+ if expected != actual {
52+ t.Fatalf(fail(expected, actual))
53+ }
54+}
55+
56+// trivial reordering
57+/*
58+ 1: $(test_oid t1) = 1: $(test_oid r1) s/5/A/
59+ 3: $(test_oid t3) = 2: $(test_oid r2) s/11/B/
60+ 4: $(test_oid t4) = 3: $(test_oid r3) s/12/B/
61+ 2: $(test_oid t2) = 4: $(test_oid r4) s/4/A/
62+*/
63+func TestRangeDiffTrivialReordering(t *testing.T) {
64+ actual := cmp("a_b_reorder.patch", "a_c_reorder.patch")
65+ expected := `2: 22dde12 = 1: 7dbb94c docs: readme
66+1: 33c682a = 2: ad17587 chore: add torch and create random tensor
67+`
68+ if expected != actual {
69+ t.Fatalf(fail(expected, actual))
70+ }
71+}
72+
73+// removed commit
74+/*
75+ 1: $(test_oid t1) = 1: $(test_oid d1) s/5/A/
76+ 2: $(test_oid t2) < -: $(test_oid __) s/4/A/
77+ 3: $(test_oid t3) = 2: $(test_oid d2) s/11/B/
78+ 4: $(test_oid t4) = 3: $(test_oid d3) s/12/B/
79+*/
80+func TestRangeDiffRemovedCommit(t *testing.T) {
81+ actual := cmp("a_b_reorder.patch", "a_c_rm_commit.patch")
82+ expected := `1: 33c682a < -: ------- chore: add torch and create random tensor
83+2: 22dde12 = 1: 7dbb94c docs: readme
84+`
85+ if expected != actual {
86+ t.Fatalf(fail(expected, actual))
87+ }
88+}
89+
90+// added commit
91+/*
92+ 1: $(test_oid t1) = 1: $(test_oid a1) s/5/A/
93+ 2: $(test_oid t2) = 2: $(test_oid a2) s/4/A/
94+ -: $(test_oid __) > 3: $(test_oid a3) s/6/A/
95+ 3: $(test_oid t3) = 4: $(test_oid a4) s/11/B/
96+ 4: $(test_oid t4) = 5: $(test_oid a5) s/12/B/
97+*/
98+func TestRangeDiffAddedCommit(t *testing.T) {
99+ actual := cmp("a_b_reorder.patch", "a_c_added_commit.patch")
100+ expected := `1: 33c682a = 1: 33c682a chore: add torch and create random tensor
101+2: 22dde12 = 2: 22dde12 docs: readme
102+-: ------- > 3: b248060 chore: make tensor 6x6
103+`
104+ if expected != actual {
105+ t.Fatalf(fail(expected, actual))
106+ }
107+}
108+
109+// changed commit
110+/*
111+ 1: $(test_oid t1) = 1: $(test_oid c1) s/5/A/
112+ 2: $(test_oid t2) = 2: $(test_oid c2) s/4/A/
113+ 3: $(test_oid t3) ! 3: $(test_oid c3) s/11/B/
114+ @@ file: A
115+ 9
116+ 10
117+ -11
118+ -+B
119+ ++BB
120+ 12
121+ 13
122+ 14
123+ 4: $(test_oid t4) ! 4: $(test_oid c4) s/12/B/
124+ @@ file
125+ @@ file: A
126+ 9
127+ 10
128+ - B
129+ + BB
130+ -12
131+ +B
132+ 13
133+*/
134+func TestRangeDiffChangedCommit(t *testing.T) {
135+ actual := cmp("a_b_reorder.patch", "a_c_changed_commit.patch")
136+ fp, err := fixtures.Fixtures.ReadFile("expected_commit_changed.txt")
137+ if err != nil {
138+ t.Fatalf("file not found")
139+ }
140+ expected := string(fp)
141+ if expected != actual {
142+ t.Fatalf(fail(expected, actual))
143+ }
144+}
145+
146+// renamed file
147+/*
148+ 1: $(test_oid t1) = 1: $(test_oid n1) s/5/A/
149+ 2: $(test_oid t2) ! 2: $(test_oid n2) s/4/A/
150+ @@ Metadata
151+ ZAuthor: Thomas Rast <trast@inf.ethz.ch>
152+ Z
153+ Z ## Commit message ##
154+ - s/4/A/
155+ + s/4/A/ + rename file
156+ Z
157+ - ## file ##
158+ + ## file => renamed-file ##
159+ Z@@
160+ Z 1
161+ Z 2
162+ 3: $(test_oid t3) ! 3: $(test_oid n3) s/11/B/
163+ @@ Metadata
164+ Z ## Commit message ##
165+ Z s/11/B/
166+ Z
167+ - ## file ##
168+ -@@ file: A
169+ + ## renamed-file ##
170+ +@@ renamed-file: A
171+ Z 8
172+ Z 9
173+ Z 10
174+ 4: $(test_oid t4) ! 4: $(test_oid n4) s/12/B/
175+ @@ Metadata
176+ Z ## Commit message ##
177+ Z s/12/B/
178+ Z
179+ - ## file ##
180+ -@@ file: A
181+ + ## renamed-file ##
182+ +@@ renamed-file: A
183+ Z 9
184+ Z 10
185+ Z B
186+*/
187+// func TestRangeDiffRenamedFile(t *testing.T) {}
188+
189+// file with mode only change
190+/*
191+ 1: $(test_oid t2) ! 1: $(test_oid o1) s/4/A/
192+ @@ Metadata
193+ ZAuthor: Thomas Rast <trast@inf.ethz.ch>
194+ Z
195+ Z ## Commit message ##
196+ - s/4/A/
197+ + s/4/A/ + add other-file
198+ Z
199+ Z ## file ##
200+ Z@@
201+ @@ file
202+ Z A
203+ Z 6
204+ Z 7
205+ +
206+ + ## other-file (new) ##
207+ 2: $(test_oid t3) ! 2: $(test_oid o2) s/11/B/
208+ @@ Metadata
209+ ZAuthor: Thomas Rast <trast@inf.ethz.ch>
210+ Z
211+ Z ## Commit message ##
212+ - s/11/B/
213+ + s/11/B/ + mode change other-file
214+ Z
215+ Z ## file ##
216+ Z@@ file: A
217+ @@ file: A
218+ Z 12
219+ Z 13
220+ Z 14
221+ +
222+ + ## other-file (mode change 100644 => 100755) ##
223+ 3: $(test_oid t4) = 3: $(test_oid o3) s/12/B/
224+*/
225+// func TestRangeDiffFileWithModeOnlyChange(t *testing.T) {}
226+
227+// file added and later removed
228+/*
229+ 1: $(test_oid t1) = 1: $(test_oid s1) s/5/A/
230+ 2: $(test_oid t2) ! 2: $(test_oid s2) s/4/A/
231+ @@ Metadata
232+ ZAuthor: Thomas Rast <trast@inf.ethz.ch>
233+ Z
234+ Z ## Commit message ##
235+ - s/4/A/
236+ + s/4/A/ + new-file
237+ Z
238+ Z ## file ##
239+ Z@@
240+ @@ file
241+ Z A
242+ Z 6
243+ Z 7
244+ +
245+ + ## new-file (new) ##
246+ 3: $(test_oid t3) ! 3: $(test_oid s3) s/11/B/
247+ @@ Metadata
248+ ZAuthor: Thomas Rast <trast@inf.ethz.ch>
249+ Z
250+ Z ## Commit message ##
251+ - s/11/B/
252+ + s/11/B/ + remove file
253+ Z
254+ Z ## file ##
255+ Z@@ file: A
256+ @@ file: A
257+ Z 12
258+ Z 13
259+ Z 14
260+ +
261+ + ## new-file (deleted) ##
262+ 4: $(test_oid t4) = 4: $(test_oid s4) s/12/B/
263+*/
264+// func TestRangeDiffFileAddedThenRemoved(t *testing.T) {}
265+
266+// changed message
267+/*
268+ 1: $(test_oid t1) = 1: $(test_oid m1) s/5/A/
269+ 2: $(test_oid t2) ! 2: $(test_oid m2) s/4/A/
270+ @@ Metadata
271+ Z ## Commit message ##
272+ Z s/4/A/
273+ Z
274+ + Also a silly comment here!
275+ +
276+ Z ## file ##
277+ Z@@
278+ Z 1
279+ 3: $(test_oid t3) = 3: $(test_oid m3) s/11/B/
280+ 4: $(test_oid t4) = 4: $(test_oid m4) s/12/B/
281+*/
282+// func TestRangeDiffChangedMessage(t *testing.T) {}
util.go
link
+3
-3
+3
-3
1diff --git a/util.go b/util.go
2index 061bb6d..3c10da5 100644
3--- a/util.go
4+++ b/util.go
5@@ -109,7 +109,7 @@ func patchToDiff(patch io.Reader) (string, error) {
6 return str[idx:], nil
7 }
8
9-func parsePatchset(patchset io.Reader) ([]*Patch, error) {
10+func ParsePatchset(patchset io.Reader) ([]*Patch, error) {
11 patches := []*Patch{}
12 buf := new(strings.Builder)
13 _, err := io.Copy(buf, patchset)
14@@ -154,6 +154,7 @@ func parsePatchset(patchset io.Reader) ([]*Patch, error) {
15 ContentSha: contentSha,
16 RawText: patchStr,
17 BaseCommitSha: sql.NullString{String: baseCommit},
18+ Files: diffFiles,
19 })
20 }
21
22@@ -172,12 +173,11 @@ func calcContentSha(diffFiles []*gitdiff.File, header *gitdiff.PatchHeader) stri
23 authorEmail = header.Author.Email
24 }
25 content := fmt.Sprintf(
26- "%s\n%s\n%s\n%s\n%s\n",
27+ "%s\n%s\n%s\n%s\n",
28 header.Title,
29 header.Body,
30 authorName,
31 authorEmail,
32- header.AuthorDate,
33 )
34 for _, diff := range diffFiles {
35 // we need to ignore diffs with base commit because that depends
util_test.go
link
+1
-1
+1
-1
1diff --git a/util_test.go b/util_test.go
2index eaba33d..e579254 100644
3--- a/util_test.go
4+++ b/util_test.go
5@@ -15,7 +15,7 @@ func TestParsePatchsetWithCover(t *testing.T) {
6 if err != nil {
7 t.Fatalf(err.Error())
8 }
9- actual, err := parsePatchset(file)
10+ actual, err := ParsePatchset(file)
11 if err != nil {
12 t.Fatalf(err.Error())
13 }