Search code examples
c#libgit2libgit2sharp

Find all merge in Ancestry Path


In Git, I can get all of need commits via

git log hash..master --ancestry-path --merges

Is there an equivalent to do this in LibGit2Sharp?


Solution

  • First some basics:

    git log topic..master

    var filter = new CommitFilter { 
        SortBy = CommitSortStrategies.Time,
        Since = master,
        Until = topic,
    };
    var commitList = repo.Commits.QueryBy (filter);
    

    git log topic..master --merges

    var filter = new CommitFilter { 
        SortBy = CommitSortStrategies.Time,
        Since = master,
        Until = topic,
    };
    var commitList = repo.Commits.QueryBy (filter);
    var mergeList = commitList.Where (p => p.Parents.Count () >= 2);
    

    Now to your question:

    git log topic..master --ancestry-path --merges

    ancestry-path =

           When given a range of commits to display (e.g.  commit1..commit2 or
           commit2 ^commit1), only display commits that exist directly on the
           ancestry chain between the commit1 and commit2, i.e. commits that
           are both descendants of commit1, and ancestors of commit2.
    

    The -merges are easy once we have the ancestry path as we can filter the commits that have more then one parent. Getting the ancestry path requires some coding ;-)

    Since the ICommitLog that is returned from commitList in the first example above contains a DAG (Directed Acyclic Graph) via the .Parents property, we need to walk the graph and get "all the simple paths” via a depth-first search to find all non-cyclical paths. Once you have a list of all the simple paths just filter it by which commits have >=2 parents.

    Note: I have done this in a few C# projects and even simple ones like calc'ing the pull-request related to a particular commit uses this depth-first ancestry. I tend to stay away from Linq to do this as I have huge commit lists (100k+ nodes between the start to end nodes within just the sub-DAG that I searching) and also avoid recursive methods due to stack size but your use-case may/will differ. If you get stuck at this point, post another question with your algorithm/code issue.