Skip to content

shallow clone cannot switch branches #379

@minrk

Description

@minrk

Bug description

When a shallow clone is used (now the default after #117), and visited an updated URL with a new branch with an update to pull, pull fails with:

File "/opt/conda/lib/python3.13/site-packages/nbgitpuller/pull.py", line 208, in find_upstream_changed
    output = subprocess.check_output([
             ~~~~~~~~~~~~~~~~~~~~~~~^^
        'git', 'diff', '..origin/{}'.format(self.branch_name),
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        '--name-status'
        ^^^^^^^^^^^^^^^
    ], cwd=self.repo_dir).decode()
    ^^^^^^^^^^^^^^^^^^^^^
File "/opt/conda/lib/python3.13/subprocess.py", line 472, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
           ~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               **kwargs).stdout
               ^^^^^^^^^
File "/opt/conda/lib/python3.13/subprocess.py", line 577, in run
    raise CalledProcessError(retcode, process.args,
                             output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['git', 'diff', '..origin/main', '--name-status']' returned non-zero exit status 128.

The actual error from git is:

fatal: ambiguous argument '..origin/main': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

This can be fixed by explicitly fetching the new branch:

git fetch --depth 1 origin "+refs/heads/main:origin/main"

How to reproduce

  1. make a shallow clone of a repo (e.g. with nbgitpuller default)
  2. push an update to the repo
  3. visit nbgitpuller link a second time
  4. see above error

Actual behaviour

All future visits to nbgitpuller URL fail with:

File "/opt/conda/lib/python3.13/site-packages/nbgitpuller/pull.py", line 208, in find_upstream_changed
    output = subprocess.check_output([
             ~~~~~~~~~~~~~~~~~~~~~~~^^
        'git', 'diff', '..origin/{}'.format(self.branch_name),
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        '--name-status'
        ^^^^^^^^^^^^^^^
    ], cwd=self.repo_dir).decode()
    ^^^^^^^^^^^^^^^^^^^^^
File "/opt/conda/lib/python3.13/subprocess.py", line 472, in check_output
    return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
           ~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
               **kwargs).stdout
               ^^^^^^^^^
File "/opt/conda/lib/python3.13/subprocess.py", line 577, in run
    raise CalledProcessError(retcode, process.args,
                             output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['git', 'diff', '..origin/main', '--name-status']' returned non-zero exit status 128.

reproduce without nbgitpuller

You can reproduce the same steps with just the git commands nbgitpuller uses:

ovyan@jupyter-benjaminrk-gmail-com---f8198f73:/tmp$ git clone --depth 1 --branch behind https://github.com/minrk/cgm-sandbox
Cloning into 'cgm-sandbox'...
remote: Enumerating objects: 29, done.
remote: Counting objects: 100% (29/29), done.
remote: Compressing objects: 100% (28/28), done.
remote: Total 29 (delta 0), reused 24 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (29/29), 424.59 KiB | 4.25 MiB/s, done.
jovyan@jupyter-benjaminrk-gmail-com---f8198f73:/tmp$ cd cgm-sandbox/
jovyan@jupyter-benjaminrk-gmail-com---f8198f73:/tmp/cgm-sandbox$ git diff ..origin/main --name-status # fails
fatal: ambiguous argument '..origin/main': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

# explicitly fetch origin/main
jovyan@jupyter-benjaminrk-gmail-com---f8198f73:/tmp/cgm-sandbox$ git fetch --depth 1 origin "+refs/heads/main:origin/main"
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 5), reused 4 (delta 3), pack-reused 0 (from 0)
Unpacking objects: 100% (6/6), 1.37 KiB | 469.00 KiB/s, done.
From https://github.com/minrk/cgm-sandbox
 * [new branch]      main       -> origin/main
jovyan@jupyter-benjaminrk-gmail-com---f8198f73:/tmp/cgm-sandbox$ git diff ..origin/main --name-status
M       extensions.py
M       overlays.py
M       viewer.py
M       visualize_sample.ipynb

Your personal set up

  • OS: ubuntu 24.04
  • 2i2c jupyter-health deployment
Full environment
aiohappyeyeballs==2.6.1
aiohttp==3.12.15
aiosignal==1.4.0
alembic==1.16.5
altair==5.5.0
annotated-types==0.7.0
anyio==4.11.0
archspec==0.2.5
argon2-cffi==25.1.0
argon2-cffi-bindings==25.1.0
arrow==1.3.0
asttokens==3.0.0
async_generator==1.10
async-lru==2.0.5
attrs==25.3.0
babel==2.17.0
beautifulsoup4==4.14.2
black==25.1.0
bleach==6.2.0
blinker==1.9.0
bokeh==3.8.0
boltons==25.0.0
Bottleneck==1.6.0
Brotli==1.1.0
cached-property==1.5.2
certifi==2025.10.5
certipy==0.2.2
cffi==2.0.0
cfgv==3.4.0
cgmquantify_updated==0.5.3
charset-normalizer==3.4.3
click==8.3.0
cloudpickle==3.1.1
colorama==0.4.6
comm==0.2.3
conda==25.9.0
conda-libmamba-solver==25.4.0
conda-package-handling==2.4.0
conda_package_streaming==0.12.0
contourpy==1.3.3
cryptography==46.0.2
cycler==0.12.1
Cython==3.1.4
cytoolz==1.0.1
dask==2025.9.1
dataclasses-json==0.6.7
DateTime==5.5
debugpy==1.8.17
decorator==5.2.1
deepmerge==2.0
defusedxml==0.7.1
dill==0.4.0
distlib==0.3.9
distributed==2025.9.1
distro==1.9.0
et_xmlfile==2.0.0
exceptiongroup==1.3.0
executing==2.2.1
faiss-cpu==1.12.0
fastjsonschema==2.21.2
filelock==3.18.0
fonttools==4.60.1
fqdn==1.5.1
frozendict==2.4.6
frozenlist==1.8.0
fsspec==2025.9.0
gh-scoped-creds==4.1
gitdb==4.0.12
GitPython==3.1.45
gmpy2==2.2.1
greenlet==3.2.4
h11==0.16.0
h2==4.3.0
h5py==3.14.0
hpack==4.1.0
httpcore==1.0.9
httpx==0.28.1
httpx-sse==0.4.1
hyperframe==6.1.0
identify==2.6.9
idna==3.10
imagecodecs==2025.8.2
imageio==2.37.0
importlib_metadata==8.7.0
ipykernel==6.30.1
ipympl==0.9.7
ipython==9.6.0
ipython_genutils==0.2.0
ipython_pygments_lexers==1.1.1
ipywidgets==8.1.7
isoduration==20.11.0
jedi==0.19.2
Jinja2==3.1.6
jiter==0.11.0
joblib==1.5.2
json5==0.12.1
jsonpatch==1.33
jsonpath-ng==1.7.0
jsonpointer==3.0.0
jsonschema==4.25.1
jsonschema-specifications==2025.9.1
jupyter_ai==2.31.6
jupyter_ai_magics==2.31.6
jupyter_client==8.6.3
jupyter_core==5.8.1
jupyter-events==0.12.0
jupyter-lsp==2.3.0
jupyter_server==2.17.0
jupyter_server_mathjax==0.2.6
jupyter_server_terminals==0.5.3
jupyter-smart-on-fhir==0.1.0a3
jupyterhealth-client==0.1.0a3
jupyterhub==5.3.0
jupyterlab==4.4.9
jupyterlab_code_formatter==3.0.2
jupyterlab_git==0.51.2
jupyterlab_pygments==0.3.0
jupyterlab_server==2.27.3
jupyterlab_widgets==3.0.15
kiwisolver==1.4.9
langchain==0.3.27
langchain-community==0.3.30
langchain-core==0.3.78
langchain-openai==0.3.35
langchain-text-splitters==0.3.11
langsmith==0.4.32
lark==1.3.0
lazy_loader==0.4
libmambapy==2.3.2
llvmlite==0.45.1
locket==1.0.0
lz4==4.4.4
Mako==1.3.10
MarkupSafe==3.0.3
marshmallow==3.26.1
matplotlib==3.10.6
matplotlib-inline==0.1.7
menuinst==2.3.1
mistune==3.1.4
mplcursors==0.7
mpmath==1.3.0
msgpack==1.1.1
multidict==6.4.2
munkres==1.1.4
mypy-extensions==1.0.0
narwhals==2.6.0
nbclassic==1.3.3
nbclient==0.10.2
nbconvert==7.16.6
nbdime==4.0.2
nbformat==5.10.4
nbgitpuller==1.2.2
nest_asyncio==1.6.0
networkx==3.5
nodeenv==1.9.1
notebook==7.4.7
notebook_shim==0.2.4
numba==0.62.1
numexpr==2.13.1
numpy==2.3.3
oauthlib==3.3.1
openai==2.1.0
openpyxl==3.1.5
orjson==3.11.3
overrides==7.7.0
packaging==25.0
pamela==1.2.0
pandas==2.3.3
pandocfilters==1.5.0
parso==0.8.5
partd==1.4.2
pathspec==0.12.1
patsy==1.0.1
pexpect==4.9.0
pickleshare==0.7.5
pillow==11.3.0
pip==25.2
platformdirs==4.4.0
pluggy==1.6.0
ply==3.11
pre_commit==4.2.0
prometheus_client==0.23.1
prompt_toolkit==3.0.52
propcache==0.3.1
protobuf==6.31.1
psutil==7.1.0
ptyprocess==0.7.0
pure_eval==0.2.3
py-cpuinfo==9.0.0
pyarrow==21.0.0
pycosat==0.6.6
pycparser==2.22
pydantic==2.11.10
pydantic_core==2.33.2
pydantic-settings==2.11.0
Pygments==2.19.2
PyJWT==2.10.1
pyparsing==3.2.5
PySocks==1.7.1
python-dateutil==2.9.0.post0
python-dotenv==1.1.1
python-json-logger==2.0.7
pytz==2025.2
PyWavelets==1.9.0
PyYAML==6.0.3
pyzmq==27.1.0
referencing==0.36.2
regex==2025.9.18
requests==2.32.5
requests-toolbelt==1.0.0
rfc3339_validator==0.1.4
rfc3986-validator==0.1.1
rfc3987-syntax==1.1.0
rpds-py==0.27.1
ruamel.yaml==0.18.15
ruamel.yaml.clib==0.2.12
ruff==0.11.4
ruptures==1.1.10
scikit-image==0.25.2
scikit-learn==1.7.2
scipy==1.16.2
seaborn==0.13.2
Send2Trash==1.8.3
setuptools==80.9.0
six==1.17.0
smmap==5.0.2
sniffio==1.3.1
sortedcontainers==2.4.0
soupsieve==2.8
SQLAlchemy==2.0.43
stack_data==0.6.3
statsmodels==0.14.5
sympy==1.14.0
tables==3.10.2
tblib==3.1.0
tenacity==9.1.2
terminado==0.18.1
threadpoolctl==3.6.0
tifffile==2025.9.20
tiktoken==0.11.0
tinycss2==1.4.0
tomli==2.2.1
toolz==1.0.0
tornado==6.5.2
tqdm==4.67.1
traitlets==5.14.3
truststore==0.10.3
types-python-dateutil==2.9.0.20250822
typing_extensions==4.15.0
typing-inspect==0.9.0
typing-inspection==0.4.2
typing_utils==0.1.0
tzdata==2025.2
uri-template==1.3.0
urllib3==2.5.0
virtualenv==20.30.0
voila==0.5.8
wcwidth==0.2.14
webcolors==24.11.1
webencodings==0.5.1
websocket-client==1.8.0
websockets==15.0.1
widgetsnbextension==4.0.14
xlrd==2.0.2
xyzservices==2025.4.0
yarl==1.19.0
zict==3.0.0
zipp==3.23.0
zope.interface==7.2
zstandard==0.25.0

Suggested fix

I think a fix might be that we need to unshallow the clone:

git fetch --unshallow

if the repo's not up-to-date. I'm not sure there's another way to update a shallow clone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions