Search code examples
gitversion-controlrepository

git log --grep: search in the range from HEAD to the last (arbitrary) branch name


I'm currently using Git as part of a tool in which I need to mark some Git repository changes. Therefore, I create some "marker commits". Now, I want to know how to efficiently find those commits.

The Git repositories all have a specific structure. I want to describe it on a concrete example:

Consider an arbitrary (big) repository with a detached HEAD that always has a linear chain up to an arbitrary next branch name. A git log --oneline on that repository would look like:

9b6eea6063ae (HEAD) foo
51206b9c09db bar
8ec634b9e864 baz
...
2fba8a89a6ee marker123
75a8e54af67e (some_branch) ipsum
...

I now want to find whether there exist a commit with the name marker123 on the path to the last branch.

With git log --grep marker123 --format=oneline --max-count=1 | grep ., I found a command that searches for that name and returns no error, when the commit exists and an error, when it not exists. However, if no commit marker123 exists, it searches the whole history. Can I restrict the search of git log to the range between HEAD and some_branch? My main problem is that I do not know the name of some_branch in advance. I only know that it is somewhere on the linear chain of back commits and is a branch name. Especially, I do not know how to define a commit range for git log.

Side note: I know this behavior a little bit from git rebase -i without an additional specification of the target commit. It also does a rebase starting from the last (remote?) branch then.

Here is a script to setup two repositories and demonstrate the problem:

#!/bin/sh

echo "Setup a repository, where the search works."
mkdir git-test; cd git-test
git init --initial-branch=random_name
git commit --allow-empty -m "marker123"
git tag "This-commit-never-ever-should-be-found"
git commit --allow-empty -m "ipsum"
git checkout --detach HEAD
git commit --allow-empty -m "marker123"
git commit --allow-empty -m "baz"
git commit --allow-empty -m "bar"
git commit --allow-empty -m "foo"

git log --oneline # situation of the example
echo -e "\nSearch for marker:"
git log --grep "marker123" --oneline -1 | grep .
echo "Errorcode $?"

cd ..

echo "Setup a repository, where the search does not work."
mkdir git-test2; cd git-test2
git init --initial-branch=random_name
git commit --allow-empty -m "marker123"
git tag "This-commit-never-ever-should-be-found"
git commit --allow-empty -m "ipsum"
git checkout --detach HEAD
# git commit --allow-empty -m "marker123" # this commit is missing here
git commit --allow-empty -m "baz"
git commit --allow-empty -m "bar"
git commit --allow-empty -m "foo"

git log --oneline # situation of the example
echo -e "\nSearch for marker:"
git log --grep "marker123" --oneline -1 | grep . # this should result in an error
echo "Errorcode $?"
git log --grep "marker123" --oneline -1 "random_name..HEAD" | grep . # this works here but only if random_name is known
echo "Errorcode $?"

cd ..

Solution

  • You can :

    • list the branches that do not contain HEAD:
    git branch --no-contains HEAD
    
    • use that list in a git log HEAD --not [list of branches ...] command:
    git log --oneline HEAD --not $(git branch --no-contains HEAD)
    

    If the above command gives you the history you expect, you can add whatever options you see fit to git log:

    git log --grep marker123 -1 --oneline HEAD --not $(git branch --no-contains HEAD)