nbdime - version control for Jupyter notebooks#

Documentation: https://nbdime.readthedocs.io

With nbdime installed, in JupyterLab you’ll see a little “git” button on the toolbar for any notebook that’s under version control. Clicking on that button will show you a diff of the notebook’s state vs the version in git (the equivalent of doing at the command-line git diff <this-notebook>), in a new JupyterLab tab.

To use nbdime on a hosted hub, first we define the URL of our hub:

hub_url = "hub.cryointhecloud.com"

Accessing nbdime on the hub#

The nbdiff-web command should be executed with these parameters. You can pick the port number at will, but you need to pick a number so you can set the same value both in the -p and --base-url flags; using port 9999 for illustration:

nbdiff-web --ip 0.0.0.0 -p 9999 --base-url ${JUPYTERHUB_SERVICE_PREFIX}proxy/absolute/9999

in the folder where the notebooks under git version control that you want to diff reside.

Warning

The above command has no / between the ${JUPYTERHUB_SERVICE_PREFIX} environment variable and proxy! That variable already ends in /, and if there’s a double / in the command, the proxying will fail.

And then the following URL should be accessed:

:eval:`f"https://{hub_url}/user-redirect/proxy/absolute/9999/difftool"`

If you are working regularly in a folder, you can leave this command running and reload the page to see any new changes you’ve made.

Note

The nbdiff-web command returns immediately without printing any output if there’s no diff to show.

When instead accessing a manual diff of two files, that on a local machine would be done with nbdiff-web nb1.ipynb nb2.ipynb, you should similarly execute

nbdiff-web --ip 0.0.0.0 -p 9999 --base-url ${JUPYTERHUB_SERVICE_PREFIX}proxy/absolute/9999 nb1.ipynb nb2.ipynb

but then you need to access the URL:

:eval:`f"https://{hub_url}/user-redirect/proxy/absolute/9999/diff?base=nb1.ipynb&remote=nb2.ipynb"`

Code to semi-automate the above#

Let’s first define some little utilities that we’ll use to display cleaner code later:

from IPython.display import Markdown

def mdpre(s):
    return Markdown(f"`{s}`")

def mdcode(code, lang=''):
    tpl = f"""\
```{lang}
{code}
```"""
    return Markdown(tpl)

def mdsh(code):
    return mdcode(code, 'bash')

Now, define the command to run:

port = 9999
nbdiff_web = f"nbdiff-web --ip 0.0.0.0 -p {port} --base-url ${{JUPYTERHUB_SERVICE_PREFIX}}proxy/absolute/{port}"
nbdiff_web
'nbdiff-web --ip 0.0.0.0 -p 9999 --base-url ${JUPYTERHUB_SERVICE_PREFIX}proxy/absolute/9999'

And our base url:

# Production hub
baseurl = f"https://{hub_url}/user-redirect/proxy/absolute/{port}"
baseurl
'https://hub.cryointhecloud.com/user-redirect/proxy/absolute/9999'

Next, define the location of the file/directory we want to diff:

folder = "$HOME/dev/CryoCloudWebsite/book/how_tos/nbdime"

Now, go to the folder with your project with:

:eval:`mdsh(f"cd {folder}")`

and, once there, run the command:

:eval:`mdsh(nbdiff_web)`

and then visit :eval:`Markdown(f"[this URL]({baseurl}/difftool)")` (:eval:`mdpre(f"{baseurl}/difftool")`).

If using nbdime to diff two local files (instead of the git state), there’s a small change:

file1 = "nb1.ipynb"
file2 = "nb2.ipynb"

In this case, with two explicit files to compare, we can again go to the folder with this content:

:eval:`mdsh(f"cd {folder}")`

and, once there, run the command:

:eval:`mdsh(f"{nbdiff_web} {file1} {file2}")`

and and then visit :eval:`Markdown(f"[this URL]({baseurl}/diff?base={file1}&remote={file2})")`.