@@ -147,12 +147,6 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m
147
147
break
148
148
}
149
149
current := cIn .(* commitAndPaths )
150
- currentID := current .commit .ID ()
151
-
152
- if seen [currentID ] {
153
- continue
154
- }
155
- seen [currentID ] = true
156
150
157
151
// Load the parent commits for the one we are currently examining
158
152
numParents := current .commit .NumParents ()
@@ -166,8 +160,7 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m
166
160
}
167
161
168
162
// Examine the current commit and set of interesting paths
169
- numOfParentsWithPath := make ([]int , len (current .paths ))
170
- pathChanged := make ([]bool , len (current .paths ))
163
+ pathUnchanged := make ([]bool , len (current .paths ))
171
164
parentHashes := make ([]map [string ]plumbing.Hash , len (parents ))
172
165
for j , parent := range parents {
173
166
parentHashes [j ], err = getFileHashes (parent , treePath , current .paths )
@@ -176,42 +169,32 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m
176
169
}
177
170
178
171
for i , path := range current .paths {
179
- if parentHashes [j ][path ] != plumbing .ZeroHash {
180
- numOfParentsWithPath [i ]++
181
- if parentHashes [j ][path ] != current .hashes [path ] {
182
- pathChanged [i ] = true
183
- }
172
+ if parentHashes [j ][path ] == current .hashes [path ] {
173
+ pathUnchanged [i ] = true
184
174
}
185
175
}
186
176
}
187
177
188
178
var remainingPaths []string
189
179
for i , path := range current .paths {
190
- switch numOfParentsWithPath [i ] {
191
- case 0 :
192
- // The path didn't exist in any parent, so it must have been created by
193
- // this commit. The results could already contain some newer change from
194
- // different path, so don't override that.
195
- if result [path ] == nil {
196
- result [path ] = current .commit
197
- }
198
- case 1 :
199
- // The file is present on exactly one parent, so check if it was changed
200
- // and save the revision if it did.
201
- if pathChanged [i ] {
202
- if result [path ] == nil {
203
- result [path ] = current .commit
204
- }
205
- } else {
180
+ // The results could already contain some newer change for the same path,
181
+ // so don't override that and bail out on the file early.
182
+ if result [path ] == nil {
183
+ if pathUnchanged [i ] {
184
+ // The path existed with the same hash in at least one parent so it could
185
+ // not have been changed in this commit directly.
206
186
remainingPaths = append (remainingPaths , path )
187
+ } else {
188
+ // There are few possible cases how can we get here:
189
+ // - The path didn't exist in any parent, so it must have been created by
190
+ // this commit.
191
+ // - The path did exist in the parent commit, but the hash of the file has
192
+ // changed.
193
+ // - We are looking at a merge commit and the hash of the file doesn't
194
+ // match any of the hashes being merged. This is more common for directories,
195
+ // but it can also happen if a file is changed through conflict resolution.
196
+ result [path ] = current .commit
207
197
}
208
- default :
209
- // The file is present on more than one of the parent paths, so this is
210
- // a merge. We have to examine all the parent trees to find out where
211
- // the change occurred. pathChanged[i] would tell us that the file was
212
- // changed during the merge, but it wouldn't tell us the relevant commit
213
- // that introduced it.
214
- remainingPaths = append (remainingPaths , path )
215
198
}
216
199
}
217
200
@@ -222,17 +205,29 @@ func getLastCommitForPaths(c *object.Commit, treePath string, paths []string) (m
222
205
if seen [parent .ID ()] {
223
206
continue
224
207
}
208
+ seen [parent .ID ()] = true
225
209
226
210
// Combine remainingPath with paths available on the parent branch
227
211
// and make union of them
228
212
var remainingPathsForParent []string
213
+ var newRemainingPaths []string
229
214
for _ , path := range remainingPaths {
230
- if parentHashes [j ][path ] != plumbing . ZeroHash {
215
+ if parentHashes [j ][path ] == current . hashes [ path ] {
231
216
remainingPathsForParent = append (remainingPathsForParent , path )
217
+ } else {
218
+ newRemainingPaths = append (newRemainingPaths , path )
232
219
}
233
220
}
234
221
235
- heap .Push (& commitAndPaths {parent , remainingPathsForParent , parentHashes [j ]})
222
+ if remainingPathsForParent != nil {
223
+ heap .Push (& commitAndPaths {parent , remainingPathsForParent , parentHashes [j ]})
224
+ }
225
+
226
+ if len (newRemainingPaths ) == 0 {
227
+ break
228
+ } else {
229
+ remainingPaths = newRemainingPaths
230
+ }
236
231
}
237
232
}
238
233
}
0 commit comments