Tôi thích câu đố này, nó có sự tinh tế của nó. Nguồn tập tin này, nói init foo.rb 1000,1005
và làm theo hướng dẫn. Khi bạn hoàn tất, tệp @changes
sẽ có danh sách cam kết chính xác theo thứ tự cấu trúc liên kết và @blames
sẽ có đầu ra đổ lỗi thực tế từ mỗi đơn hàng.
Điều này phức tạp hơn nhiều so với the accepted solution above. Nó tạo ra đầu ra đôi khi sẽ hữu ích hơn, và khó tái tạo, và thật thú vị khi viết mã.
Sự cố khi cố gắng tự động theo dõi phạm vi số dòng trong khi bước lùi qua lịch sử là một đoạn đường thay đổi vượt qua ranh giới phạm vi được đánh số dòng bạn không thể tự động xác định vị trí trong đoạn ranh giới phạm vi mới đó sẽ phải bao gồm một phạm vi lớn để bổ sung lớn và vì vậy tích lũy (đôi khi rất nhiều) thay đổi không liên quan, hoặc thả vào chế độ thủ công để đảm bảo nó đúng (tất nhiên là bạn quay lại ngay tại đây), hoặc chấp nhận tổn thất nghiêm trọng ở lần .
Nếu bạn muốn kết quả chính xác, hãy sử dụng câu trả lời ở trên với phạm vi regex đáng tin cậy như `/^type function (/,/^}/', hoặc sử dụng cái này, Để đổi lấy độ phức tạp thêm, nó tạo ra danh sách hit trong chuỗi tôpô và ít nhất nó (khá thành công) cố gắng cải thiện cơn đau ở mỗi bước. Ví dụ, và cập nhật phạm vi làm cho điều chỉnh số dòng dễ dàng hơn. Và tất nhiên có độ tin cậy của việc phải có nhãn cầu riêng từng hunks ... :-P
Để chạy tự động hoàn toàn, hãy nói { init foo.rb /^class foo/,/^end/; auto; } 2>&-
### functions here create random @-prefix files in the current directory ###
#
# git blame history for a range, finding every change to that range
# throughout the available history. It's somewhat, ahh, "intended for
# customization", is that enough of a warning? It works as advertised
# but drops @-prefix temporary files in your current directory and
# defines new commands
#
# Source this file in a subshell, it defines functions for your use.
# If you have @-prefix files you care about, change all @ in this file
# to something you don't have and source it again.
#
# init path/to/file [<start>,<end>] # range optional
# update-ranges # check range boundaries for the next step
# cycle [<start>,<end>] # range unchanged if not supplied
# prettyblame # pretty colors,
# blue="child commit doesn't have this line"
# green="parent commit doesn't have this line"
# brown=both
# shhh # silence the pre-cycle blurb
#
# For regex ranges, you can _usually_ source this file and say `init
# path/to/file /startpattern/,/endpattern/` and then cycle until it says 0
# commits remain in the checklist
#
# for line-number ranges, or regex ranges you think might be unworthy, you
# need to check and possibly update the range before each cycle. File
# @next is the next blame start-point revision text; and command
# update-ranges will bring up vim with the current range V-selected. If
# that looks good, `@M` is set up to quit even while selecting, so `@M` and
# cycle. If it doesn't look good, 'o' and the arrow keys will make getting
# good line numbers easy, or you can find better regex's. Either way, `@M`
# out and say `cycle <start>,<end>` to update the ranges.
init() {
file=$1;
range="$2"
rm -f @changes
git rev-list --topo-order HEAD -- "$file" \
| tee @checklist \
| cat -n | sort -k2 > @sequence
git blame "-ln${range:+L$range}" -- "$file" > @latest || echo >@checklist
check-cycle
cp @latest @blames
}
update-latest-checklist() {
# update $latest with the latest sha that actually touched our range,
# and delete that and everything later than that from the checklist.
latest=$(
sed s,^^,, @latest \
| sort -uk1,1 \
| join -1 2 -o1.1,1.2 @sequence - \
| sort -unk1,1 \
| sed 1q \
| cut -d" " -f2
)
sed -i 1,/^$latest/d @checklist
}
shhh() { shhh=1; }
check-cycle() {
update-latest-checklist
sed -n q1 @checklist || git log $latest~..$latest --format=%H\ %s | tee -a @changes
next=`sed 1q @checklist`
git cat-file -p `git rev-parse $next:"$file"` > @next
test -z "$shh$shhh$shhhh" && {
echo "A blame from the (next-)most recent alteration (id `git rev-parse --short $latest`) to '$file'"
echo is in file @latest, save its contents where you like
echo
echo you will need to look in file @next to determine the correct next range,
echo and say '`cycle its-start-line,its-end-line`' to continue
echo the "update-ranges" function starts you out with the range selected
} >&2
ncommits=`wc -l @checklist | cut -d\ -f1`
echo $ncommits commits remain in the checklist >&2
return $((ncommits==0))
}
update-ranges() {
start="${range%,*}"
end="${range#*,}"
case "$start" in
*/*) startcmd="1G$start"$'\n' ;;
*) startcmd="${start}G" ;;
esac
case "$end" in
*/*) endcmd="$end"$'\n' ;;
[0-9]*) endcmd="${end}G" ;;
+[0-9]*) endcmd="${end}j" ;;
*) endcmd="echohl Search|echo "can\'t" get to '${end}'\"|echohl None" ;;
esac
vim -c 'set buftype=nofile|let @m=":|q'$'\n"' -c "norm!${startcmd}V${endcmd}z.o" @next
}
cycle() {
sed -n q1 @checklist && { echo "No more commits to check"; return 1; }
range="${1:-$range}"
git blame "-ln${range:+L$range}" $next -- "$file" >@latest || echo >@checklist
echo >>@blames
cat @latest >>@blames
check-cycle
}
auto() {
while cycle; do true; done
}
prettyblames() {
cat >@pretty <<-\EOD
BEGIN {
RS=""
colors[0]="\033[0;30m"
colors[1]="\033[0;34m"
colors[2]="\033[0;32m"
colors[3]="\033[0;33m"
getline commits < "@changes"
split(commits,commit,/\n/)
}
NR!=1 { print "" }
{
thiscommit=gensub(/ .*/,"",1,commit[NR])
printf "%s\n","\033[0;31m"commit[NR]"\033[0m"
split($0,line,/\n/)
for (n=1; n<=length(line); ++n) {
color=0
split(line[n],key,/[1-9][0-9]*)/)
if (NR!=1 && !seen[key[1]]) color+=1
seen[key[1]]=1;
linecommit = gensub(/ .*/,"",1,line[n])
if (linecommit==thiscommit) color+=2
printf "%s%s\033[0m\n",colors[color],line[n]
}
}
EOD
awk -f @pretty @blames | less -R
}
Bạn có chắc chắn đây là những gì bạn muốn không? Xác định các thay đổi với số dòng chỉ hoạt động đối với một trạng thái nhất định của tệp. Nếu bạn muốn dòng 15 - 20 cho commit '12345' mã trên các dòng đó có thể nằm trên các dòng 55 - 60 cho commit' 12345^'. – asm
Khá chắc chắn. Đây là lý do tại sao tôi cần phải viết một kịch bản xác định đó là tốt. Tuy nhiên, vì lý do đơn giản, định nghĩa chưa bao giờ chuyển trong tệp từ lần commit ban đầu trong repo. –
có thể trùng lặp của [Lấy nhật ký cam kết cho một dòng cụ thể trong một tệp?] (Http://stackoverflow.com/questions/8435343/retrieve-the-commit-log-for-a-specific-line-in-a -file) –