當使用 Git 儲存庫時,這六個 Bash 指令碼將使你的生活更輕鬆。
我編寫了許多 Bash 指令碼,這些指令碼使我在使用 Git 儲存庫時工作更加輕鬆。我的許多同事說沒有必要:我所做的一切都可以用 Git 命令完成。雖然這可能是正確的,但我發現指令碼遠比嘗試找出適當的 Git 命令來執行我想要的操作更加方便。
gitlog
列印針對 master 分支的當前修補程式的簡短列表。它從最舊到最新列印它們,並顯示作者和描述,其中 H
代表 HEAD
,^
代表 HEAD^
,2
代表 HEAD~2
,依此類推。例如:
$ gitlog-----------------------[ recovery25 ]-----------------------(snip)11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode 9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glops 8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite 7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing 6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency 5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite 4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite 3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation 2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops ^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time
如果我想檢視其他分支上有哪些修補程式,可以指定一個替代分支:
$ gitlog recovery24
gitlog.id
只是列印出修補程式的 SHA1 ID:
$ gitlog.id-----------------------[ recovery25 ]-----------------------56908eeb6940 2ca4a6b628a1 fc64ad5d99fe 02031a00a251 f6f38da7dd18 d8546e8f0023 fc3cc1f98f6b 12c3e0cb3523 76cce178b134 6fc1dce3ab9c 1b681ab074ca 26fed8de719b 802ff51a5670 49f67a512d8c f04f20193bbb 5f6afe809d23 2030521dc70e dada79b3be94 9b19a1e08161 78a035041d3e f03da011cae2 0d2b2e068fcd 2449976aa133 57dfb5e12ccd 53abedfdcf72 6fbdda3474b3 49544a547188 187032f7a63c 6f75dae23d93 95fc2a261b00 ebfb14ded191 f653ee9e414a 0e2911cb8111 73968b76e2e3 8a3e4cb5e92c a5f2da803b5b 7c9ef68388ed 71ca19d0cba8 340d27a33895 9b3c4e6efb10 d2e8c22be39b 9563e31f8bfd ebac7a38036c f703a3c27874 a3e86d2ef30e da3c604755b0 4525c2f5b46f a06a5b7dea02 8ba93c796d5c e8b5ff851bb9
同樣,它假定是當前分支,但是如果需要,我可以指定其他分支。
gitlog.id2
與 gitlog.id
相同,但頂部沒有顯示分支的行。這對於從一個分支挑選所有修補程式到當前分支很方便:
$ # 建立一個新分支$ git branch --track origin/master$ # 檢出剛剛建立的新分支$ git checkout recovery26$ # 從舊的分支挑選所有修補程式到新分支$ for i in `gitlog.id2 recovery25` ; do git cherry-pick $i ;done
gitlog.grep
會在該修補程式集合中尋找一個字串。例如,如果我發現一個錯誤並想修復參照了函數 inode_go_sync
的修補程式,我可以簡單地執行以下操作:
$ gitlog.grep inode_go_sync-----------------------[ recovery25 - 50 patches ]-----------------------(snip)11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode 9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glops152:-static void inode_go_sync(struct gfs2_glock *gl)153:+static int inode_go_sync(struct gfs2_glock *gl)163:@@ -296,6 +302,7 @@ static void inode_go_sync(struct gfs2_glock *gl) 8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite 7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing 6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency 5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite 4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite 3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation 2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops ^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time
因此,現在我知道修補程式 HEAD~9
是需要修復的修補程式。我使用 git rebase -i HEAD~10
編輯修補程式 9,git commit -a --amend
,然後 git rebase --continue
以進行必要的調整。
gitbranchcmp3
使我可以將當前分支與另一個分支進行比較,因此我可以將較舊版本的修補程式與我的較新版本進行比較,並快速檢視已更改和未更改的內容。它生成一個比較指令碼(使用了 KDE 工具 Kompare,該工具也可在 GNOME3 上使用)以比較不太相同的修補程式。如果除行號外沒有其他差異,則列印 [SAME]
。如果僅存在註釋差異,則列印 [same]
(小寫)。例如:
$ gitbranchcmp3 recovery24Branch recovery24 has 47 patchesBranch recovery25 has 50 patches(snip)38 87eb6901607a 340d27a33895 [same] gfs2: drain the ail2 list after io errors39 90fefb577a26 9b3c4e6efb10 [same] gfs2: clean up iopen glock mess in gfs2_create_inode40 ba3ae06b8b0e d2e8c22be39b [same] gfs2: Do proper error checking for go_sync family of glops41 2ab662294329 9563e31f8bfd [SAME] gfs2: use page_offset in gfs2_page_mkwrite42 0adc6d817b7a ebac7a38036c [SAME] gfs2: don't use buffer_heads in gfs2_allocate_page_backing43 55ef1f8d0be8 f703a3c27874 [SAME] gfs2: Improve mmap write vs. punch_hole consistency44 de57c2f72570 a3e86d2ef30e [SAME] gfs2: Multi-block allocations in gfs2_page_mkwrite45 7c5305fbd68a da3c604755b0 [SAME] gfs2: Fix end-of-file handling in gfs2_page_mkwrite46 162524005151 4525c2f5b46f [SAME] Rafael Aquini's slab instrumentation47 a06a5b7dea02 [ ] GFS2: Add go_get_holdtime to gl_ops48 8ba93c796d5c [ ] gfs2: introduce new function remaining_hold_time and use it in dq49 e8b5ff851bb9 [ ] gfs2: Allow rgrps to have a minimum hold timeMissing from recovery25:The missing:Compare script generated at: /tmp/compare_mismatches.sh
最後,我有一個 gitlog.find
指令碼,可以幫助我識別修補程式程式的上游版本在哪裡以及每個修補程式的當前狀態。它通過匹配修補程式說明來實現。它還會生成一個比較指令碼(再次使用了 Kompare),以將當前修補程式與上游對應修補程式進行比較:
$ gitlog.find-----------------------[ recovery25 - 50 patches ]-----------------------(snip)11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errorslo 5bcb9be74b2a Bob Peterson gfs2: drain the ail2 list after io errors10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inodefn 2c47c1be51fb Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode 9 d2e8c22be39b Bob Peterson gfs2: Do proper error checking for go_sync family of glopslo feb7ea639472 Bob Peterson gfs2: Do proper error checking for go_sync family of glops 8 9563e31f8bfd Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwritems f3915f83e84c Christoph Hellwig gfs2: use page_offset in gfs2_page_mkwrite 7 ebac7a38036c Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backingms 35af80aef99b Christoph Hellwig gfs2: don't use buffer_heads in gfs2_allocate_page_backing 6 f703a3c27874 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistencyfn 39c3a948ecf6 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency 5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwritefn f53056c43063 Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite 4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwritefn 184b4e60853d Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite 3 4525c2f5b46f Bob Peterson Rafael Aquini's slab instrumentation Not found upstream 2 a06a5b7dea02 Bob Peterson GFS2: Add go_get_holdtime to gl_ops Not found upstream ^ 8ba93c796d5c Bob Peterson gfs2: introduce new function remaining_hold_time and use it in dq Not found upstream H e8b5ff851bb9 Bob Peterson gfs2: Allow rgrps to have a minimum hold time Not found upstreamCompare script generated: /tmp/compare_upstream.sh
修補程式顯示為兩行,第一行是你當前的修補程式,然後是相應的上游修補程式,以及 2 個字元的縮寫,以指示其上游狀態:
lo
表示修補程式僅在本地(local
)上游 Git 儲存庫中(即尚未推播到上游)。ms
表示修補程式位於 Linus Torvald 的主(master
)分支中。fn
意味著修補程式被推播到我的 “for-next” 開發分支,用於下一個上游合併視窗。 我的一些指令碼根據我通常使用 Git 的方式做出假設。例如,當搜尋上游修補程式時,它使用我眾所周知的 Git 樹的位置。因此,你需要調整或改進它們以適合你的條件。gitlog.find
指令碼旨在僅定位 GFS2 和 DLM 修補程式,因此,除非你是 GFS2 開發人員,否則你需要針對你感興趣的元件對其進行自定義。以下是這些指令碼的原始碼。
#!/bin/bashbranch=$1if test "x$branch" = x; then branch=`git branch -a | grep "*" | cut -d ' ' -f2`fipatches=0tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`LIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`for i in $LIST; do patches=$(echo $patches + 1 | bc);doneif [[ $branch =~ .*for-next.* ]]then start=HEAD# start=origin/for-nextelse start=origin/masterfitracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`/usr/bin/echo "-----------------------[" $branch "]-----------------------"patches=$(echo $patches - 1 | bc);for i in $LIST; do if [ $patches -eq 1 ]; then cnt=" ^" elif [ $patches -eq 0 ]; then cnt=" H" else if [ $patches -lt 10 ]; then cnt=" $patches" else cnt="$patches" fi fi /usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s %n" $i patches=$(echo $patches - 1 | bc)done#git log --reverse --abbrev-commit --pretty=format:"%h %<|(32)%an %s" $tracking..$branch#git log --reverse --abbrev-commit --pretty=format:"%h %<|(32)%an %s" ^origin/master ^linux-gfs2/for-next $branch
#!/bin/bashbranch=$1if test "x$branch" = x; then branch=`git branch -a | grep "*" | cut -d ' ' -f2`fitracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`/usr/bin/echo "-----------------------[" $branch "]-----------------------"git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
#!/bin/bashbranch=$1if test "x$branch" = x; then branch=`git branch -a | grep "*" | cut -d ' ' -f2`fitracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
#!/bin/bashparam1=$1param2=$2if test "x$param2" = x; then branch=`git branch -a | grep "*" | cut -d ' ' -f2` string=$param1else branch=$param1 string=$param2fipatches=0tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`LIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`for i in $LIST; do patches=$(echo $patches + 1 | bc);done/usr/bin/echo "-----------------------[" $branch "-" $patches "patches ]-----------------------"patches=$(echo $patches - 1 | bc);for i in $LIST; do if [ $patches -eq 1 ]; then cnt=" ^" elif [ $patches -eq 0 ]; then cnt=" H" else if [ $patches -lt 10 ]; then cnt=" $patches" else cnt="$patches" fi fi /usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s" $i /usr/bin/git show --pretty=email --patch-with-stat $i | grep -n "$string" patches=$(echo $patches - 1 | bc)done
#!/bin/bash## gitbranchcmp3 <old branch> [<new_branch>]#oldbranch=$1newbranch=$2script=/tmp/compare_mismatches.sh/usr/bin/rm -f $scriptecho "#!/bin/bash" > $script/usr/bin/chmod 755 $scriptecho "# Generated by gitbranchcmp3.sh" >> $scriptecho "# Run this script to compare the mismatched patches" >> $scriptecho " " >> $scriptecho "function compare_them()" >> $scriptecho "{" >> $scriptecho " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $scriptecho " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $scriptecho " kompare /tmp/gronk1 /tmp/gronk2" >> $scriptecho "}" >> $scriptecho " " >> $scriptif test "x$newbranch" = x; then newbranch=`git branch -a | grep "*" | cut -d ' ' -f2`fitracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`declare -a oldsha1s=(`git log --reverse --abbrev-commit --pretty=oneline $tracking..$oldbranch | cut -d ' ' -f1 |paste -s -d ' '`)declare -a newsha1s=(`git log --reverse --abbrev-commit --pretty=oneline $tracking..$newbranch | cut -d ' ' -f1 |paste -s -d ' '`)#echo "old: " $oldsha1soldcount=${#oldsha1s[@]}echo "Branch $oldbranch has $oldcount patches"oldcount=$(echo $oldcount - 1 | bc)#for o in `seq 0 ${#oldsha1s[@]}`; do# echo -n ${oldsha1s[$o]} " "# desc=`git show $i | head -5 | tail -1|cut -b5-`#done#echo "new: " $newsha1snewcount=${#newsha1s[@]}echo "Branch $newbranch has $newcount patches"newcount=$(echo $newcount - 1 | bc)#for o in `seq 0 ${#newsha1s[@]}`; do# echo -n ${newsha1s[$o]} " "# desc=`git show $i | head -5 | tail -1|cut -b5-`#doneechofor new in `seq 0 $newcount`; do newsha=${newsha1s[$new]} newdesc=`git show $newsha | head -5 | tail -1|cut -b5-` oldsha=" " same="[ ]" for old in `seq 0 $oldcount`; do if test "${oldsha1s[$old]}" = "match"; then continue; fi olddesc=`git show ${oldsha1s[$old]} | head -5 | tail -1|cut -b5-` if test "$olddesc" = "$newdesc" ; then oldsha=${oldsha1s[$old]} #echo $oldsha git show $oldsha |tail -n +2 |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk1 git show $newsha |tail -n +2 |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk2 diff /tmp/gronk1 /tmp/gronk2 &> /dev/null if [ $? -eq 0 ] ;then# No differences same="[SAME]" oldsha1s[$old]="match" break fi git show $oldsha |sed -n '/diff/,$p' |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk1 git show $newsha |sed -n '/diff/,$p' |grep -v "index.*\.\." |grep -v "@@" > /tmp/gronk2 diff /tmp/gronk1 /tmp/gronk2 &> /dev/null if [ $? -eq 0 ] ;then# Differences in comments only same="[same]" oldsha1s[$old]="match" break fi oldsha1s[$old]="match" echo "compare_them $oldsha $newsha" >> $script fi done echo "$new $oldsha $newsha $same $newdesc"doneechoecho "Missing from $newbranch:"the_missing=""# Now run through the olds we haven't matched upfor old in `seq 0 $oldcount`; do if test ${oldsha1s[$old]} != "match"; then olddesc=`git show ${oldsha1s[$old]} | head -5 | tail -1|cut -b5-` echo "${oldsha1s[$old]} $olddesc" the_missing=`echo "$the_missing ${oldsha1s[$old]}"` fidoneecho "The missing: " $the_missingecho "Compare script generated at: $script"#git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
#!/bin/bash## Find the upstream equivalent patch## gitlog.find#cwd=$PWDparam1=$1ubranch=$2patches=0script=/tmp/compare_upstream.shecho "#!/bin/bash" > $script/usr/bin/chmod 755 $scriptecho "# Generated by gitbranchcmp3.sh" >> $scriptecho "# Run this script to compare the mismatched patches" >> $scriptecho " " >> $scriptecho "function compare_them()" >> $scriptecho "{" >> $scriptecho " cwd=$PWD" >> $scriptecho " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $scriptecho " cd ~/linux.git/fs/gfs2" >> $scriptecho " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $scriptecho " cd $cwd" >> $scriptecho " kompare /tmp/gronk1 /tmp/gronk2" >> $scriptecho "}" >> $scriptecho " " >> $script#echo "Gathering upstream patch info. Please wait."branch=`git branch -a | grep "*" | cut -d ' ' -f2`tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`cd ~/linux.gitif test "X${ubranch}" = "X"; then ubranch=`git branch -a | grep "*" | cut -d ' ' -f2`fiutracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`## gather a list of gfs2 patches from master just in case we can't find it##git log --abbrev-commit --pretty=format:" %h %<|(32)%an %s" master |grep -i -e "gfs2" -e "dlm" > /tmp/gronkgit log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/gfs2/ > /tmp/gronk.gfs2# ms = in Linus's mastergit log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/dlm/ > /tmp/gronk.dlmcd $cwdLIST=`git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '`for i in $LIST; do patches=$(echo $patches + 1 | bc);done/usr/bin/echo "-----------------------[" $branch "-" $patches "patches ]-----------------------"patches=$(echo $patches - 1 | bc);for i in $LIST; do if [ $patches -eq 1 ]; then cnt=" ^" elif [ $patches -eq 0 ]; then cnt=" H" else if [ $patches -lt 10 ]; then cnt=" $patches" else cnt="$patches" fi fi /usr/bin/git show --abbrev-commit -s --pretty=format:"$cnt %h %<|(32)%an %s" $i desc=`/usr/bin/git show --abbrev-commit -s --pretty=format:"%s" $i` cd ~/linux.git cmp=1 up_eq=`git log --reverse --abbrev-commit --pretty=format:"lo %h %<|(32)%an %s" $utracking..$ubranch | grep "$desc"`# lo = in local for-next if test "X$up_eq" = "X"; then up_eq=`git log --reverse --abbrev-commit --pretty=format:"fn %h %<|(32)%an %s" master..$utracking | grep "$desc"`# fn = in for-next for next merge window if test "X$up_eq" = "X"; then up_eq=`grep "$desc" /tmp/gronk.gfs2` if test "X$up_eq" = "X"; then up_eq=`grep "$desc" /tmp/gronk.dlm` if test "X$up_eq" = "X"; then up_eq=" Not found upstream" cmp=0 fi fi fi fi echo "$up_eq" if [ $cmp -eq 1 ] ; then UP_SHA1=`echo $up_eq|cut -d' ' -f2` echo "compare_them $UP_SHA1 $i" >> $script fi cd $cwd patches=$(echo $patches - 1 | bc)doneecho "Compare script generated: $script"