public inbox for git@vger.kernel.org
 help / color / mirror / Atom feed
From: Aaron Rainbolt <arraybolt3@gmail.com>
To: git@vger.kernel.org
Cc: adrelanos@kicksecure.com
Subject: [Bug] git difftool "--submodule=diff" argument does nothing
Date: Sun, 8 Dec 2024 03:02:22 -0600	[thread overview]
Message-ID: <20241208030222.60e7ac70@kf-ir16> (raw)

[-- Attachment #1: Type: text/plain, Size: 5067 bytes --]

I'm working with a project that has a lot of submodules. Like, a
shockingly large number of submodules. Each submodule is a miniature
project in its own right, with its own version history, version
numbers, etc. The "master project" is then used to build all of them
and integrate them into an installable Linux image. This works great,
except for when we want to look at all of the changes from one version
of the project to the next.

As one might expect, using something like `git difftool --tool=meld
--dir-diff prior-version-tag` doesn't work right. Rather than showing
the changes within the submodules, git simply shows the submodules
themselves, with contents such as 'Subproject commit
idontactuallywanttotypeasha256hashhere'. I don't really want to see
that, I want to see the contents of the submodules.

According to `man git-difftool`, the `git difftool` command supports
all of the same options as `git diff`:

    git difftool is a frontend to git diff and accepts the same options
    and arguments.

`git diff` supports a `--submodule=diff` argument, which will show me
exactly the info I want to see, but in a massive long diff file that
is painful to read and easy to miss stuff in. So, I tried running `git
difftool --submodule=diff --tool=meld --dir-diff prior-version-tag`
and... it did exactly the same thing as what it does without
`--submodule=diff`. It didn't crash, it didn't complain that I gave it
a bad argument, it just... pretended like the option wasn't there.

After experimenting and a bit of research, I don't think git has a way
of doing this yet. I found someone else on the mailing list mentioning
this same problem, and it was suggested that they use something along
the lines of `git submodule foreach git diff`. The problem with that is
it assumes that all of the submodules are going to have the exact same
version tags as the "master repo", which they don't, by design. Trying
this on my repo results in an error `fatal: ambiguous reference
'prior-version-tag': unknown revision or path not in the working tree`.
So that won't work.

Due to my unwillingness to be subjected to reading massive git diff
output, I went ahead and wrote a script that basically emulates the
behavior I want out of `git difftool`. This works, but it's non-ideal
for a number of reasons (it's hardcoded to use meld, it's written in
bash, it's not integrated into git, it does nothing about the fact that
the git manpage is incorrect when it comes to difftool's feature set,
etc.). If it was just me and the devs I work with using this, I
probably wouldn't mind it so much, but the problem is we expect people
who use our code to also audit our code, and it's decidedly non-ideal
that people would have to install a special script on their system just
to be able to run a user-friendly diff against our code for audit
purposes.

So... are there any particular roadblocks to making this work? Anything
I should be aware of aside from standard contribution guidelines before
sending a patch?

Thanks,
Aaron

P.S.: The script I wrote for emulating `git difftool --submodule=diff
--tool=meld --dir-diff`:

#!/bin/bash

## Copyright (C) 2024 - 2024 ENCRYPTED SUPPORT LP <adrelanos@whonix.org>
## See the file COPYING for copying conditions. (AGPLv3+ licensed.)

set -x
set -e
set -o pipefail
set -o errtrace
set -o nounset
set -o pipefail

cleanup() {
   rm "${git_diff_file}"
   rm -rf "${git_difftool_current_dir}"
   rm -rf "${git_difftool_selected_rev_dir}"
}

trap cleanup EXIT

pushd "$(git rev-parse --show-toplevel)"

git_ref="${1:-}"
[ -z "${git_ref}" ] && exit 1

git_diff_file="$(mktemp)"
git_difftool_current_dir="$(mktemp -d)"
git_difftool_selected_rev_dir="$(mktemp -d)"
git diff --submodule=diff "${git_ref}" > "${git_diff_file}" || exit 1;
git_diff_file_line_seek='n'
git_diff_target_file=''
while read -r git_diff_line; do
   if [[ "${git_diff_line}" =~ ^diff\ --git\ a/ ]]; then
      git_diff_file_line_seek='y'
      continue
   elif [ "${git_diff_file_line_seek}" = 'y' ]; then
      if [[ "${git_diff_line}" =~ ^'+++ b/' ]]; then
         # trim off the +++ b/ at the start
         git_diff_target_file="${git_diff_line:6}"
         git_diff_target_dirname="$(dirname "${git_diff_target_file}")"
         mkdir -p "${git_difftool_selected_rev_dir}/${git_diff_target_dirname}"
         mkdir -p "${git_difftool_current_dir}/${git_diff_target_dirname}"
         if [ -f "${git_diff_target_file}" ]; then
            cp "${git_diff_target_file}" "${git_difftool_selected_rev_dir}/${git_diff_target_file}"
            cp "${git_diff_target_file}" "${git_difftool_current_dir}/${git_diff_target_file}"
         fi
         git_diff_file_line_seek='n'
      fi
   fi
done < "${git_diff_file}"

pushd "${git_difftool_selected_rev_dir}"
patch -R -p1 < "${git_diff_file}"

popd # git_difftool_selected_rev_dir
popd # git rev-parse --show-toplevel

meld "${git_difftool_current_dir}" "${git_difftool_selected_rev_dir}"

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

                 reply	other threads:[~2024-12-08  9:02 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20241208030222.60e7ac70@kf-ir16 \
    --to=arraybolt3@gmail.com \
    --cc=adrelanos@kicksecure.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox