{"id":13498054,"url":"https://github.com/danvk/webdiff","last_synced_at":"2025-05-15T13:07:58.758Z","repository":{"id":46756402,"uuid":"21252626","full_name":"danvk/webdiff","owner":"danvk","description":"Two-column web-based git difftool","archived":false,"fork":false,"pushed_at":"2025-02-17T16:38:57.000Z","size":4337,"stargazers_count":281,"open_issues_count":38,"forks_count":39,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-05-15T13:07:53.082Z","etag":null,"topics":["diff","git-difftool","image-diffs"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danvk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"danvk"}},"created_at":"2014-06-26T19:40:43.000Z","updated_at":"2025-05-05T22:00:22.000Z","dependencies_parsed_at":"2024-07-06T15:56:16.015Z","dependency_job_id":"b4bb2815-2456-4e5a-a865-282d03fef2c6","html_url":"https://github.com/danvk/webdiff","commit_stats":{"total_commits":275,"total_committers":8,"mean_commits":34.375,"dds":0.1454545454545455,"last_synced_commit":"9df5d2f2ba657a362b1b476e34569f32b3528c6b"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fwebdiff","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fwebdiff/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fwebdiff/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danvk%2Fwebdiff/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danvk","download_url":"https://codeload.github.com/danvk/webdiff/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254346624,"owners_count":22055808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["diff","git-difftool","image-diffs"],"created_at":"2024-07-31T20:00:49.349Z","updated_at":"2025-05-15T13:07:53.750Z","avatar_url":"https://github.com/danvk.png","language":"TypeScript","funding_links":["https://github.com/sponsors/danvk"],"categories":["JavaScript","TypeScript"],"sub_categories":[],"readme":"# git webdiff\n\nTwo-column web-based git difftool.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pypi.org/project/webdiff/\" target=\"_blank\"\u003e\u003cimg alt=\"PyPI - Version\" src=\"https://img.shields.io/pypi/v/webdiff\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://dl.circleci.com/status-badge/redirect/gh/danvk/webdiff/tree/main\" target=\"_blank\"\u003e\u003cimg alt=\"CircleCI 📝\" src=\"https://dl.circleci.com/status-badge/img/gh/danvk/webdiff/tree/main.svg?style=svg\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/danvk/webdiff/blob/main/LICENSE\" target=\"_blank\"\u003e\u003cimg alt=\"License: Apache2 📝\" src=\"https://img.shields.io/github/license/danvk/webdiff\" /\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/sponsors/danvk\" target=\"_blank\"\u003e\u003cimg alt=\"Sponsor: On GitHub 💸\" src=\"https://img.shields.io/badge/sponsor-on_github_💸-21bb42.svg\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nFeatures include:\n\n* Side-by-side (two column) diff view\n* Runs in the browser of your choice on any platform.\n* Syntax highlighting via highlight.js\n* Step back and forth through multiple files in a single diff\n* Rich support for image diffs\n\n\u003c!-- These are absolute URLs so that they display on pypi.org --\u003e\n\u003c!-- This is `git webdiff 05157bba^..05157bba`, in this repo --\u003e\n![Screenshot of webdiff in action](https://raw.githubusercontent.com/danvk/webdiff/main/images/webdiff.png)\n\n\u003c!-- This is `git webdiff c80f969^..c80f969` in the dygraphs-dpxdt repo --\u003e\n![Screenshot of image diffs](https://raw.githubusercontent.com/danvk/webdiff/main/images/webdiff-images.png)\n\n## Installation\n\n    pip install webdiff\n\nor, if you prefer [Homebrew]:\n\n    brew install danvk/webdiff/webdiff\n\n(the latter will also install [ImageMagick] as a recommended dependency.)\n\n## Usage\n\nInstead of running \"git diff\", run:\n\n    git webdiff\n\nYou can also start webdiff via:\n\n    git webdiff [args]\n\nYou can pass all the same arguments that you would to `git diff`, e.g.\n`1234..5678` or `HEAD`.\n\n`webdiff` can also be invoked directly to diff two directories or files:\n\n    webdiff \u003cleft_dir\u003e \u003cright_dir\u003e\n    webdiff \u003cleft_file\u003e \u003cright_file\u003e\n\nYou can also use `webdiff` to view GitHub pull requests:\n\n    webdiff https://github.com/owner/repo/pull/123\n    webdiff '#150'  # if you're in a git repo with a github remote\n\nThis will download the files relevant to the Pull Request and run `webdiff`.\n\nIf you run into GitHub API quota limits or you'd like to use webdiff with\nprivate repos, you can set your credentials in a `.githubrc` file:\n\n    user.login: yourusername\n    user.token: your-personal-access-tokens\n\nMake sure you chmod this file to only be readable by yourself. You can generate\na personal access token for webdiff via github.com → profile → Settings →\nPersonal access tokens. Make sure to grant all the \"repo\" privileges.\n\nYou can also use `git webshow` in place of `git show` to show a single commit:\n\n    git webshow HEAD\n\n`git webshow REF` is shorthand for `git webdiff REF^..REF`.\n\n## Configuration\n\nwebdiff can be configured via [`git config`][git config]. To change the syntax highlighting theme, for example:\n\n    git config webdiff.theme rainbow\n\n(You can find a list of supported themes in the [themes] directory.)\n\nAs with any git configuration setting, these can be set globally or per-repo.\n\nOptions are:\n\n| Setting        | Default       | Notes  |\n| -------------- | ------------- | ------ |\n| webdiff.theme  | googlecode    | Syntax highlighting theme (see [themes] directory). |\n| webdiff.port   | -1            | Port on which to serve webdiff. Default is random open port. This can be overridden with the `--port` command line flag or the `WEBDIFF_PORT` environment variable. |\n| webdiff.host   | localhost     | Host name on which to serve the webdiff UI. Use `0.0.0.0` to serve publicly. The special value `\u003chostname\u003e` uses your computer's network name. This can be overridden with the `--host` command line flag or the `WEBDIFF_HOST` environment variable. |\n| webdiff.maxDiffWidth | 100 | Maximum length of lines in the diff display. After this width, lines will wrap. |\n| webdiff.unified | 8 | Lines of context to display by default (`git diff -U`) |\n| webdiff.extraDirDiffArgs | \"\" | Any extra arguments to pass to `git diff` when diffing directories. |\n| webdiff.extraFileDiffArgs | \"\" | Any extra arguments to pass to `git diff` when diffing files. |\n| webdiff.openBrowser | true | Whether to automatically open the browser UI when you run webdiff. |\n| webdiff.maxLinesForSyntax | 10000 | Maximum lines in file to do syntax highlighting. |\n| webdiff.colors.delete | #fee | CSS background color for delete (left) lines |\n| webdiff.colors.insert | #efe | CSS background color for insert (right) lines |\n| webdiff.colors.charDelete | #fcc | CSS background color for deleted characters in a delete (left) line |\n| webdiff.colors.charInsert | #cfc | CSS background color for inserted characters in an insert (right) line |\n\n## Development\n\n    poetry install\n    cd ts\n    yarn\n    # see https://github.com/webpack/webpack/issues/14532\n    NODE_OPTIONS=--openssl-legacy-provider webpack\n\nThen from the root directory:\n\n    poetry run webdiff/app.py testdata/dygraphsjs/{left,right}\n\nor to launch in debug mode:\n\n    ./test.sh $(pwd)/testdata/manyfiles/{left,right}\n\n(or any other directory in testdata)\n\nTo run the Python tests:\n\n    poetry run pytest\n\nTo format the code, run:\n\n    poetry run ruff format\n    cd ts\n    yarn prettier\n\nTo debug `git webdiff`, run:\n\n    ./test-gitwebdiff.sh\n\n## Publishing\n\nTo iterate on the PyPI package, run:\n\n    pip3 uninstall webdiff\n    poetry build\n    pip3 install dist/webdiff-?.?.?.tar.gz\n\nTo publish to pypitest:\n\n    poetry build\n    poetry publish -r testpypi\n\nAnd to the real pypi:\n\n    poetry publish\n\nSee [pypirc][] and [poetry][] docs for details on setting up tokens for pypi.\n\nPublication checklist. Do these from _outside_ the webdiff directory:\n\n- Run `webdiff webdiff/testdata/.../{left,right}`\n- Run `git webdiff 52aa15f^..52aa15f` in the codediff.js repo\n- Run `git webshow 52aa15f` from the codediff.js repo (should be same as previous command)\n- Run `webdiff https://github.com/danvk/webdiff/pull/160`\n\n## Implementation notes\n\nwebdiff doesn't calculate any diffs itself. Instead, it relies on `git diff`. This is possible because `git diff` has a `--no-index` mode that allows it to operate outside of a git repository. Of course, this means that you need to have `git` installed to use webdiff!\n\nWhen you run `webdiff dir1 dir2`, webdiff runs:\n\n    git diff --raw --no-index dir1 dir2\n\nTo ask `git` which files are adds, removes, renames and changes. Then, when it's serving the web UI for a particular diff, it runs:\n\n    git diff --no-index (diff args) file1 file2\n\nThis produces a patch, which is what the web UI renders. (It also needs both full files for syntax highlighting.)\n\nWhen you run `git webdiff (args)`, it runs:\n\n    git difftool -d -x webdiff (args)\n\nThis tells `git` to set up two directories and invoke `webdiff leftdir rightdir`.\n\nThere's one complication involving symlinks. `git difftool -d` may fill one of the sides (typically the right) with symlinks. This is faster than copying files, but unfortunately `git diff --no-index` does not resolve these symlinks. To make this work, if a directory contains symlinks, webdiff makes a copy of it before diffing. For file diffs, it resolves the symlink before passing it to `git diff --no-index`. The upshot is that you can run `git webdiff`, edit a file, reload the browser window and see the changes.\n\n[pypirc]: https://packaging.python.org/specifications/pypirc/\n[Homebrew]: https://brew.sh/\n[ImageMagick]: https://imagemagick.org/index.php\n[git config]: https://git-scm.com/docs/git-config\n[themes]: http://example.com\n[poetry]: https://python-poetry.org/docs/repositories/#publishable-repositories\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanvk%2Fwebdiff","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanvk%2Fwebdiff","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanvk%2Fwebdiff/lists"}