Lumi
Lumi

Reputation: 15314

Git: How to find all commits in branch A that originated in derived branch B merged back into A?

In Git, given (1) a branch A and (2) a branch B derived from A at some point in the past and then merged back into A, how can I find all the commits now in A that originated in B?

The intent is to identify the changeset of work performed in B now in A to more quickly track down issues.

A squash commit would obviously and conveniently pack the entire changeset in one commit for easy reference, but the drawbacks (such as loss of information and individual attributability) make this option undesirable for us. Hence my question.

Upvotes: 4

Views: 630

Answers (3)

Jakub Narębski
Jakub Narębski

Reputation: 324012

Take a look at git-resurrect.sh script in contrib/ area of git sources.

usage: git resurrect [-a] [-r] [-m] [-t] [-n] [-b <newname>] <name>

    -b, --branch ...      save branch as  instead of <name>
    -a, --all             same as -l -r -m -t
    -k, --keep-going      full rev-list scan (instead of first match)
    -l, --reflog          scan reflog for checkouts (enabled by default)
    -r, --reflog-merges   scan for merges recorded in reflog
    -m, --merges          scan for merges into other branches (slow)
    -t, --merge-targets   scan for merges of other branches into 
    -n, --dry-run         don't recreate the branch

git-resurrect attempts to find traces of a branch tip called <name>,
and tries to resurrect it.  Currently, the reflog is searched for checkout
messages, and with `-r' also merge messages.  With `-m' and `-t', the
history of all refs is scanned for "Merge <name> into other" /
"Merge <other> into <name>" (respectively) in commit subjects,
which is rather slow but allows you to resurrect other people's
topic branches.

Upvotes: 1

Tim Henigan
Tim Henigan

Reputation: 62238

Assuming that B was fully merged into A, you can use:

git cherry -v <merge-commit>^ <topic-branch>

...where:

  • <merge-commit>^ is the parent of the commit where you merged the topic branch.
  • <topic-branch> is the branch that you want to check

Upvotes: 5

Cascabel
Cascabel

Reputation: 497752

Once a branch has been merged back in, the merge commit is the marker of its existence. Assuming you don't monkey around too much with your merge commit messages, you could do something like this:

#!/bin/bash

die_with_usage() {
    # add a git alias for merged-commits to be able to call it like this
    echo "usage: git merged-commits <branch-merged> <branch-merged-into>" 1>&2
    exit 1
}

if [ $# -ne 2 ]; then
    die_with_usage
fi

# Find the merge commits
merges=($(git log --pretty=%H --grep="Merge branch '$1' into $2"))

if [ ${#merges[@]} -eq 0 ]; then
    echo "error: no such merges found!" 1>&2
    die_with_usage
fi

for merge in ${merges[@]}; do
    # The first parent is the merged-into branch
    bar=$merge^1
    # The second is the merged branch
    foo=$merge^2

    # Find the merge base
    base=$(git merge-base $bar $foo)

    # Show the commits
    git log --pretty=%H $base..$foo
done

I figured it'd be helpful to just print the SHA1s and let you go off and do what you like with them afterward, but of course you can fiddle with the output format of that last git log.

(And I even tested this! Might keep it around; it's a cool little few-liner.)

Another thing you can do (in the future) is adopt a merge commit message along the lines of git.git, which essentially embeds the shortlog of the merged commits in the merged commit message (here's an example). There's a built-in way to do this coming someday (it's been merged to next but not master) but for now you'd have to roll your own, or make a gutsy move and build from next.

Upvotes: 1

Related Questions