Skip to content

Instantly share code, notes, and snippets.

@monochromer
Last active April 6, 2022 12:13
Show Gist options
  • Select an option

  • Save monochromer/d2f4e79d706d14cc67ce50e57c4a520e to your computer and use it in GitHub Desktop.

Select an option

Save monochromer/d2f4e79d706d14cc67ce50e57c4a520e to your computer and use it in GitHub Desktop.
git get last date commit of files
# https://stackoverflow.com/questions/32893773/how-to-git-log-with-date-time-and-file-names-in-one-line
git log --pretty=%x0a%ci --name-only \
| awk '
/^$/ { dateline=!dateline; next }
dateline { date=$0; next }
!seen[$0]++ { print date,$0 }
'
const path = require('path')
const os = require('os')
const fs = require('fs')
const { promisify } = require('util')
const { exec } = require('child_process')
const divider = '|'
const pathSeparator = path.sep
// Выводим список дат и файлов в формате `<файл> | <дата>`
const gitCommand = `
git ls-tree -r --name-only HEAD | while read filename; do
echo "$filename ${divider} $(git log -1 --format="%ad" -- $filename)"
done
`
async function main() {
const { stdout } = await promisify(exec)(gitCommand)
// создаём стуктуру вида [[<путь до файла>, <дата обновления>]] (массив массивов)
const filesDataList = stdout
.split(os.EOL)
.map(textLine => textLine
.split(divider)
.map(item => item.trim())
)
.filter(fileData => {
const [filePath] = fileData
const pathSegments = filePath.split(pathSeparator).filter(Boolean)
const tag = pathSegments[0]
return [
// учитываем только файлы, находящиеся в папках статей
['html', 'css', 'js', 'tools'].includes(tag),
// не учитывем файлы индексов статей, например, 'css/index.md'
pathSegments.length >= 3,
// исключаем файлы index.11tydata.json
!filePath.includes('index.11tydata.json')
].every(Boolean)
})
// возвращаем путь до папки самой статьи
// например, из пути `css/active/index.md` оставляем только `css/active`
.map(fileData => {
const [filePath, fileDate] = fileData
const [tag, articleName] = filePath.split(pathSeparator).filter(Boolean)
const newFilePath = [tag, articleName].join(pathSeparator)
return [newFilePath, fileDate]
})
// создаём map-структуру вида { [<путь до папки статьи>]: <дата последних обновлений в статье>}
const filesDataMap = filesDataList.reduce((hashMap, fileData) => {
const [filePath, fileDate] = fileData
hashMap[filePath] = hashMap[filePath] || []
hashMap[filePath].push(fileDate)
return hashMap
}, {})
Object.keys(filesDataMap).forEach(filePath => {
const dates = filesDataMap[filePath].map(d => new Date(d))
filesDataMap[filePath] = new Date(Math.max(...dates))
})
Object.entries(filesDataMap).forEach((fileData) => {
const [filePath, fileDate] = fileData
if (!fs.existsSync(filePath)) {
return
}
const dataFilePath = path.join(process.cwd(), filePath, 'index.11tydata.json')
const indexData = (() => {
try {
return require(dataFilePath)
} catch {
return {}
}
})()
const createDateToSave = indexData['createdAt'] ?? fileDate
const savedUpdatedDate = indexData['updatedAt']
? new Date(indexData['updatedAt'])
: createDateToSave
const timeDiff = 1000 * 60 * 60
const updateDateToSave = Math.abs(savedUpdatedDate - fileDate) < timeDiff
? savedUpdatedDate
: fileDate
const dataToSave = {
updatedAt: updateDateToSave,
createdAt: createDateToSave,
}
fs.writeFileSync(dataFilePath, JSON.stringify(dataToSave, null, 2) + '\n')
})
}
main()
.catch(console.error)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment