26

Вопрос по git – Как определяются BASE (или «предок»), LOCAL и REMOTE в конфликте Git cherry-pick или rebase merge merge?

В обычном конфликте слияния Git три версии файла для воспроизведения для трехстороннего слияния примерно таковы:

  • LOCAL: the version from my branch
  • REMOTE: the version from the other branch
  • BASE: the version from the common ancestor of the two branches (in particular, the common ancestor of my branch's HEAD and the other branch's HEAD)

Когда Git cherry-pick выбирает конфликт слияния, то, собственно говоря, общего предка нет, так как же эти вещи определяются? То же самое можно спросить о ребазе.

  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от Chris
  • Error: User Rate Limit ExceededthinkError: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceededmanpage hereError: User Rate Limit Exceeded

    от Chris
  • 35

    cherry-pick

    Если я не введу себя в заблуждение, то если вы выполните git cherry-pick & lt; commit C & gt; & quot ;, то вы получите:

    LOCAL: the commit you're merging on top of (ie the HEAD of your branch) REMOTE: the commit you're cherry picking (i.e. <commit C>) BASE: the parent of the commit you're cherry-picking (ie C^, ie the parent of C)

    Если сразу не ясно, почему BASE должен быть C ^, см. "Почему" раздел ниже.

    А пока давайте возьмем пример и посмотрим, что BASEcan be но частоwon't be общий предок во время вишни. Предположим, что граф фиксации выглядит так

    E <-- master
    |
    D 
    | C <-- foo_feature(*)
    |/
    B
    |
    A
    

    а вы в ветке foo_feature (отсюда и звездочка). Если вы выполните «git cherry-pick & lt; commit D», тогда BASE для этого cherry-pick будет коммит B, который является общим предком C и D. (C будет LOCAL, а D будет REMOTE. ) Однако, если вы вместо этого выполните git cherry-pick & lt; commit E & gt;, тогда BASE будет коммитом D. (C будет МЕСТНЫМ, а E будет УДАЛЕННЫМ.)

    rebase

    Для фонового контекста rebase - это итеративный сбор вишни. В частности, перебазирование темы поверх мастера (то есть «тема git checkout; мастер git rebase») означает примерно:

    git checkout master # switch to master's HEAD commit
    git checkout -b topic_rebased # create new branch rooted there
    for each commit C in master..topic # for each topic commit not already in master...
        git cherry-pick C # bring it over to the new branch
    finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.
    

    Метки, которые применяются во время этого процесса, являются продолжением обычных правил выбора вишни:

    LOCAL: the commit you're cherry-picking on top of This is the HEAD of the new topic_rebased branch For the first commit only, this will be the same as the HEAD of master REMOTE: the commit you're cherry picking (i.e. <commit C>) BASE: the parent of the commit you're cherry-picking (C^, ie the parent of C)

    Это подразумевает, что нужно помнить о LOCAL vs REMOTE, если вы хотите избежать путаницы:

    Even though you were on branch topic when you initiated the rebase, LOCAL never refers to a commit on the topic branch while a rebase is in progress. Instead, LOCAL always refers to a commit on the new branch being created (topic_rebased).

    (Если не помнить об этом, то во время неприятного слияния можно начать спрашивать себя: «Подождите, почему он говорит, что этоlocal изменения? Клянусь, это были изменения, сделанные на мастере, а не на моей ветке. & Quot;)

    Чтобы быть более конкретным, вот пример:

    Скажем, у нас есть график

    D <-- foo_feature(*)
    |
    | C <-- master
    B |
    |/
    |
    A
    

    и мы в настоящее время находимся на ветке foo_feature (обозначено как "*"). Если мы запустим «git rebase master», перебазирование будет продолжено в два этапа:

    Во-первых, изменения от B будут воспроизведены поверх C. Во время этого, C является ЛОКАЛЬНЫМ, B является УДАЛЕННЫМ, и A является ОСНОВНЫМ. Обратите внимание, что A является реальным общим предком B и C. После этого первого шага у вас есть примерно такой график:

       B' <-- foo_feature
    D  |
    |  |
    |  C <-- master
    B /
    |/
    |
    A
    

    (В реальной жизни B и D, возможно, уже были обрезаны с дерева на этой стадии, но я оставляю их здесь, чтобы было легче обнаружить любых потенциальных общих предков.)

    Во-вторых, изменения из D будут воспроизведены поверх B '. Во время этого B & a; является локальным, D является удаленным, а B является базовым. Обратите внимание, что B не является значимым общим предком чего-либо. (Например, он не является общим предком нынешних LOCAL и REMOTE, B 'и D. И он не является общим предком исходных головок ветвей, C и D). После этого шага у вас есть ветка примерно так:

       D' <-- foo_feature
       |
       B'
    D  |
    |  |
    |  C <-- master
    B /
    |/
    |
    A
    

    Для полноты заметки к концу ребазы B и D удаляются с графика, давая:

    D' <-- foo_feature
    |
    B'
    |
    C <-- master
    |
    A
    

    Why is BASE defined as it is?

    Как отмечено выше, и для вишни, и для перебазирования BASE является родителем (C ^) коммита C, в который вытягивается. В общем случае C ^ не является общим предком, так зачем называть его BASE? (При обычном слиянии BASEis общий предок. И часть успехов git в слиянии обусловлена его способностью находить хорошего общего предка.)

    По сути, это делается для того, чтобы реализовать «исправление». функциональность через обычныйтрехстороннее слияние алгоритм. В частности, вы получаете эти «пятнистые» свойства:

    If <commit C> doesn't modify a given given region of the file, then the version of that region from your branch will prevail. (This is, regions that the "patch" doesn't call for changing don't get patched.) If <commit C> modifies a given region of the file and your branch leaves that region alone, then the version of that region from <commit x> will prevail. (That is, regions that the "patch" calls for changing get patched.) If <commit C> modifies a given region of the file but your branch has also modified that region, then you get a merge conflict.