Git Product home page Git Product logo

webdiff's Introduction

git webdiff

Two-column web-based git difftool.

PyPI - Version CircleCI ๐Ÿ“ License: Apache2 ๐Ÿ“ Sponsor: On GitHub ๐Ÿ’ธ

Features include:

  • Side-by-side (two column) diff view
  • Runs in the browser of your choice on any platform.
  • Syntax highlighting via highlight.js
  • Step back and forth through multiple files in a single diff
  • Rich support for image diffs

Screenshot of webdiff in action

Screenshot of image diffs

Installation

pip install webdiff

or, if you prefer Homebrew:

brew install danvk/webdiff/webdiff

(the latter will also install ImageMagick as a recommended dependency.)

Usage

Instead of running "git diff", run:

git webdiff

You can also start webdiff via:

git webdiff [args]

You can pass all the same arguments that you would to git diff, e.g. 1234..5678 or HEAD.

webdiff can also be invoked directly to diff two directories or files:

webdiff <left_dir> <right_dir>
webdiff <left_file> <right_file>

You can also use webdiff to view GitHub pull requests:

webdiff https://github.com/owner/repo/pull/123
webdiff '#123'  # if you're in a git repo with a github remote

This will download the files relevant to the Pull Request and run webdiff.

If you run into GitHub API quota limits or you'd like to use webdiff with private repos, you can set your credentials in a .githubrc file:

user.login: yourusername
user.token: your-personal-access-tokens

Make sure you chmod this file to only be readable by yourself. You can generate a personal access token for webdiff via github.com โ†’ profile โ†’ Settings โ†’ Personal access tokens. Make sure to grant all the "repo" privileges.

Configuration

webdiff can be configured via git config. To change the syntax highlighting theme, for example:

git config webdiff.theme rainbow

(You can find a list of supported themes in the themes directory.)

As with any git configuration setting, these can be set globally or per-repo.

Options are:

Setting Default Notes
webdiff.theme googlecode Syntax highlighting theme (see themes directory).
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.
webdiff.host localhost Host name on which to serve the webdiff UI. Use 0.0.0.0 to serve publicly. The special value <hostname> uses your computer's network name. This can be overridden with the --host command line flag or the WEBDIFF_HOST environment variable.
webdiff.maxDiffWidth 100 Maximum length of lines in the diff display. After this width, lines will wrap.
webdiff.unified 8 Lines of context to display by default (git diff -U)
webdiff.extraDirDiffArgs "" Any extra arguments to pass to git diff when diffing directories.
webdiff.extraFileDiffArgs "" Any extra arguments to pass to git diff when diffing files.
webdiff.openBrowser true Whether to automatically open the browser UI when you run webdiff.
webdiff.maxLinesForSyntax 10000 Maximum lines in file to do syntax highlighting.
webdiff.colors.delete #fee CSS background color for delete (left) lines
webdiff.colors.insert #efe CSS background color for insert (right) lines
webdiff.colors.charDelete #fcc CSS background color for deleted characters in a delete (left) line
webdiff.colors.charInsert #cfc CSS background color for inserted characters in an insert (right) line

Development

python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cd ts
yarn
# see https://github.com/webpack/webpack/issues/14532
NODE_OPTIONS=--openssl-legacy-provider webpack

Then from the root directory:

PYTHONPATH=. ./webdiff/app.py testdata/dygraphsjs/{left,right}

or to launch in debug mode:

./test.sh $(pwd)/testdata/manyfiles/{left,right}

(or any other directory in testdata)

To run the Python tests:

pytest

To format the code, run:

./scripts/black.sh
cd ts
yarn prettier

To debug git webdiff, run:

WEBDIFF_CONFIG=$(pwd)/testing.cfg ./webdiff/gitwebdiff.py

To iterate on the PyPI package, run:

# from outside the webdiff virtualenv:
pip3 uninstall webdiff

# from inside the webdiff virtualenv, adjust for current version
python setup.py sdist
mkdir /tmp/webdiff-test
cp dist/webdiff-?.?.?.tar.gz /tmp/webdiff-test

deactivate
cd /tmp/webdiff-test
pip3 install webdiff-?.?.?.tar.gz

To publish to pypitest:

pip install --upgrade wheel setuptools twine
python setup.py sdist bdist_wheel
twine upload -r testpypi dist/*

And to the real pypi:

twine upload dist/*

See pypirc docs for details on setting up ~/.pypirc.

Implementation notes

webdiff 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!

When you run webdiff dir1 dir2, webdiff runs:

git diff --raw --no-index dir1 dir2

To ask git which files are adds, removes, renames and changes. Then, when it's serving the web UI for a particular diff, it runs:

git diff --no-index (diff args) file1 file2

This produces a patch, which is what the web UI renders. (It also needs both full files for syntax highlighting.)

When you run git webdiff (args), it runs:

git difftool -d -x webdiff (args)

This tells git to set up two directories and invoke webdiff leftdir rightdir.

There'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.

webdiff's People

Contributors

danvk avatar daytonb avatar nikolasoliveira avatar ryan-williams avatar xuv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

webdiff's Issues

Stage/Unstage/commit diffs from browser

Check out GitX; it has not been updated since 2009 AFAICT but I use it as a pretty handy diff viewer / commit-creation tool. Notable features:

  • stage/unstage diffs
    • per file
    • per logical diff chunk
    • per line
  • type commit messages / create commits
  • bonus: ammend commits
    • somewhat hackily implemented / buggy

GitX has some annoying issues:

  • no way to turn off OSX spell-checker by default (always turns on at start up), leading to many DYACs in commit msgs
  • sometimes mysteriously spins with 100% CPU in background when it shouldn't be doing anything
  • generally kind of slow
  • could use some hot-key love

Some of GitX combined with your vision for webdiff could be really killer: better diffing (e.g. inline diff highlighting), syntax highlighting, general web-interface goodness, reflecting changes on disk in realtime, allowing inline editing?!!! so many possibilities.

Would love to port my existing GitX flow (stage/unstage/commit) to webdiff to start, though.

Added files are too green

The bright shade of green gets used for pure adds. A lighter shade would be easier to look at let the syntax highlighting shine through. The green is not very information-rich in a pure add.

Show image diffs

Since browsers are already good at showing images, this shouldn't be too difficult.

For bonus points, show a perceptual diff!

Show tabs in the UI

Rietveld & co show a red โ‰ซ symbol.

Should allow custom tab widths. Default should probably be 8.

Show more compact renames

github does this well. On this PR, for example, it shows the file rename this way:

cycledash/static/js/examine/{examine.js โ†’ ExaminePage.js}

This is much better than what webdiff shows at the moment:

cycledash/static/js/examine/examine.js โ†’ cycledash/static/js/examine/ExaminePage.js

"pip install webdiff" fails on Yosemite

I'm getting an error installing the latest update in yosemite:

running pip install webdiff generates this error:

Command /usr/bin/python -c "import setuptools, tokenize;__file__='/private/tmp/pip_build_root/pillow/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-09Jsha-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /private/tmp/pip_build_root/pillow
Storing debug log for failure in /Users/adam/Library/Logs/pip.log

Add a "shrink to fit" button for image diffs

This would shrink the images to fit in the current browser window. Behavior would have to be different for side-by-side (which always shows two images) and the other modes (which use one image's worth of space).

Add support for merges

The git UI for merges is confusing:

<<<blah
blah
======
blah
>>>blah

It would be nice if webdiff could show the three-way merge.

Double scroll bars

See screenshot, I'm getting a scrollbar on both the container page and the iframe'd page.
screen shot 2014-07-10 at 6 47 06 pm

Running "webdiff #292" in dygraphs repo fails

Here's the error I see:

$ git remote -v
origin  [email protected]:danvk/dygraphs.git (fetch)
origin  [email protected]:danvk/dygraphs.git (push)

$ webdiff #292
Traceback (most recent call last):
  File "/usr/local/bin/webdiff", line 11, in <module>
    sys.exit(run())
  File "/usr/local/lib/python2.7/site-packages/webdiff/app.py", line 228, in run
    parsed_args = argparser.parse(sys.argv[1:])
  File "/usr/local/lib/python2.7/site-packages/webdiff/argparser.py", line 49, in parse
    owner, repo, num = github_fetcher.get_pr_repo(num)
  File "/usr/local/lib/python2.7/site-packages/webdiff/github_fetcher.py", line 77, in get_pr_repo
    remotes = _get_github_remotes()
  File "/usr/local/lib/python2.7/site-packages/webdiff/github_fetcher.py", line 113, in _get_github_remotes
    return [parse(remote.group(3)) for remote in remotes]
  File "/usr/local/lib/python2.7/site-packages/webdiff/github_fetcher.py", line 110, in parse
    assert m, 'Unable to parse github remote %s' % remote
AssertionError: Unable to parse github remote git

Detect move + change

git commit is fairly good about detecting when you move + modify a file. git webdiff detects pure moves, but it should also detect move + modify in a similar way to how git does it. I'd assume the algorithm involves % of identical lines, or % of the file that's covered by identical diffhunks.

Support for submodules

when inside the submodule directory, running webdiff returns an error:

fatal: Could not switch to '../../../../Submodules/': No such file or directory
diff --raw --no-abbrev -z: command returned error: 128

contents of the .git in the submodule directory is:

../../.git/modules/Submodules/mixpanel

lmk if you need anything else to repro, but i'm pretty sure this is true for any submodule

Quick views of PR files by status

Looking at this PR:

1 file added, 49 modified, 67 deleted:

$ gd --name-status $oh..$pr/478 | first | hist 1 A 49 M 67 D

Github PR view is really bogged down by all the contents of the deleted files:

Resulting in me doing things like:

# grep for Modified files and diff them
$ gd $oh..$pr/478 -- $(gd --name-status $oh..$pr/478 | grep '^M' | col 1)

It would be cool if we provided some enhanced capabilities for slicing/dicing PRs, e.g.

  • show only names of deleted files
  • filter to view to only Modified, Deleted, or Added files

Show diffstats

This would be simple to add and would make it clear where the big changes are.

Fetch github files lazily

This would make the initial diff load more quickly and reduce the likelihood of exhausting your API request limit.

It might require some refactoring, since this would break the model that webdiff always diffs two directories.

Tests are failing

$ nosetests
....F.
======================================================================
FAIL: pair_test.test_pairing_with_move
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/Users/danvk/github/webdiff/tests/pair_test.py", line 42, in test_pairing_with_move
    {'a': 'file.json', 'path': 'file.json', 'b': None, 'type': 'delete', 'idx': 1}], diff)
AssertionError: [{'a': 'file.json', 'path': 'file.json', 'b': 'renamed.json', 'type': 'move', 'idx': 0}, {'a': 'file.json', 'path': 'file.json', 'b': None, 'type': 'delete', 'idx': 1}] != [{'a': 'file.json', 'no_changes': True, 'b': 'renamed.json', 'idx': 0, 'path': 'file.json', 'type': 'move'}, {'a': 'file.json', 'no_changes': False, 'b': None, 'idx': 1, 'path': 'file.json', 'type': 'delete'}]

----------------------------------------------------------------------
Ran 6 tests in 0.095s

FAILED (failures=1)

Support GitHub auth

It's fairly easy to hit GitHub's rate limit with webdiff's pull request feature. There should be an easy way to OAuth in.

Detect file renames

"git diff" does a terrible job of this, but it should be easy to detect pure renames in webdiff. Detecting rename + modification is harder, but I'm sure there are good algorithms for this.

Reloading diff kills the web server

webdiff listens for the onbeforeunload event and kills the web server when it fires. This usually corresponds to closing the web server, so this behavior makes sense. But if you reload, the event also fires and the reload will fail.

A solution might be to wait 0.5 seconds before killing the server.

Run webdiff with two files

This would let you use webdiff in place of plain-old diff. Currently it requires two directories as parameters, but it would be nice if it could accept two files as well.

Large diffs hang the browser

If you try to view changes to a very large file (say a 4 MB one line JSON file), the browser will just hang.

Better behavior would be to say something like "large file (4,567,890 bytes)".

Add a "stage" button when run as "git webdiff"

A frequent use case is to run git webdiff to review your unstaged changes in a git repo. When run this way, it would be helpful to have a "stage" button which git adds the file you're looking at.

This is a less ambitious version of #11.

Closing diff window sometimes logs stack trace

Here's an example session:

$ webdiff https://github.com/hammerlab/cycledash/pull/200/files
Loading pull request hammerlab/cycledash#200 from github...
  __tests__/pdifftests/examine-charted.png...
  __tests__/pdifftests/examine-sorted.png...
  __tests__/pdifftests/examine-tooltip.png...
  __tests__/pdifftests/examine.png...
Serving diffs on http://localhost:51234
Close the browser tab or hit Ctrl-C when you're done.
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 51342)
Traceback (most recent call last):
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 321, in process_request
    self.finish_request(request, client_address)
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 334, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 651, in __init__
    self.finish()
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 710, in finish
    self.wfile.close()
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 279, in close
    self.flush()
  File "/usr/local/Cellar/python/2.7.6_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 303, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe
----------------------------------------

^C%

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.