{"thread":{"id":"62612","subject":"[Bug] git difftool \"--submodule=diff\" argument does nothing","startedAt":"2024-12-08T09:02:32Z","lastAt":"2024-12-08T09:02:32Z","messageCount":1,"participants":["Aaron Rainbolt"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"508833","messageId":"20241208030222.60e7ac70@kf-ir16","threadId":"62612","inReplyTo":null,"subject":"[Bug] git difftool \"--submodule=diff\" argument does nothing","fromName":"Aaron Rainbolt","fromEmail":"arraybolt3@gmail.com","sentAt":"2024-12-08T09:02:22Z","receivedAt":"2024-12-08T09:02:32Z","isPatch":false,"sender":{"key":"arraybolt3@gmail.com","avatar":null},"body":"I'm working with a project that has a lot of submodules. Like, a\nshockingly large number of submodules. Each submodule is a miniature\nproject in its own right, with its own version history, version\nnumbers, etc. The \"master project\" is then used to build all of them\nand integrate them into an installable Linux image. This works great,\nexcept for when we want to look at all of the changes from one version\nof the project to the next.\n\nAs one might expect, using something like `git difftool --tool=meld\n--dir-diff prior-version-tag` doesn't work right. Rather than showing\nthe changes within the submodules, git simply shows the submodules\nthemselves, with contents such as 'Subproject commit\nidontactuallywanttotypeasha256hashhere'. I don't really want to see\nthat, I want to see the contents of the submodules.\n\nAccording to `man git-difftool`, the `git difftool` command supports\nall of the same options as `git diff`:\n\n    git difftool is a frontend to git diff and accepts the same options\n    and arguments.\n\n`git diff` supports a `--submodule=diff` argument, which will show me\nexactly the info I want to see, but in a massive long diff file that\nis painful to read and easy to miss stuff in. So, I tried running `git\ndifftool --submodule=diff --tool=meld --dir-diff prior-version-tag`\nand... it did exactly the same thing as what it does without\n`--submodule=diff`. It didn't crash, it didn't complain that I gave it\na bad argument, it just... pretended like the option wasn't there.\n\nAfter experimenting and a bit of research, I don't think git has a way\nof doing this yet. I found someone else on the mailing list mentioning\nthis same problem, and it was suggested that they use something along\nthe lines of `git submodule foreach git diff`. The problem with that is\nit assumes that all of the submodules are going to have the exact same\nversion tags as the \"master repo\", which they don't, by design. Trying\nthis on my repo results in an error `fatal: ambiguous reference\n'prior-version-tag': unknown revision or path not in the working tree`.\nSo that won't work.\n\nDue to my unwillingness to be subjected to reading massive git diff\noutput, I went ahead and wrote a script that basically emulates the\nbehavior I want out of `git difftool`. This works, but it's non-ideal\nfor a number of reasons (it's hardcoded to use meld, it's written in\nbash, it's not integrated into git, it does nothing about the fact that\nthe git manpage is incorrect when it comes to difftool's feature set,\netc.). If it was just me and the devs I work with using this, I\nprobably wouldn't mind it so much, but the problem is we expect people\nwho use our code to also audit our code, and it's decidedly non-ideal\nthat people would have to install a special script on their system just\nto be able to run a user-friendly diff against our code for audit\npurposes.\n\nSo... are there any particular roadblocks to making this work? Anything\nI should be aware of aside from standard contribution guidelines before\nsending a patch?\n\nThanks,\nAaron\n\nP.S.: The script I wrote for emulating `git difftool --submodule=diff\n--tool=meld --dir-diff`:\n\n#!/bin/bash\n\n## Copyright (C) 2024 - 2024 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>\n## See the file COPYING for copying conditions. (AGPLv3+ licensed.)\n\nset -x\nset -e\nset -o pipefail\nset -o errtrace\nset -o nounset\nset -o pipefail\n\ncleanup() {\n   rm \"${git_diff_file}\"\n   rm -rf \"${git_difftool_current_dir}\"\n   rm -rf \"${git_difftool_selected_rev_dir}\"\n}\n\ntrap cleanup EXIT\n\npushd \"$(git rev-parse --show-toplevel)\"\n\ngit_ref=\"${1:-}\"\n[ -z \"${git_ref}\" ] && exit 1\n\ngit_diff_file=\"$(mktemp)\"\ngit_difftool_current_dir=\"$(mktemp -d)\"\ngit_difftool_selected_rev_dir=\"$(mktemp -d)\"\ngit diff --submodule=diff \"${git_ref}\" > \"${git_diff_file}\" || exit 1;\ngit_diff_file_line_seek='n'\ngit_diff_target_file=''\nwhile read -r git_diff_line; do\n   if [[ \"${git_diff_line}\" =~ ^diff\\ --git\\ a/ ]]; then\n      git_diff_file_line_seek='y'\n      continue\n   elif [ \"${git_diff_file_line_seek}\" = 'y' ]; then\n      if [[ \"${git_diff_line}\" =~ ^'+++ b/' ]]; then\n         # trim off the +++ b/ at the start\n         git_diff_target_file=\"${git_diff_line:6}\"\n         git_diff_target_dirname=\"$(dirname \"${git_diff_target_file}\")\"\n         mkdir -p \"${git_difftool_selected_rev_dir}/${git_diff_target_dirname}\"\n         mkdir -p \"${git_difftool_current_dir}/${git_diff_target_dirname}\"\n         if [ -f \"${git_diff_target_file}\" ]; then\n            cp \"${git_diff_target_file}\" \"${git_difftool_selected_rev_dir}/${git_diff_target_file}\"\n            cp \"${git_diff_target_file}\" \"${git_difftool_current_dir}/${git_diff_target_file}\"\n         fi\n         git_diff_file_line_seek='n'\n      fi\n   fi\ndone < \"${git_diff_file}\"\n\npushd \"${git_difftool_selected_rev_dir}\"\npatch -R -p1 < \"${git_diff_file}\"\n\npopd # git_difftool_selected_rev_dir\npopd # git rev-parse --show-toplevel\n\nmeld \"${git_difftool_current_dir}\" \"${git_difftool_selected_rev_dir}\"\n"}]}