From: Dan Holmsand <holmsand@gmail.com>
To: git@vger.kernel.org
Cc: Petr Baudis <pasky@ucw.cz>
Subject: [PATCH 6/6] Make cg-log use optparse, and add features
Date: Thu, 09 Jun 2005 13:29:14 +0200 [thread overview]
Message-ID: <42A8280A.3070607@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 2839 bytes --]
This is more or less a rewrite of cg-log, that adds a bunch
of new features and gives a substantial speedup.
cg-log now lets git-rev-list and git-diff-tree do as much
of the heavy lifting as possible. When possible, cg-log
pretty much reduces to a sed script, that does some fixup
and adds colorization. Otherwise, cg-log uses
--pretty=[raw|medium|short] output, that's augmented as
necessary.
New features:
- New, human friendlier output format. cg-log now uses
the same format as git-rev-list --pretty. It also
doesn't show tree, committer and parents by default.
These are all shown with "-v or --verbose", however.
- Slightly more readable summary format. sha1s are hidden
unless -v is given. Date format is condenced to HH:MM
for the last day, and Month Day otherwise. (+year is
shown for really old stuff).
summary format can also be combined with other options,
like "-f" and "-d" (diffstat).
- "-u" (or --search=) now searches the entire commit
message. This is more flexible, as you can still do e.g.
"cg-log -u 'author Petr Baudis'". Search is now also
a lot faster, done with a single grep invocation.
- Output can be limited by date or count.
- New format for "-f". This is pretty much the same
output as cg-status gives, and allows for the
rename/copy detection things to work. New and
deleted files are optionally color coded.
The old format is still available as -F.
- Merge commits are hidden by default when displaying
differences between commits, or when displaying disjoint
sets of commits. "-a" makes them show again. So
"cg-log -caF" gives you pretty much the same output
as the old "cg-log -c -f" would.
- Shows diffs between commits with the "-p" options.
The diffs use the same colorization rules as cg-diff,
and can be skipped through with "n" in less if "-c"
is given.
- "--stdin" reads sha1s from stdin instead of from
git-rev-list, for some extra flexibility.
New features in common with cg-diff:
- diffstat support (or rather git-apply --stat). The
"-d" option outputs (optionally colorized) diff stats
before the diff.
- support for more git-diff-[tree/cache] options:
-B, -R, -M, -C are now all passed on.
- The COGITO_AUTO_COLOR environment variable makes output
automatically colorized, if set and if we're on a color
capable terminal.
We also use the new optparse function from cg-Xlib, to allow
for e.g. "cg-log -sfa" and stuff.
Reuse colorization logic from cg-Xlib. All the colors are
added in a single sed invocation.
And use LESS to make "less" search for chunks and diff --git
markers. This allows you to "n" your way through a series
of diffs, and gives a nice visual separation of patches.
Signed-off-by: Dan Holmsand <holmsand@gmail.com>
---
[-- Attachment #2: 6-cg-log.patch.txt --]
[-- Type: text/plain, Size: 16296 bytes --]
cg-log | 545 +++++++++++++++++++++++++++++++++++++++-------------------------
1 files changed, 331 insertions(+), 214 deletions(-)
diff --git a/cg-log b/cg-log
--- a/cg-log
+++ b/cg-log
@@ -3,6 +3,7 @@
# Make a log of changes in a GIT branch.
# Copyright (c) Petr Baudis, 2005.
# Copyright (c) David Woodhouse, 2005.
+# Copyright (c) Dan Holmsand, 2005.
#
# Display log information for files or a range of commits. The output
# will automatically be displayed in a pager unless it is piped to
@@ -13,7 +14,7 @@
# Arguments not interpreted as options will be interpreted as filenames;
# cg-log then displays only changes in those files.
#
-# -c::
+# -c, --color::
# Colorize to the output. The used colors are listed below together
# with information about which log output (summary, full or both)
# they apply to:
@@ -26,8 +27,15 @@
# - `date`: 'green' (summary)
# - `trim_mark`: 'magenta' (summary)
#
+# -d, --diffstat::
+# Show `diffstat' for every commit.
+#
# -f::
-# List affected files. (No effect when passed along `-s`.)
+# Show list of files modified in each commit.
+#
+# -F::
+# Show ChangeLog-style list of modified files, instead of the
+# default listing.
#
# -r FROM_ID[:TO_ID]::
# Limit the log information to a set of revisions using either
@@ -37,29 +45,61 @@
# to the initial commit is shown. If no revisions is specified,
# the log information starting from 'HEAD' will be shown.
#
-# -m::
-# End the log listing at the merge base of the -r arguments
-# (defaulting to master and origin).
-#
-# -s::
+# -s, --summary::
# Show a one line summary for each log entry. The summary contains
# information about the commit date, the author, the first line
# of the commit log and the commit ID. Long author names and commit
# IDs are trimmed and marked with an ending tilde (~).
#
-# -uUSERNAME::
-# List only commits where author or committer contains 'USERNAME'.
-# The search for 'USERNAME' is case-insensitive.
+# -p, --patches::
+# Show diffs for files modified by each commit.
+#
+# -v, --verbose::
+# Show committer, tree and parents for each commit.
+#
+# -a, --all::
+# Show merge commits as well.
+#
+# -m::
+# End the log listing at the merge base of the -r arguments
+# (defaulting to master and origin).
+#
+# -u, --search=TEXT::
+# List only commits where author, committer or commit message
+# contains 'TEXT'. The search for 'TEXT' is case-insensitive.
+#
+# -S, --match=TEXT::
+# Look for commits that introduces TEXT in a file.
+#
+# -M::
+# Detect renames.
+#
+# -C::
+# Detect copies (as well as renames).
+#
+# -B::
+# Detect rewrites.
+#
+# -y, --max-age=DATE::
+# Limit output to commits younger than DATE.
+#
+# -o, --min-age=DATE::
+# Limit output to commits older than DATE.
+#
+# --max-count=N::
+# Show at most N commits.
+#
+# --stdin::
+# Show commits for sha1s read from stdin.
#
# ENVIRONMENT VARIABLES
# ---------------------
# PAGER::
# The pager to display log information in, defaults to `less`.
#
-# PAGER_FLAGS::
-# Flags to pass to the pager. By default `R` and `S` is added to the
-# `LESS` environment variable to allow displaying of colorized output
-# and to avoid long lines from wrapping when using `-s`.
+# COGITO_AUTO_COLOR::
+# If set, colorized output is used automatically on color-capable
+# terminals.
#
# EXAMPLE USAGE
# -------------
@@ -75,228 +115,305 @@ USAGE="cg-log [-c] [-f] [-m] [-s] [-uUSE
# at least somewhere it does. Bash is broken.
trap exit SIGPIPE
-[ "$COLUMNS" ] || COLUMNS="$(tput cols)"
+# speed bash up on utf-8 locales
+LANG=C
-colheader=
-colauthor=
-colcommitter=
-colfiles=
-colsignoff=
-colcommit=
-coldate=
-coltrim=
-coldefault=
-
-list_files=
-log_start=
-log_end=
-summary=
-user=
-mergebase=
-files=()
-
-while [ "$1" ]; do
- case "$1" in
- -c)
- # See terminfo(5), "Color Handling"
- colheader="$(tput setaf 2)" # Green
- colauthor="$(tput setaf 6)" # Cyan
- colcommitter="$(tput setaf 5)" # Magenta
- colfiles="$(tput setaf 4)" # Blue
- colsignoff="$(tput setaf 3)" # Yellow
-
- colcommit="$(tput setaf 4)"
- coldate="$(tput setaf 2)"
- coltrim="$(tput setaf 5)"
-
- coldefault="$(tput op)" # Restore default
- ;;
- -f)
- list_files=1
- ;;
- -u*)
- user="${1#-u}"
- ;;
- -r)
- shift
- if echo "$1" | grep -q ':'; then
- log_end=$(echo "$1" | cut -d : -f 2)
- [ "$log_end" ] || log_end="HEAD"
- log_start=$(echo "$1" | cut -d : -f 1)
- elif [ -z "$log_start" ]; then
- log_start="$1"
- else
- log_end="$1"
- fi
- ;;
- -m)
- mergebase=1
- ;;
- -s)
- summary=1
- ;;
- *)
- files=("$@")
- break
- ;;
- esac
- shift
-done
+unset id1 id2 user verbose filelist patches sedprog incoming pretty maxn
+unset diffstat stdin opt_color renames dtmode quiet summary longsummary files
+unset needparse
+filemode=-s
+dtargs=() rlargs=()
+
+revlist() {
+ if [ "$stdin" ]; then
+ # read sha1s from stdin. remove leading stuff from
+ # git-rev-tree output.
+ sed 's/^[0-9]* \([a-f0-9]\{40\}\)/\1/'
+ elif [ "$user" ]; then
+ git-rev-list --header "${rlargs[@]}" |
+ LANG=C grep -iz "$user" | tr '\n\0' '\t\n' | cut -f1
+ else
+ git-rev-list "${rlargs[@]}" "$@"
+ fi
+}
-list_commit_files()
-{
- tree1="$1"
- tree2="$2"
- line=
- sep=" * $colfiles"
- # List all files for for the initial commit
- if [ -z $tree2 ]; then
- list_cmd="git-ls-tree $tree1"
+dolog() {
+ if [ "$dtmode" = diff-tree ]; then
+ revlist |
+ git-diff-tree --stdin -v -r $filemode "${dtargs[@]}" \
+ -- "${ARGS[@]}"
else
- list_cmd="git-diff-tree -r $tree1 $tree2"
+ revlist --pretty${pretty+=}$pretty
fi
+}
+
+showstat() {
+ git-diff-tree -r -p "${dtargs[@]}" $1 $2 -- "${ARGS[@]}" |
+ git-apply --stat 2>/dev/null
echo
- $list_cmd | cut -f 2- | while read file; do
- echo -n "$sep"
- sep=", "
- line="$line$sep$file"
- if [ ${#line} -le 74 ]; then
- echo -n "$file"
+}
+
+showfiles() {
+ local p=6 sep=" * $colfiles" IFS=$'\n' file end=":$coldefault"
+ [ "$summary" ] && { end="$coldefault"$'\n'; }
+ for i in $(git-diff-tree -m -r $1 $2); do
+ [[ "$i" == :* ]] || continue
+ i=${i##*$'\t'}
+ if (( (p += 2 + ${#i}) < 75 )); then
+ echo -n "$sep$i"
else
- line=" $file"
- echo "$coldefault"
- echo -n " $colfiles$file"
+ (( p = 6 + ${#i} ))
+ echo ",$coldefault"
+ echo -n " $colfiles$i"
fi
+ sep=", "
done
- echo "$coldefault:"
+ echo "$end"
}
-process_commit_line()
-{
- if [ "$key" = "%" ] || [ "$key" = "%$colsignoff" ]; then
- # The fast common case
- [ "$summary" ] || [ "$skip_commit" ] || echo " $rest"
- return
+toepoch() {
+ expr "$1" : "[0-9]*$" >/dev/null && echo "$1" ||
+ date -ud "$1" +%s || die "invalid date $1"
+}
+
+showsummary() {
+ local commit=$1 author=$2 date=$3 text=$4 da
+ author=${author#Author: }
+ author=${author% <*}
+ [ ${#author} -gt 14 ] && author=${author:0:13}$coltrim~
+ if [ -z "$longsummary" ]; then
+ commit=
+ elif [ "${COLUMNS:-0}" -le 90 ]; then
+ commit="$colcommit${commit:0:12}$coltrim~ "
+ else
+ commit="$colcommit$commit "
fi
- case "$key" in
- "commit")
- [ "$summary" ] || [ "$skip_commit" ] || { [ "$commit" ] && echo; }
- commit="$rest"
- parents=()
- skip_commit=
- ;;
- "tree")
- tree="$rest"
- ;;
- "parent")
- parents[${#parents[@]}]="$rest"
- ;;
- "committer")
- committer="$rest"
- ;;
- "author")
- author="$rest"
- ;;
- "")
- if [ ! "$commit" ]; then
- # Next commit is coming
- [ "$summary" ] || echo
- return
- fi
+ # find suitable short date format, assumes date in "std linus format"
+ da=(${date#Date:})
+ local dyear=${da[4]}
+ if [ "$year" -ne "$dyear" ]; then
+ # year month day
+ date="${da[1]} ${da[2]} $dyear"
+ elif [ "$month" != "${da[1]}" -o "$day" -ne "${da[2]}" ]; then
+ # month day
+ date="${da[1]} ${da[2]}"
+ else
+ # time
+ date=${da[3]%:*}
+ fi
+ line=${line# }
+ printf "%s$colauthor%-14s $coldate%-6s $coldefault%s\n" \
+ "$commit" "$author" "$date" "$line"
+}
- if [ "$user" ]; then
- if ! echo -e "author $author\ncommitter $committer" \
- | grep -qi "$user"; then
- skip_commit=1
- return
- fi
- fi
- if [ "$files" ]; then
- parent="${parents[0]}"
- diff_ops=
- [ "$parent" ] || diff_ops=--root
- if ! [ "$(git-diff-tree -r $diff_ops $commit $parent "${files[@]}")" ]; then
- skip_commit=1
- return
- fi
- fi
- if [ "$summary" ]; then
- # Print summary
- commit="${commit%:*}"
- author="${author% <*}"
- date=(${committer#*> })
- date="$(showdate $date '+%F %H:%M')"
- read title
- if [ "${#author}" -gt 15 ]; then
- author="${author:0:14}$coltrim~"
- fi
- if [ "${COLUMNS:-0}" -le 90 ]; then
- commit="${commit:0:12}$coltrim~"
+while optparse; do
+ if optparse -c || optparse --color; then
+ opt_color=1
+ elif optparse -f; then
+ [ "$patches" ] && optconflict
+ files=1
+ filemode=
+ elif optparse -F; then
+ filelist=1
+ dtmode=diff-tree
+ elif optparse -p || optparse --patches; then
+ [ "$files" ] && optconflict
+ patches=1
+ filemode=-p
+ elif optparse -d || optparse --diffstat; then
+ diffstat=1
+ dtmode=diff-tree
+ elif optparse -u= || optparse --search= 2; then
+ user=$OPTARG
+ dtmode=diff-tree
+ elif optparse -q || optparse --short; then
+ [ "$verbose$summary" ] && optconflict
+ quiet=1
+ elif optparse -v || optparse --verbose; then
+ [ "$quiet" ] && optconflict
+ verbose=1
+ elif optparse -s || optparse --summary 2; then
+ [ "$quiet" ] && optconflict
+ summary=1
+ elif optparse --stdin 2; then
+ stdin=1
+ dtmode=diff-tree
+ elif optparse -y= || optparse --max-age= 5; then
+ rlargs[${#rlargs[@]}]=--max-age=$(toepoch "$OPTARG") || exit 1
+ elif optparse -o= || optparse --min-age= 2; then
+ rlargs[${#rlargs[@]}]=--min-age=$(toepoch "$OPTARG") || exit 1
+ elif optparse --max-count= 5; then
+ maxn=$OPTARG
+ elif optparse -a || optparse --all; then
+ dtargs[${#dtargs[@]}]="-m"
+ dtargs[${#dtargs[@]}]="--root"
+ elif optparse -m || optparse --mergebase 2; then
+ incoming=1
+ elif optparse -S= || optparse --match= 3; then
+ dtargs[${#dtargs[@]}]="-S$OPTARG"
+ elif optparse -M; then
+ [ "$renames" ] && optconflict
+ [ "$patches" ] || filemode=
+ dtargs[${#dtargs[@]}]="-M"
+ renames=1
+ elif optparse -C; then
+ [ "$renames" ] && optconflict
+ [ "$patches" ] || filemode=
+ dtargs[${#dtargs[@]}]="-C"
+ renames=1
+ elif optparse -B; then
+ [ "$patches" ] || filemode=
+ dtargs[${#dtargs[@]}]="-B"
+ elif optparse -r= || optparse --revision=; then
+ if [ -z "${id1+set}" ]; then
+ id1=$OPTARG
+ if [[ "$id1" == *:* ]]; then
+ id2=${id1#*:}
+ id1=${id1%:*}
fi
-
- printf "$colcommit%s $colauthor%-15s $coldate%s $coldefault%s\n" \
- "${commit%:*}" "$author" "$date" "${title:2}"
- commit=
- return
+ else
+ [ -z "${id2+set}" ] || die "too many revisions"
+ id2=$OPTARG
fi
+ else
+ optfail
+ fi
+done
- echo ${colheader}commit ${commit%:*} $coldefault
- echo ${colheader}tree $tree $coldefault
+[ -n "$COGITO_AUTO_COLOR" -a -t 1 ] && [ "$(tput setaf 1 2>/dev/null)" ] &&
+ opt_color=1
- for parent in "${parents[@]}"; do
- echo ${colheader}parent $parent $coldefault
- done
+LESS="-S $LESS"
+[ "$COLUMNS" ] || COLUMNS="$(tput cols)"
- date=(${author#*> })
- pdate="$(showdate $date)"
- [ "$pdate" ] && author="${author%> *}> $pdate"
- echo ${colauthor}author $author $coldefault
-
- date=(${committer#*> })
- pdate="$(showdate $date)"
- [ "$pdate" ] && committer="${committer%> *}> $pdate"
- echo ${colcommitter}committer $committer $coldefault
+if [ "$incoming" ]; then
+ id1="$(commit-id "${id1:-origin}")" || exit 1
+ id2="$(commit-id "${id2:-HEAD}")" || exit 1
+ id2="$(git-merge-base "$id1" "$id2")" || exit 1
+fi
- if [ -n "$list_files" ]; then
- list_commit_files "$tree" "${parents[0]}"
- fi
- echo
- commit=
- ;;
- esac
-}
+id1=$(commit-id "$id1") || exit 1
+[ -z "${id2+set}" ] || id2=$(commit-id "$id2") || exit 1
+rlargs=( "${rlargs[@]}" $id1 ${id2+^}$id2 )
-print_commit_log()
-{
- commit=
- author=
- committer=
- tree=
-
- sed -e '
- s/^ \(.*\)/% \1/
- /^% *[Ss]igned-[Oo]ff-[Bb]y:.*/ s/^% \(.*\)/% '$colsignoff'\1'$coldefault'/
- /^% *[Aa]cked-[Bb]y:.*/ s/^% \(.*\)/% '$colsignoff'\1'$coldefault'/
- ' | while read key rest; do
- trap exit SIGPIPE
- process_commit_line
- done
-}
+if [ -n "${dtargs[*]}${ARGS[*]}" -o "$filemode" != -s -o "$dtmode" ]; then
+ dtmode=diff-tree
+else
+ dtmode=commit
+ [ "$verbose" -a -z "$summary" ] && pretty=raw
+ [ "$quiet" ] && { pretty=short; quiet=; }
+fi
-if [ "$mergebase" ]; then
- [ "$log_start" ] || log_start="master"
- [ "$log_end" ] || log_end="origin"
- log_start=$(git-merge-base $(commit-id "$log_start") $(commit-id "$log_end"))
+if [ "$summary" ]; then
+ year=$(date +%Y)
+ month=$(LANG=C date +%b)
+ day=$(date +%d)
+ [ "$verbose" ] && { longsummary=1; verbose=; }
fi
-id1="$(commit-id "$log_start")" || exit 1
-if [ "$log_end" ]; then
- id2="$(commit-id "$log_end")" || exit 1
- revls="git-rev-list --pretty=raw $id2 ^$id1"
+if [ "$filelist$diffstat$summary" -o "$pretty" = raw -o $dtmode = diff-tree ]
+then
+ needparse=1
else
- revls="git-rev-list --pretty=raw $id1"
+ [ "$maxn" ] && rlargs=(--max-count="$maxn" "${rlargs[@]}")
+fi
+
+if [ "$opt_color" ]; then
+ setup_colors
+
+ if [ ! "$summary" ]; then
+ LESS=$'+/\013^Commit:.[a-f0-9]*|^diff.--git..*$'" $LESS"
+ sedprog="
+s,^\\(Commit: [^ ]*\\)\\(.*\\),$colheader\\1$coldefault\\2,
+s,^Author:.*,$colauthor&$coldefault,
+s,^Date:.*,$colauthor&$coldefault,
+s,^Tree:.*,$colheader&$coldefault,
+s,^Parent:.*,$colheader&$coldefault,
+s,^Committer:.*,$colcommitter&$coldefault,
+s,^Commitdate:.*,$colcommitter&$coldefault,
+s,^ Signed-[Oo]ff[- ][Bb]y:.*,$colsignoff&$coldefault,
+s,^ Acked[- ][Bb]y:.*,$colsignoff&$coldefault,"
+ fi
+
+ [ "$patches" ] && sedprog="$sedprog;$color_rules"
+
+ [ "$diffstat" ] && sedprog="$sedprog
+s,^\\( [^ ].*\\)\\( | *[0-9][0-9]* \\),$colfiles\\1$coldefault\\2,"
+fi
+
+if [ $dtmode = diff-tree -a -z "$filemode" ]; then
+ filediffstart=$'s,^:[0-9]* [^ ]* [^ ]* [^ ]* \('
+ filediffend=$'[^\t]*\)\t\(.*\)'
+ sedprog="$sedprog
+${filediffstart}[NCR]$filediffend,$coldiffadd\\1 \\2$coldefault,
+${filediffstart}D$filediffend,$coldiffrem\\1 \\2$coldefault,
+${filediffstart}.$filediffend,$colfiles\\1 \\2$coldefault,"
fi
-# LESS="S" will prevent less to wrap too long titles to multiple lines;
-# you can scroll horizontally.
-$revls | print_commit_log | LESS="S$LESS" pager
+if [ "$needparse" ]; then
+ # Slow version, parsing output from diff-tree or rev-list
+ unset commit showds from lineno line
+ n=0
+ dolog | ( trap exit SIGPIPE
+ while [ "$line" ] || IFS='' read -r line; do
+ case $line in
+ $dtmode\ *)
+ [ "$maxn" ] && (( ++n > maxn )) && exit
+ [ "$showds" ] && showstat $commit $from
+ line=${line#$dtmode } f="%s\n" showds=$diffstat lineno=0
+ commit=${line% (*} from=${line#*(from }; from=${from%)}
+ [ "$summary" ] && f= || echo "Commit: $line" ;;
+
+ Author:*) printf "$f" "$line"; author=$line ;;
+
+ Date:*) printf "$f" "$line"; date=$line ;;
+
+ author\ *)
+ line=${line#author }; author=${line% [0-9]*}; date=${line##*> }
+ if [ "$f" ]; then
+ printf "$f" "Author: $author"
+ [ "$quiet" ] || printf "$f" "Date: $(showdate $date)"
+ elif [ "$summary" ]; then
+ date=$(showdate $date)
+ fi ;;
+
+ committer\ *)
+ if [ "$verbose" ]; then
+ line=${line#committer }
+ echo "Committer: ${line% [0-9]*}"
+ echo "Commitdate: $(showdate ${line##*> })"
+ fi ;;
+
+ tree\ *) [ "$verbose" ] && echo "Tree: ${line#tree }" ;;
+
+ parent\ *) [ "$verbose" ] && echo "Parent: ${line#parent }" ;;
+
+ \ \ \ \ * | '')
+ if (( ++lineno == 2 )); then
+ [ "$summary" ] &&
+ showsummary $commit "$author" "$date" "$line"
+ [ "$filelist" ] && showfiles $commit $from
+ printf "$f" "$line"
+ [ "$quiet" ] && { f=; echo; }
+ else
+ printf "$f" "$line"
+ fi ;;
+
+ *)
+ [ "$showds" ] && { showstat $commit $from; showds=; }
+ printf "%s\n" "$line"
+ while IFS='' read -r line; do
+ case $line in $dtmode\ *) break ;; esac
+ printf "%s\n" "$line"
+ done
+ continue ;;
+ esac
+ line=
+ done
+ [ "$showds" ] && showstat $commit $from
+ ) | LANG=C sed -e "$sedprog" | pager
+else
+ # Fast version, using sed only.
+ sedprog="s,^$dtmode ,Commit: ,;$sedprog"
+ dolog | LANG=C sed -e "$sedprog" | pager
+fi
next reply other threads:[~2005-06-09 12:44 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-06-09 11:29 Dan Holmsand [this message]
2005-06-09 11:24 ` [PATCH 5/6] Make cg-diff use optparse, and add features Dan Holmsand
2005-06-11 0:02 ` Petr Baudis
2005-06-11 14:29 ` [PATCH] Rewrite cg-diff colorization, add diffstat and reverse Dan Holmsand
2005-06-12 7:29 ` Petr Baudis
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=42A8280A.3070607@gmail.com \
--to=holmsand@gmail.com \
--cc=git@vger.kernel.org \
--cc=pasky@ucw.cz \
/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;
as well as URLs for NNTP newsgroup(s).