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?:
- a graphical depiction of the forking and merging of the commits in the branch,
- a list of only the "primary" commits--ie: the merge commits to
mainvia a PR (Pull Request), or commits committed directly tomainwithout a merge PR (assuming the person had sufficient privileges and the branch wasn't protected), and - [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)
For 1. I'd like to see something like the drawing above.
For 2. I'd like to see this:
* commit4 (merge commit to `main`, via a PR) * commit3 * commit2 * commit1 (initial commit)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
I've added some additional markers for
commit4^2andcommit4~in the commit graph here to make my answer more clear: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-log2. List of only the "primary" commits
Use:
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:
This is from my Q&A here: How to view a linear
git log(exclude feature commits), showing only commits tomainor merges tomain, 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:
In a real example, you would use the full or short commit hashes instead of the word
commit4above. So, it might look like this, for example:More specifically:
This:
...produces this:
And this:
...produces this:
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, eithercommit4plusfeatureCommit2andfeatureCommit1, or justfeatureCommit2andfeatureCommit1, 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:
commit^2is the immediate right parent of the two parents involved in the merge which createdcommit. 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.commit~is the immediate left parent of the two parents involved in the merge which createdcommit. In this case, this would be themainbranch as it was before this PR was merged intomain.The carat (
^) symbol in front of a commit means "not" that commit, or to "exclude" that commit.So:
commit4means "commit4",commit4~means "one commit beforecommit4", AKA: "commit4's left parent" (ifcommit4is a merge commit), and otherwise just "commit4's only parent".^commit4~means "not incommit4's left parent", andcommit4^2means "incommit4's right parent".So:
git lg ^commit4~ commit4^2means "show me all commits which are incommit4's right parent (ie: excludingcommit4itself), but not incommit4'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:git lg ^commit4~ commit4means "show me all commits which are in or undercommit4(includingcommit4itself), but not incommit4'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.