i am currently porting git-server from nodegit to isomorphic-git (adobe/git-server#47). The port has been straight forward so far, kudos to the isomorphic team!
However, there's one feature i can't find in isomorphic-git: listing all commits which affected a particular file, i.e. the eqiuvalent of
git log -- path/to/file
Any pointers/suggestions would be greatly appreciated.
Hmmm that's going to be a little tricky. I'm not sure how the canonical git does it (it may have some kind of optimized lookup table) but you could kind of brute force it with a combination of log and readObject...
OK, here's something that kinda works. It doesn't track files across renames (because that ability is still magic to me) but it finds all the commits where the SHA changed including when the file first appeared.
const git = require('.')
git.plugins.set('fs', require('fs'))
const dir = '.'
// PARAMS
const filepath = 'jest.config.js'
;(async () => {
let commits = await git.log({dir: '.'})
let lastSHA = null
let lastCommit = null
let commitsThatMatter = []
for (let commit of commits) {
try {
let o = await git.readObject({ dir, oid: commit.oid, filepath })
if (o.oid !== lastSHA) {
if (lastSHA !== null) commitsThatMatter.push(lastCommit)
lastSHA = o.oid
}
} catch (err) {
// file no longer there
commitsThatMatter.push(lastCommit)
break;
}
lastCommit = commit
}
console.log(commitsThatMatter)
})()
I ran it on isomorphic-git and here's the output:
> node test.js
[ { oid: '0d2331d49cedbcd0b5e9cf233895f691cb0b1810',
message:
'ci: expose GH_TOKEN to semantic-release script (#474)\n\n* expose GH_TOKEN to semantic-release script\n\n* chore: format code with prettier-standard\n',
parent: [ '3931d60569f1a242bba0fce99b4f9cfb506a0e42' ],
tree: 'e80591285dc42641e1ce4294cef8cbd96a77bf0e',
author:
{ name: 'William Hilton',
email: '[email protected]',
timestamp: 1537739485,
timezoneOffset: 240 },
committer:
{ name: 'GitHub',
email: '[email protected]',
timestamp: 1537739485,
timezoneOffset: 240 },
gpgsig:
'-----BEGIN PGP SIGNATURE-----\n\nwsBcBAABCAAQBQJbqArdCRBK7hj4Ov3rIwAAdHIIAJQv7tNkmk7NSlRtCHT9azkU\ncAS21EhBH6AfJt4Z+OnEzFtfXiy9b1m3UjESP9GEiVnfQOX/crkiZxx3YcNagghT\ntpwdk9GS6eLn9YhHqXQBHT+3PECcv2jLV6PeeJBOwHYU0PDaWFkoobeUsy+XxFG8\npBW8poTIZSMuq+CAyS4/9HgRH/emCs5MZt7zLmeshwy7oDiPetiNRPHN5mrg767b\nl7ldoxzL/T1Jm1hEURS30xRt/YvR2VPLDWSqPdIigWkK/IU3LDydUC0MGttJW9Ik\nIENIyHbia4tFQC7ae50yJJflCvMRKEd1P77UytUOyH1MnD0nJ2qMf62GMo+byN4=\n=MS+u\n-----END PGP SIGNATURE-----\n' },
{ oid: '3931d60569f1a242bba0fce99b4f9cfb506a0e42',
message: 'ci: switch from Travis to Azure Pipelines (#471)\n',
parent: [ 'fb3771739e5dd5fca5cfbc8f316e54ec5060fdb5' ],
tree: '4db7dffe4472713423df31e00e6e5775b2f67f46',
author:
{ name: 'William Hilton',
email: '[email protected]',
timestamp: 1537737565,
timezoneOffset: 240 },
committer:
{ name: 'GitHub',
email: '[email protected]',
timestamp: 1537737565,
timezoneOffset: 240 },
gpgsig:
'-----BEGIN PGP SIGNATURE-----\n\nwsBcBAABCAAQBQJbqANdCRBK7hj4Ov3rIwAAdHIIAKsT5F4DTeTKDnomIITx6/rB\nCQq8syo5pyIeO4/r4852gJlex+wT78hsfb36/64pEfb5fYKjN2dC+gi83hxxMn3C\nnFrRYIWt4TvRPw63/qzTEdwSj8TUxRlAjOhX8CJOo6kj8GtZI8a/DeSSFlhEGOuC\nDujy/+0xRZ7cHYCWI+qvwDyc6/0WwyFxW71tPjFaHZqhJAcMYMFh3dyuJfND9Tzw\ncGIzFBN+K91zEqCxKoHs/yvkA9gxL7H9KX2qUHG8CpZA6vc4NFRVu+8HGe4jn51K\nLOn0rdiL4qclvTrsRpV5v5hKoI16RPcVN4X+1nAkvi9nobmirVTPerW3TzsZLak=\n=iTUf\n-----END PGP SIGNATURE-----\n' } ]
compared with:
> git log -- jest.config.js
commit 0d2331d49cedbcd0b5e9cf233895f691cb0b1810
Author: William Hilton <[email protected]>
Date: Sun Sep 23 17:51:25 2018 -0400
ci: expose GH_TOKEN to semantic-release script (#474)
* expose GH_TOKEN to semantic-release script
* chore: format code with prettier-standard
commit 3931d60569f1a242bba0fce99b4f9cfb506a0e42
Author: William Hilton <[email protected]>
Date: Sun Sep 23 17:19:25 2018 -0400
ci: switch from Travis to Azure Pipelines (#471)
If that proves useful, let me know and I'll add it to the community Useful Snippets page.
@wmhilton that works for me, thanks!
Awesome! I've added it to the Snippets page. https://isomorphic-git.org/docs/en/snippets#git-log-path-to-file
@wmhilton i found a minor glitch in your snippet. if the file existed right from the start the initial commit is not returned.
this should fix it:
const git = require('.')
git.plugins.set('fs', require('fs'))
const dir = '.'
// PARAMS
const filepath = 'jest.config.js'
;(async () => {
let commits = await git.log({dir: '.'})
let lastSHA = null
let lastCommit = null
let commitsThatMatter = []
- for (let commit of commits) {
+ for (let i = 0; i < commits.length; i += 1) {
+ let commit = commits[i]
try {
let o = await git.readObject({ dir, oid: commit.oid, filepath })
+ if (i === commits.length - 1) {
+ // file already existed in first commit
+ commitsThatMatter.push(commit)
+ break;
+ }
if (o.oid !== lastSHA) {
if (lastSHA !== null) commitsThatMatter.push(lastCommit)
lastSHA = o.oid
}
} catch (err) {
// file no longer there
commitsThatMatter.push(lastCommit)
break;
}
lastCommit = commit
}
console.log(commitsThatMatter)
})()
I'm trying to do git log -- path/to/file. I used the snippet given, and it works. But it's very slow. Is there any way this feature could be added in a way that's performant? If not, do you have any tips for how I can speed up the readObject() loop for a large repo if, for example, I know that the path is a regular file, not a directory or other thing?
Most helpful comment
Awesome! I've added it to the Snippets page. https://isomorphic-git.org/docs/en/snippets#git-log-path-to-file