Git : 어떤 커밋이 줄의 범위에 닿았는지 발견
내가 사용하는 방법을 알아내는 데 문제가 git blame
커밋의 집합을 얻기 위해 어느 라인의 지정된 범위를 감동을. 이와 비슷한 질문 이 있지만 받아 들여진 대답은 저를 더 이상 가져 오지 않습니다.
의 1000 번째 줄에서 시작하는 정의가 있다고 가정 해 보겠습니다 foo.rb
. 길이는 5 줄에 불과하지만 해당 줄을 변경 한 커밋의 수는 엄청납니다. 만약 내가한다면
git blame foo.rb -L 1000,+5
이 줄을 변경 한 (최대) 5 개의 개별 커밋에 대한 참조를 얻지 만 "그 뒤에있는"커밋에도 관심이 있습니다.
비슷하게,
git rev-list HEAD -- foo.rb | xargs git log --oneline
거의 내가 원하는 것이지만 라인 범위를 지정할 수 없습니다. git rev-list
플래그를 전달하여 git blame
그 다섯 줄에 닿은 커밋 목록을 가져올 수 있습니까? 아니면 그러한 정보를 추출하는 스크립트를 만드는 가장 빠른 방법은 무엇입니까? 한때 정의가 5 줄보다 많거나 적은 가능성을 잠시 무시합시다.
힘내 1.8.4 이후 , git log
이 -L
라인의 범위의 진화를 볼 수 있습니다.
예를 들어 git blame
의 출력을 본다고 가정합니다 .
((aa27064...))[mlm@macbook:~/w/mlm/git]
$ git blame -L150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150) die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156) # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157) vers=$(expr "$($browser_path -version)"
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158) NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159) test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov 2008-02-09 23:22:22 -0800 160) "$browser_path" $NEWTAB "$@" &
이제 155 행의 역사를 알고 싶습니다.
그때:
((aa27064...))[mlm@macbook:~/w/mlm/git]
$ git log --topo-order --graph -u -L 155,155:git-web--browse.sh
* commit 81f42f11496b9117273939c98d270af273c8a463
| Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
| Date: Fri Dec 3 17:47:38 2010 +0100
|
| web--browse: support opera, seamonkey and elinks
|
| The list of supported browsers is also updated in the documentation.
|
| Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
| Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
| diff --git a/git-web--browse.sh b/git-web--browse.sh
| --- a/git-web--browse.sh
| +++ b/git-web--browse.sh
| @@ -143,1 +143,1 @@
| -firefox|iceweasel)
| +firefox|iceweasel|seamonkey|iceape)
|
* commit a180055a47c6793eaaba6289f623cff32644215b
| Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
| Date: Fri Dec 3 17:47:36 2010 +0100
|
| web--browse: coding style
|
| Retab and deindent choices in case statements.
|
| Signed-off-by: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>
| Signed-off-by: Junio C Hamano <gitster@pobox.com>
|
| diff --git a/git-web--browse.sh b/git-web--browse.sh
| --- a/git-web--browse.sh
| +++ b/git-web--browse.sh
| @@ -142,1 +142,1 @@
| - firefox|iceweasel)
| +firefox|iceweasel)
|
* commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <chriscool@tuxfamily.org>
Date: Sat Feb 2 07:32:53 2008 +0100
Rename 'git-help--browse.sh' to 'git-web--browse.sh'.
Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+ firefox|iceweasel)
이 기능을 자주 사용하는 경우 git 별칭이 유용 할 수 있습니다. 그렇게하려면 다음을 입력하십시오 ~/.gitconfig
.
[alias]
# Follow evolution of certain lines in a file
# arg1=file, arg2=first line, arg3=last line or blank for just the first line
follow = "!sh -c 'git log --topo-order -u -L $2,${3:-$2}:"$1"'" -
그리고 이제 당신은 할 수 있습니다 git follow git-web--browse.sh 155
.
나는 이것이 당신이 원하는 것이라고 생각합니다.
git rev-list HEAD -- foo.rb | (
while read rev; do
git blame -l -L 1000,+5 $rev -- foo.rb | cut -d ' ' -f 1
done;
) | awk '{ if (!h[$0]) { print $0; h[$0]=1 } }'
선택한 행에 대한 편집이있는 각 커밋의 개정 번호가 출력됩니다.
단계는 다음과 같습니다.
첫 번째 부분
git rev-list HEAD -- foo.rb
은 선택한 파일이 편집 된 모든 개정을 출력합니다.그런 다음 각 수정 사항은 두 번째 부분으로 이동하여 각 수정 사항을 가져 와서
git blame -l -L 1000,+5 $rev -- foo.rb | cut -d ' ' -f 1
. 이것은 두 부분으로 구성된 명령입니다.git blame -l -L 1000,+5 $rev -- foo.rb
선택한 라인에 대한 책임을 출력합니다. 개정 번호를 제공함으로써 우리는 헤드에서 시작하는 것이 아니라 커밋에서 시작하여 거기에서 가도록 지시합니다.- blame은 우리가 필요로하지 않는 많은 정보를 출력하기 때문에, blame 출력
cut -d ' ' -f 1
의 첫 번째 열 (수정 번호)을 제공합니다.
awk '{ if (!h[$0]) { print $0; h[$0]=1 } }'
나타나는 순서를 유지하면서 인접하지 않은 중복 줄을 제거합니다. 이 명령에 대한 자세한 내용은 http://jeetworks.org/node/94 를 참조하십시오 .
더 예쁜 결과물을 얻으려면 여기에 마지막 단계를 추가 할 수 있습니다. 모든 것을 파이프로 연결 xargs -L 1 git log --oneline -1
하고 개정 목록에 해당하는 커밋 메시지를 가져옵니다. 이 마지막 단계를 사용하여 출력되는 몇 가지 수정 사항을 계속 눌러야하는 이상한 문제가 발생했습니다. 그게 왜 그런지 잘 모르겠 기 때문에 솔루션에 포함하지 않았습니다.
무엇을하고 싶은지 확실하지 않지만 git log -S 가 트릭을 수행 할 수 있습니다.
-S<string> Look for differences that introduce or remove an instance of <string>. Note that this is different than the string simply appearing in diff output; see the pickaxe entry in gitdiffcore(7) for more details.
따르려는 변경 사항 (또는 변경 사항의 일부)을 문자열에 입력하면이 변경 사항을 건드린 커밋이 나열됩니다.
이 퍼즐이 마음에 들었고 미묘함이 있습니다. 이 파일을 소싱 init foo.rb 1000,1005
하고 지시 사항을 따르십시오. 완료되면 파일 @changes
은 토폴로지 순서로 올바른 커밋 목록 @blames
을 가지며 각각의 실제 비난 출력을 갖게됩니다.
이것은 위에서 받아 들여진 솔루션 보다 훨씬 더 복잡 합니다 . 때로는 더 유용하고 재현하기 어려운 출력을 생성하며 코딩하는 것이 재미있었습니다.
기록을 뒤로 이동하는 동안 줄 번호 범위를 자동으로 추적하려는 경우의 문제는 변경 덩어리가 줄 번호 범위 경계를 넘으면 해당 덩어리에서 새 범위 경계가 있어야하는 위치를 자동으로 결정할 수 없다는 것입니다. 큰 추가를 위해 큰 범위를 포함하고 관련없는 변경 사항을 축적하거나 (때로는 많은) 관련없는 변경 사항을 축적하거나 수동 모드로 내려가 올바른지 확인하거나 (물론 여기로 돌아갈 수 있습니다) 때로는 극심한 손실을 받아들이십시오.
정확한 출력을 원하면`/ ^ type function (/, / ^} / '과 같은 신뢰할 수있는 정규식 범위와 함께 위의 답변을 사용하거나 실제로 그렇게 나쁘지 않은 이것을 사용하십시오. 제 시간에.
추가 복잡성을 대신하여 토폴로지 순서로 히트리스트를 생성하고 적어도 (상당히 성공적으로) 각 단계에서 통증을 개선하려고 시도합니다. 예를 들어 중복 비난을 실행하지 않으며 업데이트 범위를 사용하면 줄 번호를 쉽게 조정할 수 있습니다. 그리고 당연히 덩치들을 개별적으로 주시해야하는 신뢰성이 있습니다 ... :-P
완전 자동으로 실행하려면 다음과 같이 말하십시오. { 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
}
여기에 게시 된 답변을 참조하십시오 . 특정 파일에 대한 모든 커밋 나열 . 정확히 필요한 것입니다.
몇 가지 생각 ..
이 게시물 과 비슷하게 들리며 다음과 같이 가까워 질 수 있습니다.
git blame -L '/variable_name *= */',+1
일치시킬 정의를 알고있는 한 (정규식의 경우).
There is a thread discussion here, about using tig
and git gui
(which apparently might handle this). I haven't tried this myself yet, so can't verify it (I'll give this a try later).
'Program Tip' 카테고리의 다른 글
UICollectionView 어설 션 실패 (0) | 2020.12.08 |
---|---|
INSERT 문을 사용하여 MySQL Workbench로 테이블 내보내기 (0) | 2020.12.08 |
UINavigationController를 사용하지 않고 Storyboard에서 UINavigationBar의 높이를 변경하는 방법이 있습니까? (0) | 2020.12.08 |
PostgreSQL에서 누적 합계 계산 (0) | 2020.12.08 |
dockerfile을 통해 docker 이미지를 빌드하는 동안 cmd 행을 통해 ENV 변수를 전달할 수 있습니까? (0) | 2020.12.08 |