Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash function to find all Git commits in which a file (whose name matches a regex) has *changed*

Tags:

git

bash

I have the following bash function, which searches for all files in a repository, whose filename matches a regular expression. It currently finds all commits in which a file exists. How can this be changed so it only searches among files that were edited (created, altered, or deleted) in each commit?

This was my original intention for the function. I was surprised to see the results being much broader than expected. The reason I'm trying to do this: I created a file a long time ago, and at some point between now and then, I accidentally deleted an important section from it. I want a list of all the points (commits) at which this file has changed, so I can quickly go back to the version containing the missing section, and paste it back into the current-commmit version.

:<<COMMENT
    Searches all commits in the current git repository containing a file whose name matches a regular expression.

    Usage: gitf <regex>

    Parameter is required, and must be at least one non-whitespace character.

    The original version of this function was based on the GitHub gist
    - https://gist.github.com/anonymous/62d981890eccb48a99dc
    written by Stack Overflow user Handyman5
    - https://stackoverflow.com/users/459089/handyman5
    which is based on this SO question:
    - https://stackoverflow.com/questions/372506/how-can-i-search-git-branches-for-a-file-or-directory/372654#372654

    The main section of this function was authored by Stack Overflow user
    SwankSwashbucklers.
    - https://stackoverflow.com/users/2615252/swankswashbucklers
    - https://stackoverflow.com/a/28095750/2736496

    Short description: Stored in GITF_DESC
COMMENT
#GITF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
GITF_DESC="gitf [searchterm]: Searches the current git repository for the file name that matches a regular expression.\n"

Body:

gitf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    wasFound="0";
    LOC=refs/remotes/origin # to search local branches only: 'refs/heads'
    ref="%(refname)"
    for branch in `git for-each-ref --format="$ref" $LOC`; do
        for commit in `git rev-list $branch | grep -oP ^.\{7\}`; do
            found=$(git ls-tree -r --name-only $commit | grep "$param")
            if [ $? -eq 0 ]; then
                echo "${branch#$LOC/}: $commit:"
                while read line; do
                    echo "  $line"
                done < <(echo "$found")
                wasFound="1";
            fi
        done
    done

    if [ "$wasFound" -eq "0" ]; then
        echo "No files in this repository match '$param'."
    fi
}
like image 566
aliteralmind Avatar asked Jan 23 '15 21:01

aliteralmind


People also ask

How do you check all commits of a file in git?

Use git log --all <filename> to view the commits influencing <filename> in all branches.

How do I see commits in git bash?

If you want to see what's happened recently in your project, you can use git log . This command will output a list of the latest commits in chronological order, with the latest commit first.

How do I see all commits?

Locally, you can use git log . The git log command enables you to display a list of all of the commits on your current branch. By default, the git log command presents a lot of information all at once.

What is the git command to view all the changes since the last commit?

By default git diff will show you any uncommitted changes since the last commit.


1 Answers

If you can live with a shell glob pattern rather than a full-blown regex, consider

git log -p --diff-filter=AMD --branches --tags -- "foo*bar.sh"

With -p, you see the deltas along with the commit message, author, SHA1, etc. The --diff-filter=AMD option selects only those commits in which the files in question were Added, Modified, or Deleted. To search remotes as well as local branches and tags, use --all rather than --branches --tags. Finally, note the -- that introduces path patterns, which you will want to quote to allow git to perform glob matching.

like image 60
Greg Bacon Avatar answered Oct 04 '22 03:10

Greg Bacon