[Bug] git difftool "--submodule=diff" argument does nothing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
## 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: pgpd20Q1oqZVI.pgp
Description: OpenPGP digital signature


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux