With this repository, git subtree merge --squash --prefix=resources/webidl2 8a7ff70664
where that commit comes from this repository, it fails with a merge conflict.
Adding -d
to enable debug output, we discover:
Squash found: 5353ef707674e9d894f207581d7dffab2609b832 bd216bcd5596d60734450adc938155deab1e1a80
However, this isn't the latest squash, and running the log call manually and changing the --grep
option it becomes apparent that --grep="^git-subtree-dir: resources/webidl2/*\$"
isn't matching 960a3d21bab0293630da8919847f87f4af3a3198 for no apparent reason (it does match --grep="^git-subtree-dir: resources/webidl2/*"
, but the lines containing git-subtree-dir
in both commits that match that are byte-for-byte identical, hence it doesn't make sense why one is matched by the previous --grep
option but not the other).
Given that git-subtree
is failing to find this previous squash, how can I do a new squash without it thinking everything in that is a local change and hence ending up with conflicts?
Looking at the object of the commit that isn't found:
$ git cat-file -p 960a3d21bab0293630da8919847f87f4af3a3198 | hexdump -C
[…]
00000cc0 6c 6c 6f 77 20 60 2d 60 0d 0a 0d 0a 67 69 74 2d |llow `-`....git-|
00000cd0 73 75 62 74 72 65 65 2d 64 69 72 3a 20 72 65 73 |subtree-dir: res|
00000ce0 6f 75 72 63 65 73 2f 77 65 62 69 64 6c 32 0d 0a |ources/webidl2..|
00000cf0 67 69 74 2d 73 75 62 74 72 65 65 2d 73 70 6c 69 |git-subtree-spli|
00000d00 74 3a 20 38 38 63 35 63 35 62 36 62 62 36 37 35 |t: 88c5c5b6bb675|
00000d10 64 30 64 39 35 61 65 33 65 63 34 64 62 33 32 35 |d0d95ae3ec4db325|
00000d20 38 37 36 38 64 30 63 38 66 63 30 |8768d0c8fc0|
00000d2b
The vital point here is that the git-subtree-dir
line ends with 0d 0a
(CR LF). git log --grep
's $
operation matches the end-of-line, which as you'd expect on a non-Windows system is LF, and therefore ^git-subtree-dir: resources/webidl2/*\$
doesn't match because there's a CR before the end-of-line.
The commit appears to be from a GitHub PR and merged through "squash and merge" with the commit message therefore edited through GitHub. Looking at the commit message compared with the original commit from git-subtree
, you'll find the original commit doesn't include any CR byte in that line. (We'll also come back to the fact it's been "squash and merged" later, as that has caused other problems!)
Looking at how to resolve this, the best approach I've found is to download a copy of git-subtree.sh
and then edit the find_latest_squash
function to just echo out the expected commit references; i.e., replace the function with:
echo "960a3d21bab0293630da8919847f87f4af3a3198" "88c5c5b6bb675d0d95ae3ec4db3258768d0c8fc0"
With this done, running git-subtree
will produce two commits: one that updates the copy of webidl2.js (whose parent commit is 960a3d21bab), but due to the previous squash this will actually result in a commit that deletes everything and adds a new copy of webidl2.js (git-subtree expects to have a graph of commits which are literally just the subtree, at the root, occasionally with new commits which squash; the "squash and merge" caused the entirety of the repository to appear in that commit with the subtree in its prefixed path), and then a merge commit which updates the copy of the subtree in the repository.
It's important, going forward, to not modify the squash commit that git-subtree creates because git-subtree is very sensitive to any changes to it.