Что люди имеют в виду, когда говорят «предок» в отношении мерзавца? - PullRequest
3 голосов
/ 17 марта 2019

Я видел, что это говорило о многом, но когда я google'd для смысла, я не мог найти его. Кто такой предок?

Я предполагаю, что предок ветви x - это какой-либо из родителей, прародитель, прародитель и т. Д. Ветви?

Итак, если ветвь x разветвлена ​​от master, а ветвь y разветвлена ​​от x, а ветвь z разветвлена ​​от y, то предками z являются y, x и master? Просто предположение.

Ответы [ 2 ]

5 голосов
/ 17 марта 2019

Термин «предок» был первым , введенным в апреле 2005 года для базы слияния (заменив «родительский»), объяснил через месяц :

слияние-base находит настолько хорошего общего предка, насколько это возможно.
Учитывая выбор одинаково хороших общих предков, нельзя полагаться на решение каким-либо определенным образом.

"родитель" был замечен какнепосредственный предок, в то время как алгоритм на основе слияния должен был вернуться дальше, чем это.

Как уже упоминалось в commit f76412e :

Родитель является первым родителем коммита.
Мы можем назвать его как (n+1)th предок поколениятот же head_rev, что и commit - предок n-го поколения, если этот номер поколения лучше, чем имя, которое у него уже есть.

В август 2005 первая запись предка былавведено:

[PATCH] Добавить новый расширенный синтаксис SHA1 ~

Новая запись - это сокращение от <name>, за которым следует <num> caret ('^') символов.
Например, "master~4" является предком четвертого поколения текущей главы ветви "master", следующей за первыми родителями;то же самое, что и "master^^^^", но немного более читабельно.


Предками z являются любые коммиты, достижимые из z HEAD.

Термин "достижимый" был уточнено в 2007 :

reachable:

Говорят, что все предки данного коммита достижимы из этого коммита.

В более общем смысле, один объект достижим от другого, если мы можем достичь одного из другого по цепочке, которая следует за тегами к тому, что они помечают, передает их родителям или деревьям, а деревья - деревьям или каплям, которыеони содержат.

Это приводит к пересмотру понятия расстояния между двумя коммитами :

Когда коммит имеет только один соответствующий родительский коммит,количество коммитов, которое может достичь коммит, - это ровно количество коммитов, которое может достичь родительский коммит плюс один;вместо выполнения count_distance() для коммитов, которые находятся на одной прямой жемчужине, мы можем просто добавить один к счету родителей.

С другой стороны, для коммита слияния, потому что коммитыдостижимо от одного родителя, может быть достигнуто от другого родителя, вы не можете просто добавить счет родителей плюс один для самого коммита;которые могли бы пересчитать предков, которые доступны от более чем одного родителя .

2 голосов
/ 17 марта 2019

TL; DR

Реальный ключ к приведенному ниже материалу заключается в понимании того, что ветви - или ветви имена - не там, где возникают отношения. Отношения между коммитами происходят из совершает . Имена ветвей просто помогут вам начать на графике!

Long

Помимо того, что VonC сказал , есть более общее описание из теории графов. Коммиты в Git-репозитории образуют направленный ациклический граф или DAG.

A граф G представляет собой набор узлов или вершин V вместе с набором ребер E , которые соединяются между вершинами, поэтому формулировка G = (V, E) . Граф направленный представляет собой график, в котором ребра заменены дугами , то есть стрелками. Вот два изображения из Википедии. Первый слева показывает регулярный (ненаправленный) график. Второй показывает ориентированный граф:

image image

When the graph is directed, you can only move from one node to another in the direction given by the arrows. The directed graph above is cyclic because starting at any node, you can move around and wind up back at that node.

An acyclic graph has no cycles, i.e., no matter which node you start from, you can never get back to where you started. The kind of graph that Git commits form is directed and acyclic, hence it is a DAG.

In the Git commit graph, each node or vertex is a commit, uniquely identified by its hash ID. Each arc, along with its direction, is a result of the parent commit hash ID(s) associated with the node. Hence a natural way to draw a Git graph is like this:

... 

The name master lets you start at the end, i.e., at commit H, and work backwards. The connecting arcs / arrows come out of the node as parent pointers.

An ancestor of some commit is then any commit you can reach by following the arrows. Suppose we have a more complex graph, like this one. I can't draw the internal arrows properly here, but because I put newer nodes toward the right, all the arrows point leftwards—maybe left and up, or left and down, but definitely leftwards. Our graph looks like this:

        D--E
       /    \
A--B--C      H--I--J   

Commit A is a node with no outgoing arcs. In a normal (non-Git) graph, this would make it a leaf node, but Git does everything backwards, so in Git, A is a root node. Commit B points back to A, C points to B, and so on, until we get to H. Commit H is a merge commit: it has two outgoing arcs, pointing to commits E and G both. From H, then, we can walk either the top line or the bottom line—or along both lines—and get back all the way to the root A.

These names, as you might guess, are branch names. They act as entry points to tip commits. From tip commit L we can work back along the bottom row, but we cannot reach commit H—we get to G by going from L to K to G, but G points only to F—so we cannot work our way up to H. All the arrows point backwards. From commit J, though, we can work backwards to H and hence to either row.

This means that commits K and L are only on develop, while commits D, E, H, I, and J are only on master. All other commits are on both branches. That's the reachability notion that VonC is describing.

Mathematically, in a DAG, we define predecessor and successor notions. For predecessor or precedes, we use the bent-less-than ≺ symbol: A ≺ B if you can go from A to B. We use the bent-greater-than ≻ ("successor" or "succeeds") symbol for the opposite. These define a частичный порядок в узлах на графике. Конечно, узел равен самому себе, и мы можем сказать, что для данного узла A = A, но также A ≼ A и A ≽ A.

Поскольку Git работает в обратном направлении, это меняется на противоположное: A ≺ B (A является предшественником B), если вы можете перейти от B к A! Чтобы избежать путаницы, Git использует is-ancestor вместо перед . В общем, Git также определяет is-ancestor как true, если вы сравниваете узел с самим собой, так что все узлы являются их собственными предками.

Поскольку внутренние стрелки Git работают исключительно в обратном направлении, Git не предлагает оператора is-потомок . Вы должны отменить тест is-ancestor (но см. Ниже). Если вы хотите знать, «является ли узел X потомком узла Y», вы можете начать с вопроса: «Y является предком X». Помните, что is-ancestor говорит «да», если два хеш-идентификатора совпадают!

Начиная с Git версии 1.8.0, простой способ проверить, связаны ли коммиты, обозначенные хешами $H1 и $H2, с этим понятием предков:

if git merge-base --is-ancestor $H1 $H2; then
    echo commit $H1 is an ancestor of $H2
else
    echo commit $H1 is not an ancestor of $H2
fi

Обратите внимание, что поскольку ≼ определяет только частичный порядок, тот факт, что $H1 является не предком $H2 , не означает , что $H2 обязательно является предком $H1. Например, в нашем примере выше коммиты J и L являются просто братьями и сестрами: J не является родителем L, но L также не является родителем J. Это означает, что если is-ancestor говорит «да», то вы сделали, но если он говорит «нет», вам все равно придется проверить обратный случай, чтобы выбрать между «является потомком» и «является родным братом».

Вы также можете иметь непересекающихся подграфов в хранилище. Здесь у вас есть как минимум два корня и как минимум два кончика ветви, но между узлами нет связи:

A--B--C   <-- branch1

D--E--F   <-- branch2

Нет никакой связи между коммитами верхнего ряда и коммитами нижнего ряда. Однако, если мы добавим слияние , это сделает их связанными в некотором смысле:

A--B--C
       \
        G   <-- branch1
       /
D--E--F   <-- branch2

Теперь коммиты A-B-C и D-E-F как бы "связаны браком" с слиянием в G, потому что теперь мы можем начинать с G и работать в обратном направлении либо к A или D. Ни A, ни D не являются предками друг друга, но оба они являются предками G.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...