Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Add merge-base command example #1078

Closed
wants to merge 1 commit into from

Conversation

dpordomingo
Copy link
Contributor

@dpordomingo dpordomingo commented Feb 26, 2019

Command example implementing git merge-base behavior, with --is-ancestor and --independent modifiers.

usage:

$ ./merge_base --help

./merge_base --helpReturns the merge-base between two commits:
./merge_base <path> <baseRev> <headRev>
./merge_base <path> --is-ancestor <baseRev> <headRev>
./merge_base <path> --independent <commitRev>...

To offer those features, it was implemented a new walker filterCommitIter (like bfsCommitIterator one), and three functions MergeBase, IsAncestor and Independents.

  • filterCommitIter

    it's a CommitIter that walks the commit history (in Breadth-first order) of the passed commit. It only returns the commits that validate the passed isValid CommitFilter, and only traverse the commits that do not validate isLimit CommitFilter.

  • MergeBase(first, second *object.Commit) ([]*object.Commit, error)

    it mimics the behavior of git merge-base a b, returning the best common ancestor of the two passed commits; the best common ancestor cannot be reached from other common ancestors.

  • IsAncestor(first, second *object.Commit) (bool, error)

    it returns true if the first commit is an ancestor of the second one, like git merge --is-ancestor does

  • Independents(commits []*object.Commit) ([]*object.Commit, error)

    it returns a subset of the passed commits, that are not reachable from any other, as git merge-base --independent commit... does

alternative:

imo the new feature could be part of go-git itself, instead of being an _example; to do so, I think that filterCommitIter could replace bfsCommitIterator or be moved into go-git/plumbing/object package, and MergeBase, IsAncestor and Independents could be moved into git.Repository struct.

If you think it could be feasible as proposed, or with any change, let me know and will work over it during the next OSD 🎉

Signed-off-by: David Pordomingo <David.Pordomingo.F@gmail.com>
@mcuadros
Copy link
Contributor

Will be nice to add a README to this example to understand how works

@dpordomingo
Copy link
Contributor Author

dpordomingo commented Feb 28, 2019

Would it be enough adding that info to the command itself?
Something like the following, that I adapted from git merge-base command.

Running it wothout no options:

$ ./merge_base

usage: merge_base <commitRev> <commitRev>
   or: merge_base --independent <commitRev>...
   or: merge_base --is-ancestor <commitRev> <commitRev>

    (no option)       lists the best common ancestors of the two passed commits
    --independent     list commits not reachable from the others
    --is-ancestor     is the first one ancestor of the other?

with --help

$ ./merge_base --help

NAME:
   merge_base - Lists the best common ancestors of the two passed commit revisions

SYNOPSIS:
 usage: merge_base <commitRev> <commitRev>
    or: merge_base --independent <commitRev>...
    or: merge_base --is-ancestor <commitRev> <commitRev>

DESCRIPTION:
    merge_base finds the best common ancestor(s) between two commits. One common
    ancestor is better than another common ancestor if the latter is an ancestor
    of the former.
    A common ancestor that does not have any better common ancestor is a best
    common ancestor, i.e. a merge base. Note that there can be more than one
    merge base for a pair of commits.
    Commits that does not share a common history has no common ancestors.

OPTIONS:
    As the most common special case, specifying only two commits on the command
    line means computing the merge base between the given two commits.

--independent
    List the sub group from the passed commits, that cannot be reached from any
    other of the passed ones. In other words, it prints a minimal subset of the
    supplied commits with the same ancestors.

--is-ancestor
    Check if the first commit is an ancestor of the second one, and exit with
    status 0 if true, or with status 1 if not. Errors are signaled by a non-zero
    status that is not 1.

DISCUSSION:
    Given two commits A and B, merge_base A B will output a commit which is the
    best common ancestor of both, what means that is reachable from both A and B
    through the parent relationship.

    For example, with this topology:

             o---o---o---o---B
            /       /
    ---3---2---o---1---o---A

    the merge base between A and B is 1.

    With the given topology 2 and 3 are also common ancestors of A and B, but
    they are not the best ones because they can be also reached from 1.

    When the history involves cross-cross merges, there can be more than one best
    common ancestor for two commits. For example, with this topology:

    ---1---o---A
        \ /
         X
        / \
    ---2---o---o---B

    When the history involves feature branches depending from another feature
    branches there can be also more than one common anvestor. For example:


           o---o---o
          /         \
         1---o---A   \
        /       /     \
    ---o---o---2---o---o---B

    In both examples, both 1 and 2 are merge-bases of A and B for each situation.
    Neither one is better than the other (both are best merge bases) because 1
    can not be reached from 2, nor the opposite.

@dpordomingo
Copy link
Contributor Author

by the way, wdyt @mcuadros about adding the core of this command (filterCommitIter, MergeBase, IsAncestor and Independents) into git-base itself?
That way, MergeBase could be also used by other apps.

@dpordomingo
Copy link
Contributor Author

TODO:

  • before merging this, I should review exit codes, because in git merge-base, exit code 1 is for nothing found, and other error codes are for real errors; My proposal does not respect that currently, and imo it should be done.

@smola
Copy link
Collaborator

smola commented Mar 7, 2019

@mcuadros I think the backing iterators and so on would belong to go-git core, maybe a GetMergeBase function too?

@dpordomingo
Copy link
Contributor Author

If you want to see how would it look like I can do it in my next OSD (that hopefully would be next Monday)

@dpordomingo
Copy link
Contributor Author

superseded by:

@dpordomingo dpordomingo deleted the merge-base branch March 25, 2019 19:15
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants