我使用git有一个不寻常的目的 - 它在我写小说时存储我的文本。 (我知道,我知道......太讨厌了。)
我正在努力追踪生产力,并希望衡量后续提交之间的差异程度。作者对“工作”的代理是“写字”,至少在创作阶段。我不能使用直字数,因为它忽略了编辑和压缩,这两者都是写作的重要部分。我想我想跟踪:
(words added)+(words removed)
会重复计算(单词更改),但我没关系。
输入一些神奇的咒语并让git报告任何两个版本的距离指标都很棒。但是,git diffs是补丁,即使你只是在线上捣乱了一个字符,也会显示整行。我不希望这样,特别是因为我的“行”是段落。理想情况下,我甚至可以用“单词”来指定我的意思(虽然\ W +可能是可以接受的)。
git-diff是否有一个标志,可以逐个字地给出差异?或者,是否有使用标准命令行工具来计算上述指标的解决方案?
答案 0 :(得分:11)
wdiff进行逐字比较。可以将Git配置为使用外部程序进行差异。基于这两个事实和this blog post,以下内容应该大致按照您的要求进行。
创建一个脚本以忽略git-diff
提供的大多数不必要的参数,并将它们传递给wdiff
。将以下内容保存为~/wdiff.py
或类似内容,并使其可执行。
#!/usr/bin/python
import sys
import os
os.system('wdiff -s3 "%s" "%s"' % (sys.argv[2], sys.argv[5]))
告诉git
使用它。
git config --global diff.external ~/wdiff.py
git diff filename
答案 1 :(得分:9)
git diff --word-diff在最新的稳定版git中工作(在git-scm.com上)
有一些选项可以让你决定你想要它的格式,默认是可读的,但如果你将输出提供给脚本,你可能需要--word-diff = porcelain。
答案 2 :(得分:9)
在James' and cornmacrelf's input的基础上,我添加了arithmetic expansion, 并提出了几个可重复使用的别名命令来计算git diff中的单词:
alias gitwa='git diff --word-diff=porcelain origin/master | grep -e "^+[^+]" | wc -w | xargs'
alias gitwd='git diff --word-diff=porcelain origin/master | grep -e "^-[^-]" | wc -w | xargs'
alias gitw='echo $(($(gitwa) - $(gitwd)))'
gitwa
和gitwd
的输出为trimmed using xargs trick。
答案 3 :(得分:8)
我想出了一种方法,可以通过建立其他答案来获得具体数字。结果是近似值,但它应足够接近,以作为添加或删除的字符数量的有用指示。以下是我的当前分支与origin / master相比的示例:
$ git diff --word-diff=porcelain origin/master | grep -e '^+[^+]' | wc -m
38741
$ git diff --word-diff=porcelain origin/master | grep -e '^-[^-]' | wc -m
46664
删除的字符(46664
)与添加的字符(38741
)之间的差异表明我当前的分支已删除大约7923
个字符。由于差异+
/ -
和缩进字符,这些单独添加/删除的计数会被夸大,但是,在大多数情况下,这种差异应抵消该通货膨胀的很大一部分。
答案 4 :(得分:4)
Git已经(很长一段时间)--color-words
git diff
选项。这不会让你计算,但它确实让你看到差异。
然而,还有一个令人兴奋的事情要分享,从git的烹饪方法来说:
* tr/word-diff (2010-04-14) 1 commit
(merged to 'next' on 2010-05-04 at d191b25)
+ diff: add --word-diff option that generalizes --color-words
这是commit introducing word-diff。据推测,它不久将从下一个进入master,然后git将能够在内部完成所有这些 - 或者生成自己的单词diff格式或类似于wdiff的东西。如果你很大胆,你可以从下一个构建git,或者只是将一个提交合并到你的本地master中来构建。
感谢Jakub的评论:如果需要,您可以通过提供gitattributes中记录的单词regex(配置参数diff。*。wordRegex)来进一步自定义单词差异。
答案 5 :(得分:2)
我喜欢Stoutie的answer,并想让它更具可配置性来回答我的一些字数问题。结束以下在ZSH中工作的解决方案,并且应该在Bash中工作。每个函数都会使用revision or revision difference,默认情况下将世界当前状态与origin/master
进行比较:
# Calculate writing word diff between revisions. Cribbed / modified from:
# https://stackoverflow.com/questions/2874318/quantifying-the-amount-of-change-in-a-git-diff
function git_words_added {
revision=${1:-origin/master}
git diff --word-diff=porcelain $revision | \
grep -e "^+[^+]" | \
wc -w | \
xargs
}
function git_words_removed {
revision=${1:-origin/master}
git diff --word-diff=porcelain $revision | \
grep -e "^-[^-]" | \
wc -w | \
xargs
}
function git_words_diff {
revision=${1:-origin/master}
echo $(($(git_words_added $1) - $(git_words_removed $1)))
}
然后你可以像这样使用它:
$ git_words_added
# => how many words were added since origin/master
$ git_words_removed
# => how many words were removed since origin/master
$ git_words_diff
# => difference of adds and removes since origin/master (net words)
$ git_words_diff HEAD
# => net words since you last committed
$ git_words_diff master@{yesterday}
# => net words written today!
$ git_words_diff HEAD^..HEAD
# => net words in the last commit
$ git_words_diff ABC123..DEF456
# => net words between two arbitrary commits
希望这有助于某人!
答案 6 :(得分:1)
对不起,我没有足够的声誉积分来评论@codebeard的答案。这是我使用的版本,我将他的两个版本都添加到了.gitconfig文件中。他们给出了不同的答案,我在第二个版本(将所有修改的文件组合在一起)中将问题追溯到wdiff -sd
,计算了diff -pdrU3
输出顶部两行中的单词。会是这样的:
--- 1 2018-12-10 22:53:47.838902415 -0800
+++ 2 2018-12-10 22:53:57.674835179 -0800
我通过遍历tail -n +4
来解决此问题。
这是我完整的.gitconfig设置,并且已修复:
[alias]
wdiff = diff
wdiffs = difftool -t wdiffs
wdiffs-all = difftool -d -t wdiffs-all
[difftool "wdiffs"]
cmd = wdiff -n -s \"$LOCAL\" \"$REMOTE\" | colordiff
[difftool "wdiffs-all"]
cmd = diff -pdrU3 \"$LOCAL\" \"$REMOTE\" | tail -n +4 | wdiff -sd
如果您想使用git config
,请使用以下命令:
git config --global difftool.wdiffs.cmd 'wdiff -n -s "$LOCAL" "$REMOTE"' | colordiff
git config --global alias.wdiffs 'difftool -t wdiffs'
git config --global difftool.wdiffs-all.cmd 'diff -pdrU3 "$LOCAL" "$REMOTE" | wdiff -sd'
git config --global alias.wdiffs-all 'difftool -d -t wdiffs-all'
现在,您可以执行git wdiffs
或git wdiffs-all
来获取自上次提交以来的字数。
要与来源/母版进行比较,请执行git wdiffs origin/master
或git wdiffs-all origin/master
。
我最喜欢这个答案,因为它同时给出了字数和差异,并且如果您通过colordiff
进行传递,它的外观也会很漂亮而且颜色也很丰富。 (@Miles答案也不错,但需要您弄清楚要使用什么时间。但是,我喜欢寻找移动文本的想法。)
wdiff的统计信息最后输出如下:
file1.txt: 12360 words 12360 100% common 0 0% deleted 5 0% changed
file2.txt: 12544 words 12360 99% common 184 1% inserted 11 0% changed
要找出您添加了多少个单词,请在上面的示例的第二行184 + 11中添加inserted
和changed
。
为什么第一行什么都没有?答案:那些词被删除了。
这是一个bash脚本,用于获得一个统一的字数统计:
wdiffoutput=$(git wdiffs-all | tail -n 1)
wdiffins=$(echo "$wdiffoutput" | grep -oP "common *\K\d*")
wdiffchg=$(echo "$wdiffoutput" | grep -oP "inserted *\K\d*")
echo "Word Count: $((wdiffins+wdiffchg))"
答案 7 :(得分:0)
由于Git 1.6.3还有git difftool
,它可以配置为运行几乎任何外部差异工具。这比需要创建脚本等的一些解决方案容易得多。如果您喜欢wdiff -s
的输出,可以配置如下内容:
git config --global difftool.wdiffs.cmd 'wdiff -s "$LOCAL" "$REMOTE"'
git config --global alias.wdiffs 'difftool -t wdiffs'
现在您可以运行git difftool -t wdiffs
或其别名git wdiffs
。
如果您希望同时获取所有已修改文件的统计信息,请执行以下操作:
git config --global difftool.wdiffs.cmd 'diff -pdrU3 "$LOCAL" "$REMOTE" | wdiff -sd'
git config --global alias.wdiffs 'difftool -d -t wdiffs'
这将获取典型的统一diff
的输出,并将其输入wdiff
,并将-d
选项设置为仅解释输入。相反,别名中-d
的额外difftool
参数告诉git在执行diff之前将所有已修改的文件复制到临时目录。
答案 8 :(得分:0)
上述答案因某些需要排除移动文本的用例而失败(例如,如果我在代码中移动一个函数或者在文档中进一步向下移动文档,我不想将所有这些作为更改计算! )
为此,您还可以计算重复行数,如果副本太多,则从查询中排除这些行。
例如,基于其他答案,我可以这样做:
git diff $sha~1..$sha|grep -e"^+[^+]" -e"^-[^-]"|sed -e's/.//'|sort|uniq -d|wc -w|xargs
计算差异中重复单词的数量,其中sha
是您的提交。
您可以在最后一天(从早上6点开始)的所有提交中执行以下操作:
for sha in $(git rev-list --since="6am" master | sed -e '$ d'); do
echo $(git diff --word-diff=porcelain $sha~1..$sha|grep -e"^+[^+]"|wc -w|xargs),\
$(git diff --word-diff=porcelain $sha~1..$sha|grep -e"^-[^-]"|wc -w|xargs),\
$(git diff $sha~1..$sha|grep -e"^+[^+]" -e"^-[^-]"|sed -e's/.//'|sort|uniq -d|wc -w|xargs)
done
打印:添加,删除,重复
(我对重复项采用了行差异,因为它排除了git diff
试图过于聪明的时间,并假设您实际上只是更改了文本而不是移动它。它还会折扣单个单词的实例被视为重复。)
或者,如果您想要对它进行复杂化,如果重复率超过80%,则可以完全排除提交,并总结其余部分:
total=0
for sha in $(git rev-list --since="6am" master | sed -e '$ d'); do
added=$(git diff --word-diff=porcelain $sha~1..$sha|grep -e"^+[^+]"|wc -w|xargs)
deleted=$(git diff --word-diff=porcelain $sha~1..$sha|grep -e"^-[^-]"|wc -w|xargs)
duplicated=$(git diff $sha~1..$sha|grep -e"^+[^+]" -e"^-[^-]"|sed -e's/.//'|sort|uniq -d|wc -w|xargs)
if [ "$added" -eq "0" ]; then
changed=$deleted
total=$((total+deleted))
echo "added:" $added, "deleted:" $deleted, "duplicated:"\
$duplicated, "changed:" $changed
elif [ "$(echo "$duplicated/$added > 0.8" | bc -l)" -eq "1" ]; then
echo "added:" $added, "deleted:" $deleted, "duplicated:"\
$duplicated, "changes counted:" 0
else
changed=$((added+deleted))
total=$((total+changed))
echo "added:" $added, "deleted:" $deleted, "duplicated:"\
$duplicated, "changes counted:" $changed
fi
done
echo "Total changed:" $total
我有这个脚本在这里执行:https://github.com/MilesCranmer/git-stats。
打印出来:
➜ bifrost_paper git:(master) ✗ count_changed_words "6am"
added: 38, deleted: 76, duplicated: 3, changes counted: 114
added: 14, deleted: 19, duplicated: 0, changes counted: 33
added: 1113, deleted: 1112, duplicated: 1106, changes counted: 0
added: 1265, deleted: 1275, duplicated: 1225, changes counted: 0
added: 4207, deleted: 4208, duplicated: 4391, changes counted: 0
Total changed: 147
我只是在处理事物的提交是显而易见的,所以我不计算这些变化。它会计算其他所有内容并告诉我更改单词的总数。