Merge remote-tracking branch 'LCTT/master'

This commit is contained in:
Xingyu Wang 2020-01-18 22:40:57 +08:00
commit ff991672ee
4 changed files with 806 additions and 827 deletions

View File

@ -1,303 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (setV: A Bash function to maintain Python virtual environments)
[#]: via: (https://opensource.com/article/20/1/setv-bash-function)
[#]: author: (Sachin Patil https://opensource.com/users/psachin)
setV: A Bash function to maintain Python virtual environments
======
Get to know setV, a lightweight Python virtual environment manager and
alternative to virtualenvwrapper.
![Coding on a computer][1]
For more than a year, [setV][2] has been hidden away within my [bash_scripts][3] project, but it's time for it to become public. setV is a Bash function I use as an alternative to [virtualenvwrapper][4]. It provides basic features that enable you to do things such as:
* Use Python 3 by default
* Create a new virtual environment
* Create a new virtual environment using a custom Python path with **-p** (or **\--python**)
* Delete an existing virtual environment
* List all existing virtual environment
* Use Tab completion (in case you don't remember the virtual environment name)
### Installation
To install setV, download the script:
```
`curl https://gitlab.com/psachin/setV/raw/master/install.sh`
```
Review the script, and then run it:
```
`sh ./install.sh`
```
When you install setV, the installation script asks you to source **~/.bashrc** or **~/.bash_profile**. Be sure to do that.
### Usage
The basic command is **setv**.
#### Create a virtual environment:
```
setv --new rango  # setv -n rango
# Or using a custom Python binary path
setv --new --python /opt/python/python3 rango  # setv -n -p /opt/python/python3 rango
```
#### Activate an existing environment:
```
setv VIRTUAL_ENVIRONMENT_NAME
# For example
setv rango
```
#### List all virtual environments:
```
setv --list
# or
setv [TAB] [TAB]
```
#### Delete a virtual environment:
```
`setv --delete rango`
```
#### Switch to another virtual environment:
```
# Assuming you are in 'rango', switch to 'tango' using
setv tango
```
#### Tab Completion
If you don't fully remember the virtual environment's name, Bash-like Tab completion works for virtual environment names.
### Get involved
setV is open source under the GNU [GPLv3][5], and contributions are welcome. To learn more, visit the Contribute section of setV's [README][6] in its GitLab repository.
### The setV script
```
#!/usr/bin/env bash
# setV - A Lightweight Python virtual environment manager.
# Author: Sachin (psachin) <[iclcoolster@gmail.com][7]>
# Author's URL: <https://psachin.gitlab.io/about>
#
# License: GNU GPL v3, See LICENSE file
#
# Configure(Optional):
# Set `SETV_VIRTUAL_DIR_PATH` value to your virtual environments
# directory-path. By default it is set to '~/virtualenvs/'
#
# Usage:
# Manual install: Added below line to your .bashrc or any local rc script():
# ---
# source /path/to/virtual.sh
# ---
#
# Now you can 'activate' the virtual environment by typing
# $ setv &lt;YOUR VIRTUAL ENVIRONMENT NAME&gt;
#
# For example:
# $ setv rango
#
# or type:
# setv [TAB] [TAB]  (to list all virtual envs)
#
# To list all your virtual environments:
# $ setv --list
#
# To create new virtual environment:
# $ setv --new new_virtualenv_name
#
# To delete existing virtual environment:
# $ setv --delete existing_virtualenv_name
#
# To deactivate, type:
# $ deactivate
# Path to virtual environment directory
SETV_VIRTUAL_DIR_PATH="$HOME/virtualenvs/"
# Default python version to use. This decides whether to use `virtualenv` or `python3 -m venv`
SETV_PYTHON_VERSION=3  # Defaults to Python3
SETV_PY_PATH=$(which python${SETV_PYTHON_VERSION})
function _setvcomplete_()
{
    # Bash-autocompletion.
    # This ensures Tab-auto-completions work for virtual environment names.
    local cmd="${1##*/}" # to handle command(s).
                         # Not necessary as such. 'setv' is the only command
    local word=${COMP_WORDS[COMP_CWORD]} # Words thats being completed
    local xpat='${word}'                 # Filter pattern. Include
                                         # only words in variable '$names'
    local names=$(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}') # Virtual environment names
    COMPREPLY=($(compgen -W "$names" -X "$xpat" -- "$word")) # compgen generates the results
}
function _setv_help_() {
    # Echo help/usage message
    echo "Usage: setv [OPTIONS] [NAME]"
    echo Positional argument:
    echo -e "NAME                       Activate virtual env."
    echo Optional arguments:
    echo -e "-l, --list                 List all Virtual Envs."
    echo -e "-n, --new NAME             Create a new Python Virtual Env."
    echo -e "-d, --delete NAME          Delete existing Python Virtual Env."
    echo -e "-p, --python PATH          Python binary path."
}
function _setv_custom_python_path()
{
    if [ -f "${1}" ];
    then
        if [ "`expr $1 : '.*python\\([2,3]\\)'`" = "3" ];
        then
            SETV_PYTHON_VERSION=3
        else
            SETV_PYTHON_VERSION=2
        fi
        SETV_PY_PATH=${1}
        _setv_create $2
    else
        echo "Error: Path ${1} does not exist!"
    fi
}
function _setv_create()
{
    # Creates new virtual environment if ran with -n|--new flag
    if [ -z ${1} ];
    then
        echo "You need to pass virtual environment name"
        _setv_help_
    else
        echo "Creating new virtual environment with the name: $1"
        if [ ${SETV_PYTHON_VERSION} -eq 3 ];
        then
            ${SETV_PY_PATH} -m venv ${SETV_VIRTUAL_DIR_PATH}${1}
        else
            virtualenv -p ${SETV_PY_PATH} ${SETV_VIRTUAL_DIR_PATH}${1}
        fi
        echo "You can now activate the Python virtual environment by typing: setv ${1}"
    fi
}
function _setv_delete()
{
    # Deletes virtual environment if ran with -d|--delete flag
    # TODO: Refactor
    if [ -z ${1} ];
    then
        echo "You need to pass virtual environment name"
        _setv_help_
    else
        if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
        then
            read -p "Really delete this virtual environment(Y/N)? " yes_no
            case $yes_no in
                Y|y) rm -rvf ${SETV_VIRTUAL_DIR_PATH}${1};;
                N|n) echo "Leaving the virtual environment as it is.";;
                *) echo "You need to enter either Y/y or N/n"
            esac
        else
            echo "Error: No virtual environment found by the name: ${1}"
        fi
    fi
}
function _setv_list()
{
    # Lists all virtual environments if ran with -l|--list flag
    echo -e "List of virtual environments you have under ${SETV_VIRTUAL_DIR_PATH}:\n"
    for virt in $(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}')
    do
        echo ${virt}
    done
}
function setv() {
    # Main function
    if [ $# -eq 0 ];
    then
        _setv_help_
    elif [ $# -le 3 ];
    then
        case "${1}" in
            -n|--new) _setv_create ${2};;
            -d|--delete) _setv_delete ${2};;
            -l|--list) _setv_list;;
            *) if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
               then
                   # Activate the virtual environment
                   source ${SETV_VIRTUAL_DIR_PATH}${1}/bin/activate
               else
                   # Else throw an error message
                   echo "Sorry, you don't have any virtual environment with the name: ${1}"
                   _setv_help_
               fi
               ;;
        esac
    elif [ $# -le 5 ];
    then
        case "${2}" in
            -p|--python) _setv_custom_python_path ${3} ${4};;
            *) _setv_help_;;
        esac
    fi
}
# Calls bash-complete. The compgen command accepts most of the same
# options that complete does but it generates results rather than just
# storing the rules for future use.
complete  -F _setvcomplete_ setv
```
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/setv-bash-function
作者:[Sachin Patil][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/psachin
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
[2]: https://gitlab.com/psachin/setV
[3]: https://github.com/psachin/bash_scripts
[4]: https://virtualenvwrapper.readthedocs.org/
[5]: https://gitlab.com/psachin/setV/blob/master/LICENSE
[6]: https://gitlab.com/psachin/setV/blob/master/ReadMe.org
[7]: mailto:iclcoolster@gmail.com

View File

@ -1,524 +0,0 @@
[#]: collector: (lujun9972)
[#]: translator: ( )
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (6 handy Bash scripts for Git)
[#]: via: (https://opensource.com/article/20/1/bash-scripts-git)
[#]: author: (Bob Peterson https://opensource.com/users/bobpeterson)
6 handy Bash scripts for Git
======
These six Bash scripts will make your life easier when you're working
with Git repositories.
![Digital hand surrounding by objects, bike, light bulb, graphs][1]
I wrote a bunch of Bash scripts that make my life easier when I'm working with Git repositories. Many of my colleagues say there's no need; that everything I need to do can be done with Git commands. While that may be true, I find the scripts infinitely more convenient than trying to figure out the appropriate Git command to do what I want.
### 1\. gitlog
**gitlog** prints an abbreviated list of current patches against the master version. It prints them from oldest to newest and shows the author and description, with **H** for **HEAD**, **^** for **HEAD^**, **2** for **HEAD~2,** and so forth. For example:
```
$ gitlog
\-----------------------[ recovery25 ]-----------------------
(snip)
11 340d27a33895 Bob Peterson     gfs2: drain the ail2 list after io errors
10 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
```
If I want to see what patches are on a different branch, I can specify an alternate branch:
```
`$ gitlog recovery24`
```
### 2\. gitlog.id
**gitlog.id** just prints the patch SHA1 IDs:
```
$ 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
```
Again, it assumes the current branch, but I can specify a different branch if I want.
### 3\. gitlog.id2
**gitlog.id2** is the same as **gitlog.id** but without the branch line at the top. This is handy for cherry-picking all patches from one branch to the current branch:
```
$ # create a new branch
$ git branch --track origin/master
$ # check out the new branch I just created
$ git checkout recovery26
$ # cherry-pick all patches from the old branch to the new one
$ for i in `gitlog.id2 recovery25` ; do git cherry-pick $i ;done
```
### 4\. gitlog.grep
**gitlog.grep** greps for a string within that collection of patches. For example, if I find a bug and want to fix the patch that has a reference to function **inode_go_sync**, I simply do:
```
$ gitlog.grep inode_go_sync
\-----------------------[ recovery25 - 50 patches ]-----------------------
(snip)
11 340d27a33895 Bob Peterson     gfs2: drain the ail2 list after io errors
10 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
152:-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
```
So, now I know that patch **HEAD~9** is the one that needs fixing. I use **git rebase -i HEAD~10** to edit patch 9, **git commit -a --amend**, then **git rebase --continue** to make the necessary adjustments.
### 5\. gitbranchcmp3
**gitbranchcmp3** lets me compare my current branch to another branch, so I can compare older versions of patches to my newer versions and quickly see what's changed and what hasn't. It generates a compare script (that uses the KDE tool [Kompare][2], which works on GNOME3, as well) to compare the patches that aren't quite the same. If there are no differences other than line numbers, it prints **[SAME]**. If there are only comment differences, it prints **[same]** (in lower case). For example:
```
$ gitbranchcmp3 recovery24
Branch recovery24 has 47 patches
Branch recovery25 has 50 patches
(snip)
38 87eb6901607a 340d27a33895 [same] gfs2: drain the ail2 list after io errors
39 90fefb577a26 9b3c4e6efb10 [same] gfs2: clean up iopen glock mess in gfs2_create_inode
40 ba3ae06b8b0e d2e8c22be39b [same] gfs2: Do proper error checking for go_sync family of glops
41 2ab662294329 9563e31f8bfd [SAME] gfs2: use page_offset in gfs2_page_mkwrite
42 0adc6d817b7a ebac7a38036c [SAME] gfs2: don't use buffer_heads in gfs2_allocate_page_backing
43 55ef1f8d0be8 f703a3c27874 [SAME] gfs2: Improve mmap write vs. punch_hole consistency
44 de57c2f72570 a3e86d2ef30e [SAME] gfs2: Multi-block allocations in gfs2_page_mkwrite
45 7c5305fbd68a da3c604755b0 [SAME] gfs2: Fix end-of-file handling in gfs2_page_mkwrite
46 162524005151 4525c2f5b46f [SAME] Rafael Aquini's slab instrumentation
47              a06a5b7dea02 [    ] GFS2: Add go_get_holdtime to gl_ops
48              8ba93c796d5c [    ] gfs2: introduce new function remaining_hold_time and use it in dq
49              e8b5ff851bb9 [    ] gfs2: Allow rgrps to have a minimum hold time
Missing from recovery25:
The missing:
Compare script generated at: /tmp/compare_mismatches.sh
```
### 6\. gitlog.find
Finally, I have **gitlog.find**, a script to help me identify where the upstream versions of my patches are and each patch's current status. It does this by matching the patch description. It also generates a compare script (again, using Kompare) to compare the current patch to the upstream counterpart:
```
$ gitlog.find
\-----------------------[ recovery25 - 50 patches ]-----------------------
(snip)
11 340d27a33895 Bob Peterson     gfs2: drain the ail2 list after io errors
lo 5bcb9be74b2a Bob Peterson     gfs2: drain the ail2 list after io errors
10 9b3c4e6efb10 Bob Peterson     gfs2: clean up iopen glock mess in gfs2_create_inode
fn 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 glops
lo 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_mkwrite
ms 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_backing
ms 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 consistency
fn 39c3a948ecf6 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
 5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
fn f53056c43063 Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
 4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
fn 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 upstream
Compare script generated: /tmp/compare_upstream.sh
```
The patches are shown on two lines, the first of which is your current patch, followed by the corresponding upstream patch, and a 2-character abbreviation to indicate its upstream status:
* **lo** means the patch is in the local upstream Git repo only (i.e., not pushed upstream yet).
* **ms** means the patch is in Linus Torvald's master branch.
* **fn** means the patch is pushed to my "for-next" development branch, intended for the next upstream merge window.
Some of my scripts make assumptions based on how I normally work with Git. For example, when searching for upstream patches, it uses my well-known Git tree's location. So, you will need to adjust or improve them to suit your conditions. The **gitlog.find** script is designed to locate [GFS2][3] and [DLM][4] patches only, so unless you're a GFS2 developer, you will want to customize it to the components that interest you.
### Source code
Here is the source for these scripts.
#### 1\. gitlog
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
    branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
patches=0
tracking=`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
if [[ $branch =~ .*for-next.* ]]
then
    start=HEAD
#    start=origin/for-next
else
    start=origin/master
fi
tracking=`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 %&lt;|(32)%an %s %n" $i
    patches=$(echo $patches - 1 | bc)
done
#git log --reverse --abbrev-commit --pretty=format:"%h %&lt;|(32)%an %s" $tracking..$branch
#git log --reverse --abbrev-commit --pretty=format:"%h %&lt;|(32)%an %s" ^origin/master ^linux-gfs2/for-next $branch
```
#### 2\. gitlog.id
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
    branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`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 ' '
```
#### 3\. gitlog.id2
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
    branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
```
#### 4\. gitlog.grep
```
#!/bin/bash
param1=$1
param2=$2
if test "x$param2" = x; then
    branch=`git branch -a | grep "*" | cut -d ' ' -f2`
    string=$param1
else
    branch=$param1
    string=$param2
fi
patches=0
tracking=`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 %&lt;|(32)%an %s" $i
    /usr/bin/git show --pretty=email --patch-with-stat $i | grep -n "$string"
    patches=$(echo $patches - 1 | bc)
done
```
#### 5\. gitbranchcmp3
```
#!/bin/bash
#
# gitbranchcmp3 &lt;old branch&gt; [&lt;new_branch&gt;]
#
oldbranch=$1
newbranch=$2
script=/tmp/compare_mismatches.sh
/usr/bin/rm -f $script
echo "#!/bin/bash" &gt; $script
/usr/bin/chmod 755 $script
echo "# Generated by gitbranchcmp3.sh" &gt;&gt; $script
echo "# Run this script to compare the mismatched patches" &gt;&gt; $script
echo " " &gt;&gt; $script
echo "function compare_them()" &gt;&gt; $script
echo "{"  &gt;&gt; $script
echo "    git show --pretty=email --patch-with-stat \$1 &gt; /tmp/gronk1" &gt;&gt; $script
echo "    git show --pretty=email --patch-with-stat \$2 &gt; /tmp/gronk2" &gt;&gt; $script
echo "    kompare /tmp/gronk1 /tmp/gronk2" &gt;&gt; $script
echo "}" &gt;&gt; $script
echo " " &gt;&gt; $script
if test "x$newbranch" = x; then
    newbranch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`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: " $oldsha1s
oldcount=${#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: " $newsha1s
newcount=${#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-`
#done
echo
for 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 "@@" &gt; /tmp/gronk1
            git show $newsha |tail -n +2 |grep -v "index.*\\.\\." |grep -v "@@"  &gt; /tmp/gronk2
            diff /tmp/gronk1 /tmp/gronk2 &amp;&gt; /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 "@@" &gt; /tmp/gronk1
            git show $newsha |sed -n '/diff/,$p' |grep -v "index.*\\.\\." |grep -v "@@" &gt; /tmp/gronk2
            diff /tmp/gronk1 /tmp/gronk2 &amp;&gt; /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" &gt;&gt; $script
        fi
    done
    echo "$new $oldsha $newsha $same $newdesc"
done
echo
echo "Missing from $newbranch:"
the_missing=""
# Now run through the olds we haven't matched up
for 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]}"`
    fi
done
echo "The missing: " $the_missing
echo "Compare script generated at: $script"
#git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
```
#### 6\. gitlog.find
```
#!/bin/bash
#
# Find the upstream equivalent patch
#
# gitlog.find
#
cwd=$PWD
param1=$1
ubranch=$2
patches=0
script=/tmp/compare_upstream.sh
echo "#!/bin/bash" &gt; $script
/usr/bin/chmod 755 $script
echo "# Generated by gitbranchcmp3.sh" &gt;&gt; $script
echo "# Run this script to compare the mismatched patches" &gt;&gt; $script
echo " " &gt;&gt; $script
echo "function compare_them()" &gt;&gt; $script
echo "{"  &gt;&gt; $script
echo "    cwd=$PWD" &gt;&gt; $script
echo "    git show --pretty=email --patch-with-stat \$2 &gt; /tmp/gronk2" &gt;&gt; $script
echo "    cd ~/linux.git/fs/gfs2" &gt;&gt; $script
echo "    git show --pretty=email --patch-with-stat \$1 &gt; /tmp/gronk1" &gt;&gt; $script
echo "    cd $cwd" &gt;&gt; $script
echo "    kompare /tmp/gronk1 /tmp/gronk2" &gt;&gt; $script
echo "}" &gt;&gt; $script
echo " " &gt;&gt; $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.git
if test "X${ubranch}" = "X"; then
    ubranch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
utracking=`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 %&lt;|(32)%an %s" master |grep -i -e "gfs2" -e "dlm" &gt; /tmp/gronk
git log --reverse --abbrev-commit --pretty=format:"ms %h %&lt;|(32)%an %s" master fs/gfs2/ &gt; /tmp/gronk.gfs2
# ms = in Linus's master
git log --reverse --abbrev-commit --pretty=format:"ms %h %&lt;|(32)%an %s" master fs/dlm/ &gt; /tmp/gronk.dlm
cd $cwd
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 %&lt;|(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 %&lt;|(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 %&lt;|(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" &gt;&gt; $script
    fi
    cd $cwd
    patches=$(echo $patches - 1 | bc)
done
echo "Compare script generated: $script"
```
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/bash-scripts-git
作者:[Bob Peterson][a]
选题:[lujun9972][b]
译者:[译者ID](https://github.com/译者ID)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/bobpeterson
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesk12_rh_021x_0.png?itok=fvorN0e- (Digital hand surrounding by objects, bike, light bulb, graphs)
[2]: https://kde.org/applications/development/org.kde.kompare
[3]: https://en.wikipedia.org/wiki/GFS2
[4]: https://en.wikipedia.org/wiki/Distributed_lock_manager

View File

@ -0,0 +1,296 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (setV: A Bash function to maintain Python virtual environments)
[#]: via: (https://opensource.com/article/20/1/setv-bash-function)
[#]: author: (Sachin Patil https://opensource.com/users/psachin)
setV一个管理 Python 虚拟环境的 Bash 函数
======
> 了解一下 setV它是轻量级的 Python 虚拟环境管理器,是 virtualenvwrapper 的替代产品。
![Coding on a computer][1]
这一年多来,[setV] [2] 悄悄隐藏在我的 [bash_scripts][3] 项目中但现在是时候该公开了。setV 是一个 Bash 函数,我可以用它代替 [virtualenvwrapper][4]。它提供了使你能够执行以下操作的基本功能:
* 默认使用 Python 3
* 创建一个新的虚拟环境
* 使用带有 `-p`(或 `--python`)的自定义 Python 路径来创建新的虚拟环境
* 删除现有的虚拟环境
* 列出所有现有的虚拟环境
* 使用制表符补全(以防你忘记虚拟环境名称)
### 安装
要安装 setV请下载该脚本
```
curl https://gitlab.com/psachin/setV/raw/master/install.sh
```
审核一下脚本,然后运行它:
```
sh ./install.sh
```
当安装 setV 时,安装脚本会询问你要嵌入到 `~/.bashrc` 还是 `~/.bash_profile`,根据你的喜好选择一个。
### 用法
基本的命令格式是 `setv`
#### 创建虚拟环境
```
setv --new rango  # setv -n rango
# 或使用定制的 Python 路径
setv --new --python /opt/python/python3 rango  # setv -n -p /opt/python/python3 rango
```
#### 激活已有的虚拟环境
```
setv VIRTUAL_ENVIRONMENT_NAME
```
```
# 示例
setv rango
```
#### 列出所有的虚拟环境
```
setv --list
# 或
setv [TAB] [TAB]
```
#### 删除虚拟环境
```
setv --delete rango
```
#### 切换到另外一个虚拟环境
```
# 假设你现在在 'rango',切换到 'tango'
setv tango
```
#### 制表符补完
如果你不完全记得虚拟环境的名称,则 Bash 式的制表符补全也可以适用于虚拟环境名称。
### 参与其中
setV 在 GNU [GPLv3][5]下开源,欢迎贡献。要了解更多信息,请访问它的 GitLab 存储库中的 setV 的 [README][6] 的贡献部分。
### setV 脚本
```
#!/usr/bin/env bash
# setV - A Lightweight Python virtual environment manager.
# Author: Sachin (psachin) <iclcoolster@gmail.com>
# Author's URL: https://psachin.gitlab.io/about
#
# License: GNU GPL v3, See LICENSE file
#
# Configure(Optional):
# Set `SETV_VIRTUAL_DIR_PATH` value to your virtual environments
# directory-path. By default it is set to '~/virtualenvs/'
#
# Usage:
# Manual install: Added below line to your .bashrc or any local rc script():
# ---
# source /path/to/virtual.sh
# ---
#
# Now you can 'activate' the virtual environment by typing
# $ setv <YOUR VIRTUAL ENVIRONMENT NAME>
#
# For example:
# $ setv rango
#
# or type:
# setv [TAB] [TAB] (to list all virtual envs)
#
# To list all your virtual environments:
# $ setv --list
#
# To create new virtual environment:
# $ setv --new new_virtualenv_name
#
# To delete existing virtual environment:
# $ setv --delete existing_virtualenv_name
#
# To deactivate, type:
# $ deactivate
# Path to virtual environment directory
SETV_VIRTUAL_DIR_PATH="$HOME/virtualenvs/"
# Default python version to use. This decides whether to use `virtualenv` or `python3 -m venv`
SETV_PYTHON_VERSION=3 # Defaults to Python3
SETV_PY_PATH=$(which python${SETV_PYTHON_VERSION})
function _setvcomplete_()
{
# Bash-autocompletion.
# This ensures Tab-auto-completions work for virtual environment names.
local cmd="${1##*/}" # to handle command(s).
# Not necessary as such. 'setv' is the only command
local word=${COMP_WORDS[COMP_CWORD]} # Words thats being completed
local xpat='${word}' # Filter pattern. Include
# only words in variable '$names'
local names=$(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}') # Virtual environment names
COMPREPLY=($(compgen -W "$names" -X "$xpat" -- "$word")) # compgen generates the results
}
function _setv_help_() {
# Echo help/usage message
echo "Usage: setv [OPTIONS] [NAME]"
echo Positional argument:
echo -e "NAME Activate virtual env."
echo Optional arguments:
echo -e "-l, --list List all Virtual Envs."
echo -e "-n, --new NAME Create a new Python Virtual Env."
echo -e "-d, --delete NAME Delete existing Python Virtual Env."
echo -e "-p, --python PATH Python binary path."
}
function _setv_custom_python_path()
{
if [ -f "${1}" ];
then
if [ "`expr $1 : '.*python\([2,3]\)'`" = "3" ];
then
SETV_PYTHON_VERSION=3
else
SETV_PYTHON_VERSION=2
fi
SETV_PY_PATH=${1}
_setv_create $2
else
echo "Error: Path ${1} does not exist!"
fi
}
function _setv_create()
{
# Creates new virtual environment if ran with -n|--new flag
if [ -z ${1} ];
then
echo "You need to pass virtual environment name"
_setv_help_
else
echo "Creating new virtual environment with the name: $1"
if [ ${SETV_PYTHON_VERSION} -eq 3 ];
then
${SETV_PY_PATH} -m venv ${SETV_VIRTUAL_DIR_PATH}${1}
else
virtualenv -p ${SETV_PY_PATH} ${SETV_VIRTUAL_DIR_PATH}${1}
fi
echo "You can now activate the Python virtual environment by typing: setv ${1}"
fi
}
function _setv_delete()
{
# Deletes virtual environment if ran with -d|--delete flag
# TODO: Refactor
if [ -z ${1} ];
then
echo "You need to pass virtual environment name"
_setv_help_
else
if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
then
read -p "Really delete this virtual environment(Y/N)? " yes_no
case $yes_no in
Y|y) rm -rvf ${SETV_VIRTUAL_DIR_PATH}${1};;
N|n) echo "Leaving the virtual environment as it is.";;
*) echo "You need to enter either Y/y or N/n"
esac
else
echo "Error: No virtual environment found by the name: ${1}"
fi
fi
}
function _setv_list()
{
# Lists all virtual environments if ran with -l|--list flag
echo -e "List of virtual environments you have under ${SETV_VIRTUAL_DIR_PATH}:\n"
for virt in $(ls -l "${SETV_VIRTUAL_DIR_PATH}" | egrep '^d' | awk -F " " '{print $NF}')
do
echo ${virt}
done
}
function setv() {
# Main function
if [ $# -eq 0 ];
then
_setv_help_
elif [ $# -le 3 ];
then
case "${1}" in
-n|--new) _setv_create ${2};;
-d|--delete) _setv_delete ${2};;
-l|--list) _setv_list;;
*) if [ -d ${SETV_VIRTUAL_DIR_PATH}${1} ];
then
# Activate the virtual environment
source ${SETV_VIRTUAL_DIR_PATH}${1}/bin/activate
else
# Else throw an error message
echo "Sorry, you don't have any virtual environment with the name: ${1}"
_setv_help_
fi
;;
esac
elif [ $# -le 5 ];
then
case "${2}" in
-p|--python) _setv_custom_python_path ${3} ${4};;
*) _setv_help_;;
esac
fi
}
# Calls bash-complete. The compgen command accepts most of the same
# options that complete does but it generates results rather than just
# storing the rules for future use.
complete -F _setvcomplete_ setv
```
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/setv-bash-function
作者:[Sachin Patil][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/psachin
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/code_computer_laptop_hack_work.png?itok=aSpcWkcl (Coding on a computer)
[2]: https://gitlab.com/psachin/setV
[3]: https://github.com/psachin/bash_scripts
[4]: https://virtualenvwrapper.readthedocs.org/
[5]: https://gitlab.com/psachin/setV/blob/master/LICENSE
[6]: https://gitlab.com/psachin/setV/blob/master/ReadMe.org
[7]: mailto:iclcoolster@gmail.com

View File

@ -0,0 +1,510 @@
[#]: collector: (lujun9972)
[#]: translator: (wxy)
[#]: reviewer: ( )
[#]: publisher: ( )
[#]: url: ( )
[#]: subject: (6 handy Bash scripts for Git)
[#]: via: (https://opensource.com/article/20/1/bash-scripts-git)
[#]: author: (Bob Peterson https://opensource.com/users/bobpeterson)
6 个方便的 Git 脚本
======
> 当使用 Git 存储库时,这六个 Bash 脚本将使你的生活更轻松。
![Digital hand surrounding by objects, bike, light bulb, graphs][1]
我编写了许多 Bash 脚本,这些脚本使我在使用 Git 存储库时工作更加轻松。我的许多同事说没有必要;我所做的一切都可以用 Git 命令完成。虽然这可能是正确的,但我发现脚本远比尝试找出适当的 Git 命令来执行我想要的操作更加方便。
### 1、gitlog
`gitlog` 打印针对 master 分支的当前补丁的简短列表。它从最旧到最新打印它们,并显示作者和描述,其中 `H` 代表 `HEAD``^` 代表 `HEAD^``2` 代表 `HEAD~2`,依此类推。例如:
```
$ gitlog
-----------------------[ recovery25 ]-----------------------
(snip)
11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors
10 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
```
### 2、gitlog.id
`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
```
同样,它假定是当前分支,但是如果需要,我可以指定其他分支。
### 3、gitlog.id2
`gitlog.id2``gitlog.id` 相同,但顶部没有显示分支的行。这对于从一个分支挑选所有补丁到当前分支很方便:
```
$ # 创建一个新分支
$ git branch --track origin/master
$ # 检出刚刚创建的新分支
$ git checkout recovery26
$ # 从旧的分支挑选所有补丁到新分支
$ for i in `gitlog.id2 recovery25` ; do git cherry-pick $i ;done
```
### 4、gitlog.grep
`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 errors
10 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
152:-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` 以进行必要的调整。
### 5、gitbranchcmp3
`gitbranchcmp3` 使我可以将当前分支与另一个分支进行比较,因此我可以将较旧版本的补丁与我的较新版本进行比较,并快速查看已更改和未更改的内容。它生成一个比较脚本(使用了 KDE 工具 [Kompare][2],该工具也可在 GNOME3 上使用)以比较不太相同的补丁。如果除行号外没有其他差异,则打印 `[SAME]`。如果仅存在注释差异,则打印 `[same]`(小写)。例如:
```
$ gitbranchcmp3 recovery24
Branch recovery24 has 47 patches
Branch recovery25 has 50 patches
(snip)
38 87eb6901607a 340d27a33895 [same] gfs2: drain the ail2 list after io errors
39 90fefb577a26 9b3c4e6efb10 [same] gfs2: clean up iopen glock mess in gfs2_create_inode
40 ba3ae06b8b0e d2e8c22be39b [same] gfs2: Do proper error checking for go_sync family of glops
41 2ab662294329 9563e31f8bfd [SAME] gfs2: use page_offset in gfs2_page_mkwrite
42 0adc6d817b7a ebac7a38036c [SAME] gfs2: don't use buffer_heads in gfs2_allocate_page_backing
43 55ef1f8d0be8 f703a3c27874 [SAME] gfs2: Improve mmap write vs. punch_hole consistency
44 de57c2f72570 a3e86d2ef30e [SAME] gfs2: Multi-block allocations in gfs2_page_mkwrite
45 7c5305fbd68a da3c604755b0 [SAME] gfs2: Fix end-of-file handling in gfs2_page_mkwrite
46 162524005151 4525c2f5b46f [SAME] Rafael Aquini's slab instrumentation
47 a06a5b7dea02 [ ] GFS2: Add go_get_holdtime to gl_ops
48 8ba93c796d5c [ ] gfs2: introduce new function remaining_hold_time and use it in dq
49 e8b5ff851bb9 [ ] gfs2: Allow rgrps to have a minimum hold time
Missing from recovery25:
The missing:
Compare script generated at: /tmp/compare_mismatches.sh
```
### 6、gitlog.find
最后,我有一个 `gitlog.find` 脚本,可以帮助我识别补丁程序的上游版本在哪里以及每个补丁程序的当前状态。它通过匹配补丁说明来实现。它还会生成一个比较脚本(再次使用了 Kompare以将当前补丁与上游对应补丁进行比较
```
$ gitlog.find
-----------------------[ recovery25 - 50 patches ]-----------------------
(snip)
11 340d27a33895 Bob Peterson gfs2: drain the ail2 list after io errors
lo 5bcb9be74b2a Bob Peterson gfs2: drain the ail2 list after io errors
10 9b3c4e6efb10 Bob Peterson gfs2: clean up iopen glock mess in gfs2_create_inode
fn 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 glops
lo 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_mkwrite
ms 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_backing
ms 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 consistency
fn 39c3a948ecf6 Andreas Gruenbacher gfs2: Improve mmap write vs. punch_hole consistency
5 a3e86d2ef30e Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
fn f53056c43063 Andreas Gruenbacher gfs2: Multi-block allocations in gfs2_page_mkwrite
4 da3c604755b0 Andreas Gruenbacher gfs2: Fix end-of-file handling in gfs2_page_mkwrite
fn 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 upstream
Compare script generated: /tmp/compare_upstream.sh
```
补丁显示为两行,第一行是你当前的修补程序,然后是相应的上游补丁,以及 2 个字符的缩写,以指示其上游状态:
* `lo` 表示补丁仅在本地(`local`)上游 Git 存储库中(即尚未推送到上游)。
* `ms` 表示补丁位于 Linus Torvald 的主(`master`)分支中。
* `fn` 意味着补丁被推送到我的 “for-next” 开发分支,用于下一个上游合并窗口。
  
我的一些脚本根据我通常使用 Git 的方式做出假设。例如,当搜索上游补丁时,它使用我众所周知的 Git 树的位置。因此,你需要调整或改进它们以适合你的条件。`gitlog.find` 脚本旨在仅定位 [GFS2][3] 和 [DLM][4] 补丁,因此,除非你是 GFS2 开发人员,否则你需要针对你感兴趣的组件对其进行自定义。
### 源代码
以下是这些脚本的源代码。
#### 1、gitlog
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
patches=0
tracking=`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
if [[ $branch =~ .*for-next.* ]]
then
start=HEAD
# start=origin/for-next
else
start=origin/master
fi
tracking=`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
```
#### 2、gitlog.id
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`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 ' '
```
#### 3、gitlog.id2
```
#!/bin/bash
branch=$1
if test "x$branch" = x; then
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`git rev-parse --abbrev-ref --symbolic-full-name @{u}`
git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
```
#### 4、gitlog.grep
```
#!/bin/bash
param1=$1
param2=$2
if test "x$param2" = x; then
branch=`git branch -a | grep "*" | cut -d ' ' -f2`
string=$param1
else
branch=$param1
string=$param2
fi
patches=0
tracking=`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
```
#### 5、gitbranchcmp3
```
#!/bin/bash
#
# gitbranchcmp3 <old branch> [<new_branch>]
#
oldbranch=$1
newbranch=$2
script=/tmp/compare_mismatches.sh
/usr/bin/rm -f $script
echo "#!/bin/bash" > $script
/usr/bin/chmod 755 $script
echo "# Generated by gitbranchcmp3.sh" >> $script
echo "# Run this script to compare the mismatched patches" >> $script
echo " " >> $script
echo "function compare_them()" >> $script
echo "{" >> $script
echo " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $script
echo " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $script
echo " kompare /tmp/gronk1 /tmp/gronk2" >> $script
echo "}" >> $script
echo " " >> $script
if test "x$newbranch" = x; then
newbranch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
tracking=`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: " $oldsha1s
oldcount=${#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: " $newsha1s
newcount=${#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-`
#done
echo
for 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"
done
echo
echo "Missing from $newbranch:"
the_missing=""
# Now run through the olds we haven't matched up
for 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]}"`
fi
done
echo "The missing: " $the_missing
echo "Compare script generated at: $script"
#git log --reverse --abbrev-commit --pretty=oneline $tracking..$branch | cut -d ' ' -f1 |paste -s -d ' '
```
#### 6、gitlog.find
```
#!/bin/bash
#
# Find the upstream equivalent patch
#
# gitlog.find
#
cwd=$PWD
param1=$1
ubranch=$2
patches=0
script=/tmp/compare_upstream.sh
echo "#!/bin/bash" > $script
/usr/bin/chmod 755 $script
echo "# Generated by gitbranchcmp3.sh" >> $script
echo "# Run this script to compare the mismatched patches" >> $script
echo " " >> $script
echo "function compare_them()" >> $script
echo "{" >> $script
echo " cwd=$PWD" >> $script
echo " git show --pretty=email --patch-with-stat \$2 > /tmp/gronk2" >> $script
echo " cd ~/linux.git/fs/gfs2" >> $script
echo " git show --pretty=email --patch-with-stat \$1 > /tmp/gronk1" >> $script
echo " cd $cwd" >> $script
echo " kompare /tmp/gronk1 /tmp/gronk2" >> $script
echo "}" >> $script
echo " " >> $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.git
if test "X${ubranch}" = "X"; then
ubranch=`git branch -a | grep "*" | cut -d ' ' -f2`
fi
utracking=`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/gronk
git log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/gfs2/ > /tmp/gronk.gfs2
# ms = in Linus's master
git log --reverse --abbrev-commit --pretty=format:"ms %h %<|(32)%an %s" master fs/dlm/ > /tmp/gronk.dlm
cd $cwd
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
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)
done
echo "Compare script generated: $script"
```
--------------------------------------------------------------------------------
via: https://opensource.com/article/20/1/bash-scripts-git
作者:[Bob Peterson][a]
选题:[lujun9972][b]
译者:[wxy](https://github.com/wxy)
校对:[校对者ID](https://github.com/校对者ID)
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
[a]: https://opensource.com/users/bobpeterson
[b]: https://github.com/lujun9972
[1]: https://opensource.com/sites/default/files/styles/image-full-size/public/lead-images/rh_003588_01_rd3os.combacktoschoolseriesk12_rh_021x_0.png?itok=fvorN0e- (Digital hand surrounding by objects, bike, light bulb, graphs)
[2]: https://kde.org/applications/development/org.kde.kompare
[3]: https://en.wikipedia.org/wiki/GFS2
[4]: https://en.wikipedia.org/wiki/Distributed_lock_manager