In a `git merge`-style workflow, show only the unique commits someone had in their PR's (Pull Request's) feature branch before merging
Asked Answered
E

1

0

I'm working in a code base with a merge-style workflow which uses Bitbucket, GitHub, or Gitlab for pull requests (PRs).

I'd like to see the "right-parent" commits only, or something akin to a git log --second-parent output, if such a command existed.

On branch main, how can I see the following?:

  1. a graphical depiction of the forking and merging of the commits in the branch,
  2. a list of only the "primary" commits--ie: the merge commits to main via a PR (Pull Request), or commits committed directly to main without a merge PR (assuming the person had sufficient privileges and the branch wasn't protected), and
  3. [most important!] a list of just the unique commits in someone's PR for any given merge commit

Example of branch main:

*   commit4 (merge commit to `main`, via a PR)
|\  
| * featureCommit2
| * featureCommit1   
|/   
*   commit3
*   commit2
*   commit1 (initial commit)
  1. For 1. I'd like to see something like the drawing above.

  2. For 2. I'd like to see this:

    * commit4 (merge commit to `main`, via a PR)
    * commit3
    * commit2
    * commit1 (initial commit)
    
  3. For 3. I'd like to see this:

    * featureCommit2
    * featureCommit1   
    

    ...or maybe this too, so I can see the merge commit itself, too:

    * commit4
    * featureCommit2
    * featureCommit1   
    
Epicene answered 7/12, 2023 at 3:2 Comment(0)
E
0

I've added some additional markers for commit4^2 and commit4~ in the commit graph here to make my answer more clear:

*   commit4 (merge commit to `main`, via a PR)
|\  
| * featureCommit2 (`commit4^2`, ie: the feature branch the person 
| |                 was working on for the PR)
| * featureCommit1   
|/   
*   commit3 (`commit4~`, ie: branch `main` before the PR above merged in)
*   commit2
*   commit1 (initial commit)

1. graphical depiction of a branch, showing forking and merges

Use git lg, an alias from Coderwall.com: https://coderwall.com/p/euwpig/a-better-git-log

# Add it as an alias
git config --global alias.lg \
    "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

# Use it
git lg

2. List of only the "primary" commits

Use:

git lg --first-parent   # single-line log version
git log --first-parent  # full-log version

Either of the commands just above will produce more output information than shown here, but here is the gist of which commits will be output in the example from the question:

* commit4 (merge commit to `main`, via a PR)
* commit3
* commit2
* commit1 (initial commit)

This is from my Q&A here: How to view a linear git log (exclude feature commits), showing only commits to main or merges to main, thanks to @larsks's answer here.

3. A list of just the new/unique commits in someone's PR for any given merge commit

This is essentially the opposite as 2. above, and took me quite some time to think about and figure out.

Use this:

# Show everything in commit4's right parent (the feature branch), 
# but NOT in its left parent (branch `main` before the merge)
git lg ^commit4~ commit4^2  

# Show everything in commit4 (the merge commit created by the PR merging, 
# plus the feature branch that was merged), but NOT in its left parent 
# (branch `main` before the merge)
git lg ^commit4~ commit4

In a real example, you would use the full or short commit hashes instead of the word commit4 above. So, it might look like this, for example:

git lg ^a1b2c3d~ a1b2c3d^2
# or
git lg ^a1b2c3d~ a1b2c3d

More specifically:

  1. This:

    git lg ^commit4~ commit4^2
    

    ...produces this:

    * featureCommit2
    * featureCommit1   
    
  2. And this:

    git lg ^commit4~ commit4
    

    ...produces this:

    * commit4
    * featureCommit2
    * featureCommit1   
    

You might think of this as showing only the "right-hand parent" or "right-parent" commits, or as a type of git log --second-parent (which doesn't exist) command.

If you go online on GitHub, Bitbucket, or Gitlab to the PR which made commit4, you'll see that it shows only these commits, either commit4 plus featureCommit2 and featureCommit1, or just featureCommit2 and featureCommit1, depending on the online system you are using.

Explanation

As I first wrote in my answer here: How to cherry-pick a single commit, multiple commits, or a range of commits:

  1. commit^2 is the immediate right parent of the two parents involved in the merge which created commit. In this case, this would be the branch of feature commits that the person who opened the PR was working on before merging their PR.
  2. And commit~ is the immediate left parent of the two parents involved in the merge which created commit. In this case, this would be the main branch as it was before this PR was merged into main.

The carat (^) symbol in front of a commit means "not" that commit, or to "exclude" that commit.

So:

  1. commit4 means "commit4",
  2. commit4~ means "one commit before commit4", AKA: "commit4's left parent" (if commit4 is a merge commit), and otherwise just "commit4's only parent".
  3. ^commit4~ means "not in commit4's left parent", and
  4. commit4^2 means "in commit4's right parent".

So:

  1. git lg ^commit4~ commit4^2 means "show me all commits which are in commit4's right parent (ie: excluding commit4 itself), but not in commit4's left parent". This includes all ancestor commits before the specified commit, too, all the way back in time, just as though you had specified a branch instead of a commit hash. And:
  2. git lg ^commit4~ commit4 means "show me all commits which are in or under commit4 (including commit4 itself), but not in commit4's left parent". Again, this includes all ancestor commits before the specified commit, too, all the way back in time, just as though you had specified a branch instead of a commit hash.
Epicene answered 7/12, 2023 at 3:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.