git添加比较和合并工具(meld)

时间:2023-03-09 15:32:18
git添加比较和合并工具(meld)

  git 下的(difftool)和(mergetool)是专门提供给使用者用自己的工具进行diff和merge的命令:

# git config --global  diff.tool  meld

# git config --global  merge.tool meld

然后直接使用命令进行两次提交的比较和合并:

# git difftool HEAD HEAD^

缺点:

虽然使用git difftool已经基本满足了我的需要,但还有个小问题:如果我要比较两次提交之间的差异时,difftool只能一个文件一个文件的比较,每次都要提示你是否打开这个文件,然后打开meld进行比较,当你关闭meld后,才会提示下一个差异文件。这样非常浪费效率,下面一个方法直接利用meld的目录比较能力(参考: https://github.com/thenigan/git-diffall):

1.新建diffall文本文件

2.在diffall文件中添加如下代码:

 #!/bin/sh
# Copyright - , Tim Henigan <tim.henigan@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # Perform a directory diff between commits in the repository using
# the external diff or merge tool specified in the user's config. USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
--cached Compare to the index rather than the working tree.
--copy-back Copy files back to the working tree when the diff
tool exits (in case they were modified by the
user). This option is only valid if the diff
compared with the working tree.
-x=<command>
--extcmd=<command> Specify a custom command for viewing diffs.
git-diffall ignores the configured defaults and
runs $command $LOCAL $REMOTE when this option is
specified. Additionally, $BASE is set in the
environment.
' SUBDIRECTORY_OK=
. "$(git --exec-path)/git-sh-setup" TOOL_MODE=diff
. "$(git --exec-path)/git-mergetool--lib" merge_tool="$(get_merge_tool)"
if test -z "$merge_tool"
then
echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
usage
fi start_dir=$(pwd) # All the file paths returned by the diff command are relative to the root
# of the working copy. So if the script is called from a subdirectory, it
# must switch to the root of working copy before trying to use those paths.
cdup=$(git rev-parse --show-cdup) &&
cd "$cdup" || {
echo >& "Cannot chdir to $cdup, the toplevel of the working tree"
exit
} # set up temp dir
tmp=$(perl -e 'use File::Temp qw(tempdir);
$t=tempdir("/tmp/git-diffall.XXXXX") or exit();
print $t') || exit 1
trap 'rm -rf "$tmp"' EXIT left=
right=
paths=
dashdash_seen=
compare_staged=
merge_base=
left_dir=
right_dir=
diff_tool=
copy_back= while test $# !=
do
case "$1" in
-h|--h|--he|--hel|--help)
usage
;;
--cached)
compare_staged=
;;
--copy-back)
copy_back=
;;
-x|--e|--ex|--ext|--extc|--extcm|--extcmd)
if test $# =
then
echo You must specify the tool for use with --extcmd
usage
else
diff_tool=$
shift
fi
;;
--)
dashdash_seen=
;;
-*)
echo Invalid option: "$1"
usage
;;
*)
# could be commit, commit range or path limiter
case "$1" in
*...*)
left=${%...*}
right=${#*...}
merge_base=
;;
*..*)
left=${%..*}
right=${#*..}
;;
*)
if test -n "$dashdash_seen"
then
paths="$paths$1 "
elif test -z "$left"
then
left=$
elif test -z "$right"
then
right=$
else
paths="$paths$1 "
fi
;;
esac
;;
esac
shift
done # Determine the set of files which changed
if test -n "$left" && test -n "$right"
then
left_dir="cmt-$(git rev-parse --short $left)"
right_dir="cmt-$(git rev-parse --short $right)" if test -n "$compare_staged"
then
usage
elif test -n "$merge_base"
then
git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist"
else
git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
fi
elif test -n "$left"
then
left_dir="cmt-$(git rev-parse --short $left)" if test -n "$compare_staged"
then
right_dir="staged"
git diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
else
right_dir="working_tree"
git diff --name-only "$left" -- $paths >"$tmp/filelist"
fi
else
left_dir="HEAD" if test -n "$compare_staged"
then
right_dir="staged"
git diff --name-only --cached -- $paths >"$tmp/filelist"
else
right_dir="working_tree"
git diff --name-only -- $paths >"$tmp/filelist"
fi
fi # Exit immediately if there are no diffs
if test ! -s "$tmp/filelist"
then
exit
fi if test -n "$copy_back" && test "$right_dir" != "working_tree"
then
echo "--copy-back is only valid when diff includes the working tree."
exit
fi # Create the named tmp directories that will hold the files to be compared
mkdir -p "$tmp/$left_dir" "$tmp/$right_dir" # Populate the tmp/right_dir directory with the files to be compared
while read name
do
if test -n "$right"
then
ls_list=$(git ls-tree $right "$name")
if test -n "$ls_list"
then
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
git show "$right":"$name" >"$tmp/$right_dir/$name" || true
fi
elif test -n "$compare_staged"
then
ls_list=$(git ls-files -- "$name")
if test -n "$ls_list"
then
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
git show :"$name" >"$tmp/$right_dir/$name"
fi
else
if test -e "$name"
then
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
cp "$name" "$tmp/$right_dir/$name"
fi
fi
done < "$tmp/filelist" # Populate the tmp/left_dir directory with the files to be compared
while read name
do
if test -n "$left"
then
ls_list=$(git ls-tree $left "$name")
if test -n "$ls_list"
then
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
git show "$left":"$name" >"$tmp/$left_dir/$name" || true
fi
else
if test -n "$compare_staged"
then
ls_list=$(git ls-tree HEAD "$name")
if test -n "$ls_list"
then
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
git show HEAD:"$name" >"$tmp/$left_dir/$name"
fi
else
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
git show :"$name" >"$tmp/$left_dir/$name"
fi
fi
done < "$tmp/filelist" LOCAL="$tmp/$left_dir"
REMOTE="$tmp/$right_dir" if test -n "$diff_tool"
then
export BASE
eval $diff_tool '"$LOCAL"' '"$REMOTE"'
else
run_merge_tool "$merge_tool" false
fi # Copy files back to the working dir, if requested
if test -n "$copy_back" && test "$right_dir" = "working_tree"
then
cd "$start_dir"
git_top_dir=$(git rev-parse --show-toplevel)
find "$tmp/$right_dir" -type f |
while read file
do
cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
done
fi

3.保存,运行如下命令配置

# git config --global alias.diffall /PATH/diffall