Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: GitHub style split diffs in your terminal (github.com/banga)
178 points by milkbikis 15 days ago | hide | past | favorite | 50 comments

I already use delta for this: https://github.com/dandavison/delta

I thought delta was fairly well-known by now so I was surprised to see this project not mention it (the readme already has a section for that). I wonder what they've chosen to do differently, besides write it in Node.js.

Yeah I (un)fortunately learned about delta too late or I probably wouldn't have made this. The main difference is that delta's default styles and appearance did not appeal to me. I'm sure it can be customized, but I wanted something that looked great by default. I especially like that the syntax highlighting matches vscode's since that's the editor I use for work.

I agree that's important! Delta's screenshot colors are so ugly that yours looks like the far superior product. It also seems more focused on diffs. I feel like I could drop in your project instantly, while delta seems to expect configuration.

> syntax highlighting matches vscode

An that's cool. I've always had a dream of having the same syntax highlighting set up everywhere: vscode, bat, vim, git diff... etc.

link is dead for me

I would much rather use this, a nice secluded statically compiled blob instead of letting node.js unspool a spaghetti of dependencies.

It’s definitely nice that delta doesn’t have a run-time dependency on node.

I use Delta and enjoy it, but using it with Git is a bit frustrating.

I wish it was able to automatically switch from side-by-side to vertical diffs depending on my terminal widt, or at least override it with --side-by-side.

Yes this is the default behavior for git-split-diffs: https://github.com/banga/git-split-diffs#narrow-terminals

Yes! This is my number one thing as well. Let me dig up the tickets...

Edit: https://github.com/dandavison/delta/issues/493#issuecomment-...

When I find myself wanting a split diff in the terminal, I tend to gravitate towards just using Vim’s built in diff mode via vim-fugitive. I even have some git aliases that will open vim and and show fugitive diffs for every file changed on the current branch.

The I like this over fancy CLI diff viewers for a handful of reasons:

- It re-uses my editor config (no need to fuss with that tools ad hoc config format)

- I can navigate the diff with my editor’s navigation tools (expand or hide context lines, open/close/reorganize tabs, etc.)

- My editor’s language-aware tooling kicks in. I can jump to def, reveal types, and find all references while reading the diffs.

I wrote more about some of the specific workflows I use in this post, if you’re curious to level up from a CLI-only diff workflow:


There’s a time and a place for CLI-only diff viewers, and kudos to the author for building a tool they enjoy! I’ve just found that they fit into a sort of uncanny valley of simplicity and power for my needs.

You and I have similar setups! I love it, but there's one thorn that I've not been able to figure out yet.

Have you (or anyone reading this) been able to figure out how to get diff-highlight to be more intelligent so that if 'foo' changes to "foo", the highlighter is smart enough to only highlight the quotes as changing, but not the word foo? (Though this example is trivial, any time you've got two changes on the same line, this issue occurs where everything in between those changes gets highlighted as well.) I noticed that other tools in this thread such as delta and banga don't suffer from this issue.

You can't configure diff-highlight to do that. It 'will find the common prefix and suffix of two lines, and consider everything in the middle to be "different".' [1]

To highlight only the quotes as changing, you need something else. On (Neo)Vim, for example, vim-gitgutter does this [2] (I'm the author).

[1] https://github.com/git/git/tree/master/contrib/diff-highligh... [2] https://github.com/airblade/vim-gitgutter/blob/master/autolo...

Thank you! I’ll check it out. I appreciate it!

gitgutter is amazing, btw. thank you.

I enjoy having good terminal ergonomics for Git.

What works for me is tig for git diffs.

Also very impressive is kitty-diff. If you use kitty as your OpenGL enabled terminal https://sw.kovidgoyal.net/kitty/kittens/diff.html

I forgot kitty has kitty-diff! I love kitty as my terminal.

You can just use icdiff to get handsome-looking split diffs in terminal. https://github.com/jeffkaufman/icdiff

in your .gitconfig

    tool = icdiff

    prompt = false

    [difftool "icdiff"]
    cmd = /usr/bin/icdiff --line-numbers $LOCAL $REMOTE | less -eFXR
then git difftool

This is cool! A bit slow to start up, probably due to starting up a node process each run, but looks great. Wondering if you have a theme that doesn't include a background color as I quite like my terminal's defaults.

The slowest operation is syntax highlighting: https://github.com/banga/git-split-diffs#performance. I have a PR out to improve that somewhat.

Good point about the themes, I'll add one. I'm hoping to make it easy to customize individual theme colors so you could unset the background colors, for example

I just use `vimdiff`, but this looks better.

Same. I mean... vim, right there already for free, and the invocation is rather ridiculously simpler.

And vimdiff is even an editor not just a viewer.

Now if it was say, Meld in a terminal, that would be worth talking about and I installing some stack as a dependency.

Bad luck! Emacs Ediff worked well for me before Git, and it still does (frequently in a tty, and preferably not with Git).

`diff -y` works in a pinch but I generally use icdiff: https://www.jefftk.com/icdiff

Related but for single pane diffs: https://github.com/so-fancy/diff-so-fancy

The diffs look beautiful. One suggestion to the author be to bundle this as a self-contained binary. This would have a huge impact on whether I want to install it.

For this, I would look into Deno, which supports self contained binaries with typescript. I've never tried it myself so not sure how much work this would be.

Yeah I looked into bundling and deno, but neither of those seemed palatable at this point. Deno’s ecosystem is still quite small, so I’d have to implement things like syntax highlighting from scratch which is not feasible. Other bundling options don’t seem all that reliable / popular and they aren’t really solving the actual issue of untrusted dependencies. So my current take is to just use node and be very conservative with dependencies.

Is anyone familiar with a good way to programatically create a diff like this as an image?

I wrote a small script that tracks changes to your kubernetes cluster and sends a diff of the yaml to Slack. It works but I want to prettify the diff with a GitHub style diff and I need it in image format to send to slack.

I actually tried to automate the screenshots for this project's readme using GitHub actions, but struggled to get it to produce the same quality screenshots as my local machine. This is the script I use for now, which has to be invoked manually: https://github.com/banga/git-split-diffs/blob/main/scripts/g...

Thank you. If you find a better way which works on a headless Linux container let me know. I would be interested in the older versions of your automation even if the output is worse quality so long as the quality is acceptable.

I've been using delta: https://github.com/dandavison/delta

It can be easily set up...

Nice work, banga!

:) thanks nayak!

I’ve been looking for just this!!! Thank you!!

Looks beautiful

This is amazing!

Awesome, thanks!

Nice work!


what should this be made with

Why Rust of course! /s

More seriously, as much as I'm personally not a huge fan of JS (but this is TypeScript?) I don't see how such comments add to the conversation. This particular package even seems to be very considerate with its dependencies: there's only a half dozen, and relate to obvious things like terminal coloring/manipulation, syntax highlighting, and diff generation… Now, I've not explored the full tree to see if those drag in the world, of course.

Sometimes, I think the hate on dependency trees gives them a bad rap. Code reuse lets people build things easily & quickly without having to badly reinvent every wheel! Sometimes, I get notified of a JS dependency with a security vulnerability where if a user can control how many spaces are used for indentation in some library's pretty-printer they can RCE and I die a little inside.

I think there are easier ways to get a side-by-side diff, but this tool does do a remarkable job of reproducing GitHub's aesthetics.

It's not about language nor dependency tree per se. It's about what is in that dependency tree. When I depend on a library A in say Python I can be reasonably sure that it won't download and execute random shit from Internet, nor that it will pull tons of other crap to log to console in colorful ANSI boxes. Basically, it's about NPM ecosystem, which is anything but trustworthy to be run as a terminal application.

EDIT: Anyway, didn't mean to shit on author's work. (S)he apparently put fair amount of work into it, and the result looks great.

This is illusory safety. The exact same risks are present in PyPI. There've been plenty of notorious malicious PyPI package incidents and there will be plenty more.

If there are dependencies, there could be security risks.

JavaScript and NPM just have higher market share, so that's where attackers are more likely to focus their efforts. This is akin to all the people who used to say Macs aren't or can't be infected with malware.

What you could do is just audit the package list and try to make a reasonable decision. 35 different packages for a small script, some with almost no GitHub stars or downloads? Maybe cause for concern. A few well-known libraries? Probably less concerning. You'd need to audit the entire lock file to really be sure, but this gives you some idea, at least.

It's true that JS developers generally seem to tend towards using a larger number of smaller libraries on average, so it's possible the risk is a bit higher both due to that and the market share, and maybe a few other reasons, but it's not like there are any fundamental differences here.

Each project will have their own way of handling dependencies, regardless of the language. You have to evaluate individual projects in any language on a case-by-case basis, and not just stereotype based on the language used. If your comment instead was ripping on the actual contents of package.json (or requirements.txt etc.), then you'd quite possibly have a valid point, but balking at the mere existence of the file is pretty ridiculous.

I think a big problem with the node ecosystem is the lack of standard library. When I'm developing on PHP, Python, or go, they have a vast standard library that means the likelihood of me using a third-party package is relatively low for the most mundane stuff. Comparing that to node, and you'll need to use an npm package for just about anything. This automatically gives you a much larger attack surface. If I understand correctly Deno is supposed to address that, but I have yet to play with it, so not sure how it works.

Definitely a valid counter-point. I'm sure for that and several other reasons, the Node package ecosystem is probably indeed the riskiest of the set. But it's still really foolish for the parent just immediately turn their nose in disgust simply at the sight of a package.json file.

Or to say "When I depend on a library A in say Python I can be reasonably sure that it won't download and execute random shit from Internet", which is just completely untrue and misguided in a lot of ways. It's absolutely just as easy for anyone to backdoor a Python package as it is to backdoor an NPM package, and it happens all the time. It's possible it could happen a lot more frequently in the future, too.

You could argue that statement's true in a sense, but given that same sense it's also true of Node; it's not a good way of thinking about dependency supply chain attacks.

You totally misunderstood my point. I wasn't talking about backdoors or supply chain attacks. When I say that a dependency downloads and executes random shit from Internet I meant it as a behavior intended to fulfill its function. The problem is that this is generally acceptable in nodejs/NPM ecosystem. In other words, the gap in dependency hygiene between nodejs/NPM and other ecosystems is huge, and users of it seems not to bother.

>When I say that a dependency downloads and executes random shit from Internet I meant it as a behavior intended to fulfill its function.

Can you give an example?

I'm aware of the banner thing, but I think that was only a few projects, and that's something else entirely.

See the link in my original post. The other things I'm aware of are ridiculous behaviors of npm packages, like create-react-app, which feels the right thing to do is to spawn my $EDITOR when it sees exception in the log (which it hides), except that the whole terminal session freezes because vim and create-react-app fight for the tty. And there are other things where authors pull in insane amount of dependencies to log in their own colorful fancy way.

But then again, I'm not that well versed in nodejs to judge by that experience alone. As I said in the middle, I'm not trying to dismiss author's work. I'm sorry for the tone of my previous replies. This comment thread I spawned is also very off-topic.

>See the link in my original post.

>Over a year ago, I was investigating using Prisma to be the ORM for a GraphQL API of a Postgres database. When doing a proof-of-concept, I discovered that under the hood @prisma/client was spinning up it's own GraphQL server that it would send requests to in order to generate SQL to send to postgres. This extra middleware layer between my frontend code and postgres generated some pretty poor performing queries that took 50% longer to complete than the queries generated by using Hasura as our whole GraphQL API.

Doesn't seem like it's worth writing off Node/JavaScript/NPM just due to this large project making a questionable design decision

>like create-react-app, which feels the right thing to do is to spawn my $EDITOR when it sees exception in the log (which it hides)

Just seems like it's Facebook's problem. I wouldn't be surprised if there's some Python package out there that does something similar. There's nothing inherent about JavaScript that makes this more likely to happen. Maybe there's something inherent about the community, but I'd really need to see a thorough empirical analysis of packages across a lot of languages before I start making judgments about that.

It might be worth making fun of a particular package if they pull in way too many other packages, but it's still all a case-by-case evaluation.

I personally strongly dislike JavaScript and much of its ecosystem, myself; it's just the kneejerk pattern-matching reaction that I thought was unwarranted.

> 99.1% TypeScript disappointment

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact