{"record":{"id":"681db85863336d58","repo":"nodejs/node","slug":"s-is-not-a-clean-git-repo-run-git-status","errorCode":null,"errorMessage":"%s is not a clean git repo (run git status)","messagePattern":"(.+?) is not a clean git repo \\(run git status\\)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"tools/inspector_protocol/roll.py","lineNumber":47,"sourceCode":"]\n\nREVISION_LINE_PREFIX = 'Revision: '\n\ndef RunCmd(cmd):\n  p = subprocess.Popen(cmd, stdout=subprocess.PIPE)\n  (stdoutdata, stderrdata) = p.communicate()\n  if p.returncode != 0:\n    raise Exception('%s: exit status %d', str(cmd), p.returncode)\n  return stdoutdata.decode('utf-8')\n\n\ndef CheckRepoIsClean(path):\n  os.chdir(path)  # As a side effect this also checks for existence of the dir.\n  # If path isn't a git repo, this will throw and exception.\n  # And if it is a git repo and 'git status' has anything interesting to say,\n  # then it's not clean (uncommitted files etc.)\n  if len(RunCmd(['git', 'status', '--porcelain'])) != 0:\n    raise Exception('%s is not a clean git repo (run git status)' % path)\n\n\ndef CheckRepoIsInspectorProtocolCheckout(path):\n  os.chdir(path)\n  revision = RunCmd(['git', 'config', '--get', 'remote.origin.url']).strip()\n  if (revision != 'https://chromium.googlesource.com/deps/inspector_protocol.git'):\n    raise Exception('%s is not a proper inspector_protocol checkout: %s' % (path, revision))\n\n\ndef FindFilesToSyncIn(path):\n  files = []\n  for f in FILES_TO_SYNC:\n    files += glob.glob(os.path.join(path, f))\n  files = [os.path.relpath(f, path) for f in files]\n  return files\n\n\ndef FilesAreEqual(path1, path2):","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/nodejs/node/blob/1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e/tools/inspector_protocol/roll.py#L29-L65","documentation":"tools/inspector_protocol/roll.py refuses to roll the inspector_protocol project into a node tree unless the *upstream* ip_src checkout has no uncommitted changes. CheckRepoIsClean runs `git status --porcelain` on that tree and treats any output (modified, staged, untracked, or conflicted files) as dirty.","triggerScenarios":"Invoking `python tools/inspector_protocol/roll.py` while the --ip_src_upstream tree (default ~/ip/src) has local modifications, untracked files, or an in-progress merge/rebase.","commonSituations":"Leftover edits in the ip checkout after manual testing; build artifacts that became tracked; a previous roll left the tree dirty; pointing --ip_src_upstream at a working clone you also hack on.","solutions":["Run `git -C <upstream> status` and commit, stash, or discard every change so `git status --porcelain` is empty.","Remove untracked files with `git -C <upstream> clean -fdx` (verify the list first).","Point --ip_src_upstream at a fresh, dedicated clone used only for rolling."],"exampleFix":"// before\npython tools/inspector_protocol/roll.py  # upstream tree has edits\n// after\ngit -C ~/ip/src stash && python tools/inspector_protocol/roll.py","handlingStrategy":"validation","validationCode":"import subprocess\ndef upstream_clean(path):\n    out = subprocess.run(['git','-C',path,'status','--porcelain'],\n                         capture_output=True, text=True)\n    return out.returncode == 0 and out.stdout.strip() == ''\nassert upstream_clean('~/ip/src')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep a dedicated pristine clone for rolling; never edit it directly.","Always run `git status --porcelain` on the upstream tree before invoking roll.py."],"tags":["git","inspector-protocol","roll","workflow"],"backgroundTag":null,"analyzedSha":"1b2de5e052fc0fb95fd7fb6846dcec4ade598e9e","analyzedAt":"2026-08-13T00:53:24.642Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}