Showing the "squashed diff" of multiple commits

Viewed 77

I'm looking for a shell script which displays the total/squashed diff of selected commits ($SELECTED_COMMITS) belonging to the same branch.

Background: My team is working on a rather long-living feature branch containing hundreds of commits related to dozens of tickets, in no specific order. Each commit message is prefixed by the respective ticket number (PROJECT-XXXXX). Now I would like to review the changes introduced by all the commits belonging to a specific ticket and, to this end, look at the total/squashed diff of all these $SELECTED_COMMITS. I do not want this diff to contain any changes introduced by unrelated commits in between the ones I'm interested in.

Requirements: Needless to say, unrelated commits in between the $SELECTED_COMMITS might potentially have changed the same files as $SELECTED_COMMITS and therefore cause conflicts when being "omitted" from history – in this case the command should simply fail (exit 1) and print an appropiate error messages.

Ideally, the shell script should be a single shell command accepting a list of commit hashes, so that I could set it as git alias. Also, the shell script should neither modify the working tree nor the git repository. That is, all files on disk (whether in .git or the working tree) should be treated as read-only.

The following commands do what I want, except that they modify the working directory and they also leave the repo in an undesirable state in case of conflicts:

git checkout <parent of first relevant commit>
git cherry-pick -n <all relevant commits>
git diff
git checkout <original branch>  # Reset once I'm done looking at the diff

Another way of achieving what I want (short of not modifying the git repo and handling conflicts) would be to create a temporary copy of the branch in question, do an interactive rebase where I move all commits I'm interested in in such a way that they are direct successors of one another and then, afterwards, run git diff <parent of first relevant commit> <last relevant commit> (and, finally, git checkout <original branch> && git branch -d <temporary branch> to reset everything).

Can anyone think of a way to achieve what I want? Thanks so much for your help!

1 Answers

If your only issue is to avoid breaking your index or worktree :

git worktree will allow you to have a fresh index and worktree, separate from the main one :

# will create a worktree at '/tmp/checkXXX', on your current commit,
# in 'detached HEAD' state, and a separate index file
git worktree add /tmp/checkXXX HEAD

Changing files or creating merge conflicts from within /tmp/checkXXX will not alter your initial clone.


Once you are done with that particular worktree, you can remove it :

git worktree remove /tmp/checkXXX

To list existing worktrees, run :

git worktree list
Related