3

I want to view the diff of only two commits.

For instance

$ git log --oneline
0ff4567 fix bug #1, now really really really
1ff4567 fix bug #1 really
2ff4567 fix bug #2
3ff4567 fix bug #3
4234567 refactor code
5ff4567 fix bug #1
6234567 fix bug #4

I want to view only the commits relevant to bug #1, that is, commits 0ff4567,1ff4567,5ff4567.

I don't care about the diffs of the rest of the commits.

Is there an easy way to do that?

Update: I know the list of relevant commits. Given this list, I want to get a single diff, which is easier to review.

Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169

2 Answers2

2

You can use the --grep option to git log, which only outputs commits with log messages that match a particular regular expression. In your case you could do:

git log --oneline --grep='bug #1'

... if you want to see the patches introduced by each of those commits, of course, you should do:

git log -p --grep='bug #1'

In the comments below, you explain that you really want one patch as output, which represents the cumulative effect of the patches introduce by those three commits. In that case, you could try one of the following:

  • Using the combinediff tool from patchutils to combine the diffs. (This may not work, depending on what the intermediate commits have changed.)
  • Create a temporary new branch, and use interactive rebase (possibly with a cunningly constructed command in the GIT_EDITOR environment variable) to reorder and squash the commits.

To expand a bit on the latter option, this script is based on a ("super-kludgy") example by Jefromi:

#!/bin/sh

set -e

if [ $# -ne 2 ]
then
    echo "Usage: $0 REGEX TEMPORARY_BRANCH_NAME"
    exit 1
fi

REGEX="$1"
BRANCH_NAME="$2"

git checkout -b "$BRANCH_NAME"

FIRST_COMMIT=$(git log --grep="$REGEX" --pretty=format:%H | tail -1)
if [ -z "$FIRST_COMMIT" ]
then
    echo "No commits matched '$REGEX'"
    exit 2
fi

export GIT_EDITOR="f() { if [ \"\$(basename \$1)\" = \"git-rebase-todo\" ]; then sed -i -n '/${REGEX}/p' \$1 && sed -i '2,\$s/pick/squash/' \$1; else vim $1; fi }; f"
git rebase -i ${FIRST_COMMIT}^

... which you might invoke as:

squash-matching-commits 'bug #1' tmp-branch

... which will then create the branch tmp-branch, rebase back to the parent of the first commit that matches bug #1, only picking commits that match bug #1 and squash all but the first one. (You may have to fix some conflicts, and provide a commit message for the squashed commits.) If that succeeds, then you can just do:

git show

... to see the combined patch. I don't seriously recommend anyone use this script, but it's a fun and hacky way of doing what you want, I think :)

Community
  • 1
  • 1
Mark Longair
  • 446,582
  • 72
  • 411
  • 327
1

You could use git log --grep=fix1 (as show in Git reference) in order to isolate the relevant commit, and then perform a git show <commit> for each commit.

See "Shorthand for diff of git commit with its parent?".

Combining those patches as a single diff isn't trivial, as Jefromi explains in "git diff with author filter".

The problem here is that you can't do this in the general case.
Suppose Alice changes a particular file, then Bob changes it - including parts that Alice changed - and finally Alice changes it again.
How do you combine Alice's two diffs into a single diff?
If you take them as two patches, the second simply won't apply without Bob's patch being applied first!
But you also can't simply diff the final state against the original, because that will include Bob's changes.

In your case, a possible (quite cumbersome) solution should be similar to "Extract relevant changes for code review":

Check out a working copy at a revision just before the first changes. Then merge all related commits into your working copy.
Now you have a working copy which differs from its base just by the relevant changes. You can review this directly, or create a patch from it for review.

So: a dedicated fix1_review branch is possible, but that remains a semi-automated setup (as you have to solve possible conflicts).

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • @Elazar has already identified the commits. It's a combined diff / patch that's required. – johnsyweb Oct 23 '11 at 08:44
  • @Johnsyweb: I just addressed that in a recent edit of my answer. – VonC Oct 23 '11 at 08:45
  • I read your answer after the edit, and it still seems wrong. I need to review everything with `meld`, and think if there's a problem with that. `grep`ing is irrelevant. I have the exact list of commits I'm interested with. – Elazar Leibovich Oct 23 '11 at 08:48
  • @Elzar: but you can't always combine those diffs together, except if they are *consecutive* commits. – VonC Oct 23 '11 at 08:49
  • @ElazarLeibovich: I have added the most robust solution I could find: a dedicated branch for reviewing all fix1 changes. – VonC Oct 23 '11 at 08:55
  • @VonC, I sometimes can. Fail if you can't, in 99% of the cases I can identify that those changes are independent. – Elazar Leibovich Oct 23 '11 at 08:56
  • @VonC new temporary reordered branch is what I had in mind. Thanks – Elazar Leibovich Oct 23 '11 at 08:57
  • @ElazarLeibovich: yes, this is a similar solution, and you will have to deal with potential conflict just the same. – VonC Oct 23 '11 at 08:58