Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find all unmerged commits in master grouped by the branches they were created in?

I have to create some code review from unmerged branches.

In finding solutions, let's not go to local-branch context problem as this will run on a server; there will be just the origin remote, I will always run a git fetch origin command before other commands, and when we talk about branches, we will refer to origin/branch-name.

If the setup were simple and each branch that originated from master continued on its own way, we could just run:

git rev-list origin/branch-name --not origin/master --no-merges

for each unmerged branch and add the resulting commits to each review per branch.

The problem arises when there are merges between 2-3 branches and work is continued on some of them. As I said, for each branch I want to create code reviews programmatic and I don't want to include a commit in multiple reviews.

Mainly the problems reduce on finding the original branch for each commit.
Or to put it simpler... finding all unmerged commits grouped by the branch they most probably were created on.

Let's focus on a simple example:

      *    b4 - branch2's head
   *  |    a4 - branch1's head
   |  *    b3
   *  |    merge branch2 into branch1
*  |\ |    m3 - master's head
|  * \|    a3
|  |  |
|  |  *    b2
|  *  |    merge master into branch1
* /|  |    m2
|/ |  *    merge branch1 into branch2
|  * /|    a2
|  |/ |
|  |  *    b1
|  | /
|  |/
| /|
|/ |
|  *       a1
* /        m1
|/
|
*          start

and what I want to obtain is:

  • branch1: a1, a2, a3, a4
  • branch2: b1, b2, b3, b4

The best solution I found so far is to run:

git show-branch --topo-order --topics origin/master origin/branch1 origin/branch2

and parse the result:

* [master] m3
 ! [branch1] a4
  ! [branch2] b4
---
  + [branch2] b4
  + [branch2^] b3
 +  [branch1] a4
 ++ [branch2~2] b2
 -- [branch2~3] Merge branch 'branch1' into branch2
 ++ [branch2~4] b1
 +  [branch1~2] a3
 +  [branch1~4] a2
 ++ [branch1~5] a1
*++ [branch2~5] m1

Output interpretation is like this:

  1. First n lines are the n branches analyzed
  2. one line with ----
  3. one line for each commit with a plus (or minus in case of merge commits) on the n-th indentation character if that commit is on the n-th branch.
  4. the last line is the merge base for all branches analyzed

For point 3. the commit name resolution is starting with a branch name and, from what I see, this branch corresponds to the branch that commits were created on, probably by promoting path reaching by first-parent.

As I'm not interested in merge commits, I'll ignore them.

I'll then parse each branch-path-commit to obtain their hash with rev-parse.

How can I handle this situation?

like image 738
drealecs Avatar asked Mar 23 '13 17:03

drealecs


People also ask

How do you find all the commits made on a branch?

On GitHub.com, you can access your project history by selecting the commit button from the code tab on your project. Locally, you can use git log . The git log command enables you to display a list of all of the commits on your current branch. By default, the git log command presents a lot of information all at once.

How do I see commits in master branch?

To confirm, you can run git branch . The branch that you are on will be the one with a * next to it. Git checkout might fail with an error message, e.g. if it would overwrite modified files. Git branch should show you the current branch and git log master allows you to view commit logs without changing the branch.

Is there a script to list git branches created by me?

There is no information about who created any branch in git. Period. So short answer is No, there is none.

What are unmerged commits?

git-unmerged is a tool that helps you find commits that have not been merged into an upstream branch like master or origin/master. It displays useful information in color to make it easy to identify the missing commits. To make it easier on us, it provides a brief overview, a legend, and a breakdown of each branch.


1 Answers

The repository could be cloned with --mirror which creates a bare repository that can be used as a mirror of the original repository and can be updated with git remote update --prune after which all the tags should be deleted for this feature.

I implement it this way:
1. get a list of branches not merged into master

git branch --no-merged master

2. for each branch get a list of revisions on that branch and not in master branch

git rev-list branch1 --not master --no-merges

If the list is empty, remove the branch from the list of branches
3. for each revision, determine the original branch with

git name-rev --name-only revisionHash1

and match regex for ^([^\~\^]*)([\~\^].*)?$. The first pattern is the branch name, the second is the relative path to the branch.
If the branch name found is not equal to the initial branch, remove revision from the list.

At the end I obtained a list of branches and for each of them a list of commits.


After some more bash research, it can be done all in one line with:

git rev-list --all --not master --no-merges | xargs -L1 git name-rev | grep -oE '[0-9a-f]{40}\s[^\~\^]*'

The result is an output in the form

hash branch

which can be read, parsed, ordered, group or whatever.

like image 167
drealecs Avatar answered Oct 03 '22 05:10

drealecs