|
2 years ago | |
---|---|---|
.. | ||
.gitignore | 2 years ago | |
README.md | 2 years ago | |
added.ts | 2 years ago | |
example-diff.js | 2 years ago | |
package-lock.json | 2 years ago | |
package.json | 2 years ago | |
revvalk.ts | 2 years ago | |
test.js | 2 years ago |
README.md
Introduction
This repository serves as a proof-of-concept and starting point for using nodegit to figure out when a file was created and when it was last updated, not based on timestamps (atime, ctime, mtime) but based solely on commit history.
Motivation
The way how timestamps are set is distribution dependent. Or in other
words, they depend on atime
option set in /etc/fstab/
. You can read
about different options in an Arch
wiki.
The way how timestamps are read also depends on access to the filesystem, which may or may not be avaiable. Overall, for the purpose of tracking when a markdown file was created and updated, this is not a universal, nor a portable solution.
Alternatives
A common solution to this problem is to store this timestamps in a database of some kind. But setting up a database just for the purpose of storing a filename and it's timestamps might not be desirable. This also adds a complexity in a form of synchronizing the filenames in the filesystem and a database.
Of course, when the database with the timestamps is already there, one could just store the entire markdown content in itm instead of just the filename, but then again, you cold not write the markdown file easily with your editor.
Solution
In a git based workflow, the required timestamps are already stored in a repository. According to a StackOverflow question this can be done like this:
# get a commit where a file foo.js was created
git log --diff-filter=A -- foo.js
Using a git-diff
documentation
we can elaborate further:
# get a commit where a file foo.js was modified
git log --diff-filter=M -- foo.js
This proves that the task can be done. However, ideally we need to do it
programatically, without the need for running bash
, which could also be
OS dependent, but natively in javascript. A layer of abstraction that
servers as a wrapper of git commands would suffice, because it would
presumably be less OS dependent.
Solution
As with the most things in a javascript world, not one, but multiple such
abstraction layers / wrappers already exists. I would not list them all
here. Instead, without any research, somehow nodegit
appealed to me as a
best tool for the job.
Running npm run dev
shows the dates when file added.ts
was created and
modified based on the commit history.
Caveat
One problem that I have found with this approach is renaming the file. We
use fileHistoryWalk
for walking the commit history. It returns an array of objects of type
<HistoryEntry>
, which looks like it is not documented in an API as of
time of writing. Each object contains a commit, a date and a status
entry. The first two are easy to work with but, since it is not documented,
at first I could not find out what that status means. Experimentally I
have found it correlates to the
diff delta enum.
We can see, that value 4 stands for RENAMED
, but since, we walk the
history of just one file, and renaming actually creates two filenames in a
commit history, this results in lost data. However, when not renaming
files, it works like a charm.
Notes
- typescript is used here instead of javascript
- date-fns is used for formatting the timestamps
Further reading
- https://github.community/t/show-file-history-for-renamed-files/1740
- https://stackoverflow.com/questions/40957424/using-nodegit-how-can-i-find-the-date-a-given-file-was-last-updated-in-a-git-re
- https://github.com/nodegit/nodegit/issues/1116
- https://github.com/nodegit/nodegit/issues/1228
- https://github.com/nodegit/nodegit/blob/master/examples/walk-history-for-file.js
- https://stackoverflow.com/questions/51609682/nodegit-filehistorywalk-doesnt-show-merge-commit
- https://stackoverflow.com/questions/40957424/using-nodegit-how-can-i-find-the-date-a-given-file-was-last-updated-in-a-git-re:w
License
MIT