Ask HN: Do you ever truly use your revision history?

232 points by _bxg1 ↗ HN
Source control gives you a full history of every change that's ever been made to your codebase since its beginning. At my current company they place a huge value on that history, so much so that they haven't transitioned from SVN to git solely because of the logistical challenge of migrating 30 years of commits.

Obviously the write-only paradigm is useful when reconciling changes with others and when reverting recent, broken changes or recovering accidentally-deleted work. But to me, it seems like there's diminishing value the further back you go. I can't imagine getting much value from trawling through two-year-old commits, much less twenty-year-old commits.

So I ask: at your company and in your experience, do you get value from source-control-arachaeology? And if so, what does that look like in your case?

284 comments

[ 6.2 ms ] story [ 291 ms ] thread
I've certainly gotten some mileage out of `git bisect` over the years.
For recent commits, it is useful for figuring out causes of bugs that have been brought up recently by checking out to an earlier commit until it goes away.

As for commits that are over 2 years old, they still serve a purpose. For a legacy app that I worked on, I had `git blame` ran on every line (vim and vscode both have support), and I was able to see who worked on a block of code last. Sometimes, those developers are still there and available to ask questions which has helped me greatly.

Yes, we get a lot of value out of version history. It is a good tool to evaluate existing code. We also have experience with leaving the history behind from migrating to git.

Our case was a tooling policy issue but it should be possible to migrate from SVN to git and keep the change history. You should investigate this option.

I very rarely go back more than a month or so. Very occasionally I have gone back 10 years but only for the weirdest problems and to get a sense of what the person was thinking when they added that code. I think I could live with just 6 months of history, and in most cases 30 days and never have a problem.
As a DBA, I use git blame to see who wrote slow queries. Then I assign a jira to them. :)
If your ticket explains why the query is slow and suggests an alternative that would be faster I'd welcome that. If anything, I would expect a good DBA to do that.
Well, that level of TLC isn't going to happen when ...

- I'm doing batches of 50 at a time (quarterly review)

- the SQL doesn't make any sense in the first place.

Sometimes your name is next to that code. It’s okay, you can admit it. We’ve all done it.
I did work for a company where they had a few important vendors who would run legacy versions of their software and demand a bugfix for that version. They did this only once or twice a year, but being able to reproduce and patch old versions was enough to get some clients to shell out absurd amounts of money. These companies were swimming in cash and didn't like to learn anything new. Needing old commits is rare, but important.
Yes! My company has source that is 20-30 years old, sometimes just going through the history to see who has committed on it and checking if that person is still in the company is already a win, other times there's a code review link or a ticket system link that gives possibly more context to why something was made.

(Granted code review systems and ticket systems change overtime)

Git blame on gitlab is also a good way of getting context of why something is there to begin with.

I’m a QA engineer and I go back pretty frequently so that I can see when a issue popped up and what might have caused it. It’s super useful for root cause analysis on bugs. also I use it to troubleshoot legacy versions for customers. Although I see less of that since I work on a saas product now.
With the exception of rare uses of git blame (hate that name) to figure out who made a change so I can ask them if they happen to remember about it (and if it was more than a year so my expectation is “I don’t remember” which is fair enough)... virtually never. I don’t care if my git history is “clean” or “dirty” (if you never use a tool to make a visual of the branches then you’ll probably never notice or care).

We put Jira ticket IDs in our commits and sometimes that’s useful. But the value tends to be in the content of the tickets as much as the commits.

If we decided to squash everything more than a year or two old into a single commit I doubt it would affect us very much in practice.

> With the exception of rare uses of git blame (hate that name)

I do too, so it's worth noting that you don't have to call it that. I think it was a mistake for Subversion to introduce blame as a cute alias for annotate, but its successors (at least Mercurial and Git) have at least retained annotate as an alternative. So you can git annotate to your heart's content and never blame anyone at all.

I navigate through unfamiliar code almost daily, completely different projects and different authors. I use the blame feature a ton to understand in what context a method was added: by blaming it, I can usually see what other code was added at the same time, and its evolution.

I've used git-svn[0] to use git within svn, it's been working flawlessly in my case.

[0] https://git-scm.com/docs/git-svn

An underrated feature is “blame” in the IDE. IntelliJ or Eclipse both support showing the last commit a line was changed in in the “gutter” of the code editor.

Makes it easier to figure out how old a line of code is and (if the commit messages are any good) why it was introduced or changed.

>why it was introduced or changed.

"Fixed formatting"

That one’s easy enough. Show diff, run annotate again in the left hand side.

Which is also why I always separate my formatting and structural changes into two sequential commits. Last interesting change is easy to read, and the previous one is the work of a few extra seconds.

There is value in keeping track of who wrote each line of code. Even if it's quite old, you can still figure out the persons that originally worked on a particular project/module and ask them about it. If you reset history, this knowledge is lost.
It's very nice when your dependencies have a thorough history. I updated one of my dependencies and found one of my tests started failing. Very nice to pinpoint the exact modifications that caused the break, and I got a much speedier patch because of it. Depends how often you update your dependencies though of course
"We won't switch from SVN to git due to the logistical challenge of migration".

It would be worth switching to git if the current technical costs outweighed the costs of the migration, yes.

I think there's more to it than just "we don't need all the history, just squash it and starting with git would be better" (or even "setup authors file, git svn fetch"), though.

Often, but not to the point of more than 3 months back. To me, it's more so I can delete obsolete code instead of commenting it out, without worrying that it'll be irreversible. Or sometimes if a feature is suddenly broken we can trace if any changes were made at the time.
We switched from SVN to Git about a year and a half ago. I often use the "annotate" feature in my editor to see the history of lines of code (to figure out who to talk to when I have questions), and I routinely run into the "initial commit" wall from when everything was squashed.

I wish that when the team had migrated from SVN to git, they had used a tool that would have preserved the history. It's very easy to do! I don't know why they didn't. They did it right before I joined the company so I never had an opportunity to show them how.

It may not be too late. you could rewrite the history (but good luck syncing it to everyone)
You don't even need to rewrite the history. Create a separate repository with the converted SVN history, and tell everyone who needs it how to virtually combine both repositories through the .git/info/grafts mechanism.
Frequently. Just this evening I was looking in the HN repository for the last version of the code that pg wrote, to remind myself how he used to do something.

One of my favorite tricks is to make a file out of all the changes in the history:

  git log -p > bigass
and then grep through the file (edit: which I like to do in Emacs—hence the file) to see every appearance of some construct. There's a lot of knowledge in there. It's particularly useful when you remember that you did something, but forget how you did it.

In fact, I use git proactively this way, to store things in the version history that I might want to remember later. For example, if I write exploratory code to test out a feature or throwaway code to do some analysis—anything I might want to use again, but don't want to commit to the codebase—I'll add it as a commit and then immediately revert the commit (i.e. make a new commit that deletes what I just added). The codebase remains unchanged, but what I just did is now there forever for future me to recover.

Such an approach only works if your system is small, but I like to work on small systems and prevent them from becoming large systems. There's a beneficial feedback loop here: as you get comfortable working with history, it gives you more confidence to delete things, helping to keep the system small.

I've also found this technique useful for solving the chronic problem with documentation: that it inevitably fails to get updated. When I write something about the code, I commit it and, as above, immediately revert the commit. Now it's permanently glued to the state of the code when I wrote it. When I read it in the future, I can do so alongside a diff of the code from then to now. This makes it easy to see what has changed in the meantime, in which case I can update the document and commit/revert it again.

Along these lines: git-log has a --grep option which returns only commit messages that match a regex, and git-grep searches over revision controlled files like above.

>I like to work on small systems and prevent them from becoming large systems.

This is very wise!

Similarly, ‘git log -S needle’ will surface all commits with ‘needle’ in the diff.
Yeah, the grep option is on the log messages. Use -G if you want the regex in the diff.
This is good. I'm stealing it. It's using git as sort of a super-brain, helping you remember stuff you wouldn't otherwise. It's how I use gmail. Instead of shooting for inbox zero, I just leave anything in there that I might want to remember later and delete the rest. Then, many times years later, I can search through looking for important correspondence. Both of these stories are good examples of how simple but flexible tools can be used perhaps in ways not anticipated by their creators or the majority of their users.
I use gmail the same way. I do feel that the search functionality could be improved though which I find ironic.
Gmail search used to be the best. Now it fails to find anything useful most of the time
I use gmail that way too! Never made the connection to the git thing though.
Inbox zero isn’t deleting everything, it’s archiving those that are done so they aren’t in your immediate inbox.

What you’re doing sounds compatible with that.

What's the advantage of doing this over just making an experiment branch? A branch would be easier to find than a reverted commit somewhere in the mainline branch.
For me I end having a bunch of “exper-xyz” (experimental) branches that are often small changes that I may never merge into master. The problem is I loose context of that branch, so I kind of like the idea of the reverted commits, will need to try it, for small changes at least.
Then I'd have too many branches and no longer a single place to search.
> For example, if I write exploratory code to test out a feature or throwaway code to do some analysis—anything I might want to use again, but don't want to commit to the codebase—I'll add it as a commit and then immediately revert the commit (i.e. make a new commit that deletes what I just added).

Why not use a named stash for something like this? It'll keep your history cleaner, and you can always find the stash by name later.

Can stashes be pushed to a remote repo?
Too complicated for me. I didn't even know that named stashes were a thing, and I wouldn't remember the names.

The nice thing about the approach is that there's only one place to look. I don't think it makes the history less clean, since it only contains things that were at some point, if only briefly, in the system.

I find the temporarily localized documentation idea quite interesting – anyone else here tried that?

> Such an approach only works if your system is small,

I see no reason why this wouldn't scale if you (and other people working on the same codebase) just maintain individual branches (say "dang-braindump"). Just do exploratory/documentation work on that and cherry-pick, rebase -i or git merge --ff --squash --no-commit to skip the reverts.

> I find the temporarily localized documentation idea quite interesting – anyone else here tried that?

I've done this a bit.

For several of my $DAYJOB projects I maintain documentation as Markdown files in the project, which get rendered into a website at build time. The project changelog is kept in version control the same way (https://keepachangelog.com).

Several times I've tried an experiment or alternate approach that didn't work out and done exactly this, complete with documentation, so the state is preserved. It's easy to document a prototype if it just means throwing a few paragraphs into a text file with the prototype.

Add a note in the changelog about adding the prototype then commit.

Make the revert commit and add a note in the changelog that you've removed the prototype.

Keeping a good, human-readable changelog as described above makes this strategy more scalable. You can document failed experiments you backed out, features that have been removed, and the like, in a few quick summary lines, keeping devs aware of them across the project's lifespan.

New devs can review it for the big-picture history and use the changelog's revision history to see what commits they need to see for the details.

Using a changelog this way also makes it reasonably possible to delete code but still remember it existed years later, something that's otherwise a surprisingly hard problem (especially if the project has high turnover).

Thanks for sharing! I'm not a big fan of changelogs, personally, except for publicly released projects. I prefer to have workflows that use version control for this. Reverting on master, but tracking the prototype in the changelog is a nice hack, but has a cost in terms of clutter, ability to bisect etc. I think I would prefer something branch based, but I haven't yet properly thought about the best way of doing it. If you have a special prototype branch from which you merge in master and do your prototyping, reverting and optionally notes.md there, you might effectively be able to replace the changelog based flow with just doing git log --no-merges --first-parent. What do you think?
I think as the number of branches grows, people will just start to drown in the huge list of unmerged branches and will start to work as if only trunk/master exists.

With a text file that summarizes all the project's main line of history in a structured, linear way, it's very simple to extract just what you're interested in or find all the entries for a particular thread of research across history, quickly.

I don't think the tooling around git branches really enables that kind of operation in a quick, easy way, partly due to the inherent nature of branches.

I'd be interested to see what your hypothetical workflow turns out like in practice, though. It's certainly possible I'm just not seeing the potential.

You can pipe through `less` and then search using `/`, no need to redirect into a file (and this way you don't have to wait for the history to be done dumping before you start your search, which can be a pain for very huge repos).
I do that when I know just what I'm searching for, but for this sort of meandering around, I prefer to explore a file in Emacs. I can quickly get a list of everything that matches a certain regex and hop between the locations etc. It's much easier and faster (for me—a lot of this is just whatever one's used to). You're right that for a much larger repo, waiting for a file to dump, not to mention Emacs to open it, would make this impratical.
> git log -p > bigass

> and then grep through the file (edit: which I like to do in Emacs—hence the file)

Since you already have Emacs, I would suggest you do M-& git log -p RET instead. No need to round-trip the data through a file.

I had a feeling someone would come up with a suggestion like this! Cunningham's Law and all that. Posting wrong or insufficient things on the internet is a great learning strategy.

However, I get:

  WARNING: terminal is not fully functional
  -  (press RETURN)
and on pressing return, I only get enough data to fill the buffer.
I always set PAGER=cat in Emacs. If you're running a VT100 emulator in Emacs this may be bad, otherwise it avoids the problem your describe.
I’m stealing this too! I often try to persist exploratory history as separate remote branches, but for some reason a lot of the devs I’ve worked with are very adamant about deleting any and all “unneeded” branches, and I end up appending such branch names with a “-dont-delete”, but that starts to get abit passive aggressive. Now I can just do this and nobody needs to know
Or at least by the time they know, it will be too late :)

There are some disadvantages. It can mess with git bisect, for example.

I use it to find more detail about a particular line. Often knowing when something was added, who added it and what was the commit message helps me understand the reasoning behind some particularly weird or legacy code. In some projects this can lead you to a pull request link, with even more context.
For sure. And unlike comments or documentation, it never lies.
I'd second that. I've also used old revisions to try and figure out when a particular bug I've found was introduced too.

Depending on how long it's been there can help you assign a priority, e.g. minor bug has existed for 10 years without anyone noticing is probably not something you have to fix right now. The opposite of that is a nasty bug has existed for 10 years until some data structures or control flow changed and exposed it, so it's not a hard and fast rule.

Once or twice I've seen bugs be introduced by merging huge commits from another branch, so there's lessons to be learned from history too. In this case, avoid large merges with conflicts, especially something you cherry-picked.

First git project, had a guy who loved deflecting, hated git, and had a habit of fucking up merges. Let’s call him Steve.

Some code got broken and Steve immediately throws Jim under the bus. I look at the commit history, and sure enough git blame shows Jim broke it. Except... there was one little problem: I was the one who signed off on that code. I was specifically looking for this exact class of bug before I approved it, and was pleasantly surprised to see that the author had already anticipated this problem.

So what the hell happened?

Steve happened. Steve fucked up (another) three way merge and I didn’t catch it this time. I found the original commit hash and sure enough the code was correct. So then I showed Steve, again, what I call a Five Way Merge (3 way merge, then resolve again against both parents) and made it pretty clear this was no longer a strong suggestion and now a demand that he use this method to do merges.

Not archaeology, but I use git reflog constantly as my workflow:

I push to master infrequently. I keep a series of topic branches off of master, one per project phase. For changes that affect other developers, I pull those out and PR them to master, then rebase the topic branch chain once the PR completes. When I switch projects I use git reflog to remember where I was working.

Basically I take advantage of git rebase and use it like time travel constantly. Somehow I stay sane..

Practically daily. Every bugfix or feature starts with looking at the already done mistakes engraved in the tree.

Though we stand on shoulders of midgets usually, you still get a better view.

We just switched from Perforce to git at work, and about the first 2/3 of a project I work on got squashed together. It took me less than a week to bump in to that "initial commit" when trying to figure out why a bit of code is the way it is.

"git blame" (or the p4 equivalent) is my usual archaeologic tool in this context, but "git bisect" has been very helpful in others. For the first, it should be easy to look at your current codebase in SVN and see how far back the history goes in any particular area. I've found that bisection is most useful for relatively recent history, because I usually have wanted to build or run the software to test for a bug or something - beyond some point in history that becomes impractical.

Moving from SVN to git shouldn't require losing history though...

+1 for git bisect, criminally underrated!
Reverts that get to master can royally screw up git bisect.
I spent a couple months experimenting with p4git to make sure we got a real history imported. They didn’t get every repository right and I made them redo a few, did a few others over again myself.

But lately I’ve been delving into some of the early architectural changes, trying to figure out why a bunch of things get loaded and seemingly never used/only used once... and sure enough someone did some sort of single commit repository split or bull transfer into p4 in the first place... so I have no clues why.

And yes, I use commit history all the time. Fewer secondary bugs from bug fixes. Fewer lines changed per fix, and fixing bugs nobody else can figure out. Started when someone was furious that a bug had been reintroduced twice. Two devs were alternating fixes for two bugs that caused each other. Good times.

If anything I want more commit history. I want to be able to go back and add notes to commits for posterity, or at least for myself in six months when I have forgotten because I haven’t looked at this module once in that time.

> I want to be able to go back and add notes to commits

Interesting idea - how about using tags for this?

Possible. There’s also another feature that several people have pointed out could be used for this purpose but as with so many things in git, it’s not seamless. Might still be worth using though, even if it only helps a few of us.
I'm in a similar boat with you, so I have a few questions:

1. Why did you switch? Are you satisfied with the new experience?

2. Why was some of the history needed to be squashed? Were there any technical concerns?

1a) I wasn't involved in the initial decision to switch, but gather it came down to expense and some unsupported perforce-related tooling.

1b) Absolutely! The switch from p4 could've been smoother, but git and access to the associated ecosystem is far ahead of Perforce for everything except storing binaries. We've been abusing p4 by storing electronics CAD files and similar, and do need to put some effort in to a new solution there. For source code, git (and the ecosystem of modern tooling it gives access to) is a huge improvement over p4.

A particular improvement has to do with network latency. Working from halfway around the world, I notice that p4 operations involving many files are very much slower than the similar git operations.

2a) I wasn't involved, but the particular project mentioned above had moved within the depot at some point, so guess the conversion tool that was used to move it couldn't manage that move. I intend to rebuild the older history in git, then see how viable it is to use git-replace to stick it on the beginning of what we have now.

2b) Yes. However, nontechnical concerns dominated conversation by far - to the detriment of the technical concerns.

Frequently. Whenever I run into something that makes little sense to me, I go back and look at the commit messages, the related bugs, the evolution of the code, and who wrote it.

It's called software archeology. It's not important if you keep exactly the same people working on the same project and they have perfect memory. But if you, say, move people between different teams, or lose people, or hire people, it's a gold mine.

Lots of the value for me is in well written commit message bodies.

Especially if I have written them since when someone asks me how something works or why it's written that way I can read the commit body and explain it to them/refer them to the message (otherwise my answer is, I don't remember!)

Additionally if you choose your changes well and don't squash commits it can be a good guide to what else touches the thing I'm looking at.

I regularly find myself trawling back through code that's 5+ or 10+ years old, and the best way to understand a detail of code can be to look back to the commit message where it was documented.
One of the more frequent uses of source history where I work is to see when an issue was introduced to help gauge the priority of a fix. When something is discovered and someone wants to make it a stop-the-presses fix-it-now type thing, we look back in history to see when the change was introduced. If it's been there a while, and especially if an external customer has never created a ticket on it, we come back and say, "Well, it's been that way for five years now, so why don't we just put it into the next scheduled release instead of an off-cycle emergency fix."