It kinda sounds like you’re tracking changed files (a la git diff --name-only), then on the side maintaining and syncing a Merkle tree of all the tracked project files, and in the end just uploading the list of changed files. Can’t you just skip the hash tree? Why isn’t the client just sending the updated files when the server asks?
merkle trees let us quickly check what changed by comparing root hashes - faster than scanning all files. helps us know exactly which dirs changed and ensures client/server stay in sync