)]}'
{
  "commit": "c0bec06cfedb930ecb3cd8c8cdb0f3e14e5e9308",
  "tree": "3feb1a618ab817e10585e4dffc84b5cb907a2241",
  "parents": [
    "c44beea485f0f2feaf460e2ac87fdd5608d63cf0"
  ],
  "author": {
    "name": "Jacob Keller",
    "email": "jacob.e.keller@intel.com",
    "time": "Wed Sep 24 13:57:15 2025 -0700"
  },
  "committer": {
    "name": "Junio C Hamano",
    "email": "gitster@pobox.com",
    "time": "Thu Sep 25 11:35:20 2025 -0700"
  },
  "message": "diff --no-index: fix logic for paths ending in \u0027/\u0027\n\nIf one of the two provided paths for git diff --no-index ends in a \u0027/\u0027,\na failure similar to the following occurs:\n\n  $ git diff --no-index -- /tmp/ /tmp/ \u0027:!\u0027\n  fatal: `pos + len\u0027 is too far after the end of the buffer\n\nThis occurs because of an incorrect calculation of the skip lengths in\ndiff_no_index(). The code wants to calculate the length of the string,\nbut add one in case the string doesn\u0027t end with a slash.\n\nThe method it uses is incorrect, as it always checks the trailing NUL\ncharacter of the string. This will never be a \u0027/\u0027, so we always add one.\nIn the event that we *do* have a trailing slash, this will create an\noff-by-one length error later when using the skip value.\n\nThe most straightforward fix would be to correct the skip1 and skip2\nlengths by using ends_with().\n\nHowever, Johannes made a good point that the existing logic is wasting a\nlot of computation. We generate the match string by copying the path in\nand then skipping almost all of it immediately with a potentially\nexpensive memmove() from the strbuf_remove() call. We also re-initialize\nthe match stringbuf each time we call read_directory_contents.\n\nThe read_directory_contents really wants a path that is rooted at the\nstart of the directory scan. We\u0027re currently building this by taking the\nfull path and stripping out the start portion. Instead, replace this\nlogic by building up the portion of the match as we go.\n\nStart by initializing two strbuf in diff_no_index containing the empty\nstring. Pass these into queue_diff, which in turn passes the appropriate\nleft or right side into read_directory_contents.\n\nAs before, we build up the matches by appending elements to the match\npath and then clearing them using strbuf_setlen.\n\nIn the recursive portion of the queue_diff algorithm, we build up new\nmatch paths the same way that we build up new buffer paths, by appending\nthe elements and then clearing them with strbuf_setlen after each\niteration. This is cheaper as it avoids repeated allocations, and is a\nbit simpler to track what is going on.\n\nAdd a couple of test cases that pass in paths already ending in \u0027/\u0027, to\nensure the tests cover this regression.\n\nReported-by: Johannes Schindelin \u003cJohannes.Schindelin@gmx.de\u003e\nCloses: https://lore.kernel.org/git/c75ec5f9-407a-6555-d4fb-bb629d54ec61@gmx.de/\nSigned-off-by: Jacob Keller \u003cjacob.e.keller@intel.com\u003e\n[jc: small leakfixes at the end of diff_no_index()]\nSigned-off-by: Junio C Hamano \u003cgitster@pobox.com\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "88ae4cee56ba41819cb7d6c332feb59b6e0fe5a8",
      "old_mode": 33188,
      "old_path": "diff-no-index.c",
      "new_id": "f320424f05fe0f3c0a33f1fca937282f4621ee9c",
      "new_mode": 33188,
      "new_path": "diff-no-index.c"
    },
    {
      "type": "modify",
      "old_id": "01db9243abfe4f38af2a988f9d753c14425fad3a",
      "old_mode": 33261,
      "old_path": "t/t4053-diff-no-index.sh",
      "new_id": "e0ea437685b0abd623e8050467a770c304ae962f",
      "new_mode": 33261,
      "new_path": "t/t4053-diff-no-index.sh"
    }
  ]
}
