Выполняет ли git отслеживание текущей ветки после шага слияния/переадресации?

Шаг слияния/переадресации git pull merges/rebas ק ветвь удаленного отслеживания в/в текущую ветку.

Интересно, если git pull затем проверить текущую ветку в рабочий каталог? Или я должен сам проверить себя?

Мой вопрос заключается в моей мысли о том, что шаг слияния изменяет текущую ветвь в репозитории git, в то время как рабочий каталог не обновляется с текущей ветвью, поэтому необходимо проверить измененные текущую ветвь в рабочий каталог.

Но я не уверен, что этот шаг слияния git pull делает это уже, или я должен сделать это сам после git pull.

Ответ 1

Текущая ветвь проверяется в рабочем каталоге.

После слияния/переадресации ветвь переместилась на другую фиксацию.

Итак, да, git будет проверять, что commit, чтобы вы оставались в текущей ветке.

Ответ 2

Короткий ответ - "нет", и это на самом деле полный и технически правильный ответ, но немного неудовлетворительный и, скорее всего, вводящий в заблуждение: во всех хороших случаях конечное состояние выглядит так, как будто git сделал проверку. Тем не менее, вы можете остановиться здесь, если хотите.: -)

Длительный ответ немного длинный и усложняется в современных версиях git, потому что вы можете настроить git rebase на "autostash". Но еще раз мы вернемся к тому, что git pull работает git fetch, за которым следуют либо git merge, либо git rebase.

  • Шаг fetch проще, потому что ему не нужно знать или заботиться о рабочем каталоге. Он связывается с именем remote (взятым из текущей ветки branch.$branch.remote, если вы не указали один), дает этот удаленный некоторый refspec (s) (из дополнительных аргументов, которые вы передали, или ваша конфигурация, если вы не прошли никаких), и при необходимости переносит коммиты и другие объекты с пульта. Эти коммиты и другие объекты перемещаются в хранилище в вашем репозитории, где они безопасно уходят с пути, но доступны в любое время. Некоторые имена (ветки) удаленного отслеживания могут быть обновлены, и в любом случае ветвь ветки помещается в специальный файл FETCH_HEAD (в частности, FETCH_HEAD получает идентификаторы SHA-1, которые перейдите к имени каждой ветки головки).

    Чтобы увидеть все действие/имя объекта SHA-1 в действии, запустите git ls-remote remote (например, git ls-remote origin). Это связывается с пультом дистанционного управления и получает от него ту же информацию, что и git fetch, а затем распечатывает ее в окне команд. Он ничего не меняет, поэтому он просто использует небольшую пропускную способность сети, и это, на мой взгляд, довольно образовательное. (Если на пульте есть много ветвей и тегов, вам может потребоваться прокрутка вперед и назад, чтобы просмотреть весь вывод или сохранить вывод в файле или что-то еще.)

  • Шаг merge или rebase - это место, где сложны биты. Позвольте выйти из гнездования и рассмотреть два. Пусть также рассмотрим только случай слияния с одной мишенью (т.е. Обычное каждодневное слияние, а не одно из слияний git fancy octopus).

Если вы начинаете с чистого дерева (и индекса), гораздо проще описать, что происходит сейчас. Предположим, что для начала используется чистое рабочее дерево.

Шаг fetch привел некоторые фиксации. merge или rebase находит соответствующее назначение слияния или переадресации, а затем выполняет либо слияние, либо переадресацию, как указано:

  • Для слияния git находит базу слияния. Обычно это единичная конкретная фиксация. (В некоторых случаях есть несколько кандидатов на слияние, а git обрабатывает их тоже, но не волнуйтесь о них.) Вы можете думать об этом как о точке, в которой ваша ветка и другая ветвь расходились:

    <--older--time increases as we move right--newer-->
    [see footnote 1]
    
                  o - o       <-- your branch (master)
                /
    ... - o - *
                \
                  o - o - o   <-- their branch (origin/master)
    

    На этой диаграмме каждая маленькая o node обозначает фиксацию. Слияние - это фиксация, помеченная * вместо o. Самая большая фиксация вашей ветки master является самой правой o в верхней строке, а наибольшая фиксация ее ветки origin/master является самой правой o в нижней строке.

    Позвольте называть самую частую фиксацию вашей ветки A, только для конкретности. (Он имеет свой собственный уникальный идентификатор SHA-1 и его "настоящее имя", но позвольте просто называть его A.) Позвольте называть базу слияния B и кончик их ветки C и перерисовать эту диаграмму

                  o - A       <-- your branch (master)
                /
    ... - o - B
                \
                  o - o - C   <-- their branch (origin/master)
    

    Чтобы выполнить слияние (когда требуется слияние), git начинается с запуска diff между commit B и commit A, как если бы вы сделали git diff B A (заполнение фактического SHA-1 для B и A, и он использует внутреннюю версию своего кода diff, а не просто чтение через текстовый вывод literal git diff). Этот diff сообщает git "что вы изменили" с общей базой B.

    Затем git запускает a git diff B C (внутренний формат снова, конечно). Этот diff сообщает git "что они изменили" с той же общей базы.

    Наконец, git пытается объединить два diff. Если вы добавили файл, и они этого не сделали, git сохранит ваш добавленный файл. Если вы изменили написание neighbor на neighbour в файле README, и они этого не сделали, он сохранит ваше изменение. Если они удалили файл, который вы не касались, или удалили строку из файла, который вы не коснулись, git сохраняет свое изменение. Если вы оба сделали то же самое изменение на weather.h, git хранит одну копию этого изменения (а не две копии). git применяет все "сохраненные" изменения к базовой версии и записывает результат в ваше рабочее дерево, а слияние теперь выполняется без конфликтов слияния. Результат, полагает git, готов к фиксации. (Обратите внимание, что это верно, даже если некоторые изменения, которые вы сделали, требуют, например, что система сохраняет удаленный файл, который git теперь удален. То есть, предположим, они сказали: "О, смотрите, этот файл не используется, давайте удалим его", и вы сказали "о, oops, я забыл использовать этот файл, давайте использовать его". git не знает, что эти изменения действительно конфликтуют: все, что он может сказать, это то, что строки в diff don ' t сталкиваются.)

    Следующий шаг зависит от того, присвоили ли вы флаг --no-commit. 2 Это подавляет фиксацию, несмотря ни на что. Если вы не подавили коммит, git merge совершает этот набор изменений без видимых конфликтов как "объединение слиянием", в котором есть два родителя:

                  o - A ----- M   <-- your branch (master)
                /            /
    ... - o - B             /
                \          /
                  o - o - C   <-- their branch (origin/master)
    

    На этом этапе рабочее дерево соответствует новому commit M. Хотя он не был проверен, он был проверен (зафиксирован) как слияние.

    Если вы сказали --no-commit или возник конфликт слиянием, слияние прекращается и оставляет вас для исправления и/или принятия слияния. Изменения просто присутствуют в вашем рабочем каталоге. Если и когда вы решите зафиксировать результат, это будет слияние. git знает это, потому что он оставляет файл трассировки за высказыванием "в середине слияния". Если вы решили отменить слияние с git merge --abort, это приведет к удалению трассировочного файла.

  • Для перезагрузки git проходит аналогичный процесс. Однако вместо того, чтобы найти базу слияния, он находит набор коммитов, которые у вас есть, что нет. Мы снова можем нарисовать эту диаграмму, но позволим использовать разные имена node:

                  A - B       <-- your branch (master)
                /
    ... - o - o
                \
                  C - D - E   <-- their branch (origin/master)
    

    В этом случае git находит ваши две фиксации (A и B) и копирует их (используя git cherry-pick, более или менее). Механизм для этого потенциально сложный, поэтому давайте просто отметим здесь, что каждая операция cherry-pick требует обновления вашего рабочего дерева и создания нового фиксации. Если все пойдет хорошо, мы назовем копию A, A' и копию B B'; git перемещает название ветки, указывая на B'; и окончательный рисунок выглядит следующим образом:

                  A - B       [abandoned]
                /
    ... - o - o               A' - B'   <-- your branch
                \           /
                  C - D - E   <-- their branch
    

    Поскольку каждый шаг выбора вишни обновляет ваше рабочее дерево и делает фиксацию из него, ваше рабочее дерево соответствует окончательному commit B', а не потому, что оно было проверено, но поскольку оно было проверено (зафиксировано) точно так же, как в случае слияния.

Если вы начинаете с грязного рабочего дерева (или "грязного индекса", т.е. любых изменений, которые не отмечены), это немного сложнее описать, но не слишком много. У нас все еще есть те же два случая:

  • Для слияния git будет по-прежнему пытаться объединить ваши изменения и их изменения, но он попытается это сделать, сохранив при этом ваши дополнительные незафиксированные изменения. Если он преуспевает, он делает фиксацию результата, как обычно, если не подавляется, как обычно. Если он терпит неудачу, он останавливается, как обычно, и оставляет вас очищать беспорядок.

    Хорошо, что вы можете иногда производить слияние, даже если слияние с чистым деревом не получится. Плохая вещь в том, что это действительно легко сделать это случайно, когда вы этого не хотели, и завершайте своими изменениями, собранными вместе с их изменениями, и очень трудно отступить. Обычно это просто плохая идея: commit или stash, а затем слияние из чистого состояния, возможно, с --no-commit, если хотите. Затем вы можете запускать тесты и выполнять свою собственную фиксацию после каких-либо исправлений. (Обратите внимание, что вы также можете использовать git commit --amend при компиляции слияния.)

  • Для rebase обычно git rebase просто откажется запускаться, если дерево работы не будет чистым. Это делает это легким делом. Однако, поскольку git 1.8.4, rebase теперь имеет настраиваемый параметр rebase.autostash. Если вы установите это, ваш rebase будет запускать git stash для вас в этом случае, а затем выполнить rebase, а затем (если все пойдет хорошо) вытащите тайник для вас. У этого режима есть раздражающая (но не фатальная) ошибка, которая не была зафиксирована до git 2.0.1, и я рекомендую против нее вообще - я думаю, что лучше просто сделать фиксацию контрольной точки и очистить ее в последующей очистке pass (обычно хорошо иметь пропуск для очистки до того, как "финализация" завершается, и что время, чтобы отбросить временные контрольные точки, до тех пор они естественным образом восстанавливаются, без какой-либо опасности сгоревших автозапуска).


1 Хотя диаграмма говорит, что "время увеличивается вправо", технически это просто то, что узлы справа являются наследниками их узлов слева. Это особенно актуально, когда вы получаете фиксации с удаленного. Временные метки в этих коммитах были сделаны на каком-то другом компьютере, и даже если вы хорошо разбираетесь в том, что ваш компьютер синхронизирован с атомными часами где-нибудь, кто знает, правильны ли их часы (-ы)? Эти метки времени могут быть полностью сломаны. Заказ времени не гарантируется, просто "вероятен".

2 Кроме --no-commit, git merge также принимает флаг --squash, который имеет два побочных эффекта: (1) окончательная фиксация не является фиксацией слияния вообще и (2) после выполнения обычной работы для слияния git merge останавливается без фиксации (как и для --no-commit). То есть, что --squash делает внутренне, чтобы остановить окончательную фиксацию и остановить git merge от записи этого специального файла состояния, который сообщает git, что он находится в середине слияния. Таким образом, ручная фиксация, которую вы должны выполнить после этого, является обычным фиксацией без объединения.