git: как определить, с какой веткой связано изменение - PullRequest
0 голосов
/ 21 апреля 2020

Я сделал несколько изменений в одной ветке и несколько изменений в другой. Когда я запускаю git status, я вижу изменения, связанные с обеими ветками. Как определить, какое изменение файла связано с какой веткой.

Пример: у меня 4 ветки

git branch
* devl
  docker
  master
  ravi

Когда я запускаю статус git в ветке devl, он показывает следующее изменения

git status
On branch devl
Your branch is up-to-date with 'origin/devl'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   config/moolets/cookbook.conf

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        config/docker.dev.moog.conf
        config/docker.conf
        config/moolets/v2_prod_cookbook.fnma.conf
        etc/

no changes added to commit (use "git add" and/or "git commit -a")

Я думаю config/moolets/cookbook.conf связано с веткой ravi, а другие находятся в docker ветке. Но я хочу, чтобы команда git сказала мне это.

Ответы [ 3 ]

0 голосов
/ 21 апреля 2020

Если вы попытаетесь переключить ветки после изменения файла, который был в предыдущем коммите, git выдает предупреждение:

git checkout master
error: Your local changes to the following files would be overwritten by checkout:
    your_file.txt
Please commit your changes or stash them before you switch branches.
Aborting

Это потому, что git checkout перемещает HEAD, что сбрасывает ваш рабочий каталог чтобы соответствовать новому коммиту, на который указывает HEAD (то есть кончик ветви, которую вы только что извлекли).

Поэтому вам нужно добавить изменение и зафиксировать его в текущей ветке, чтобы продолжить:

git add your_file.txt
git commit -m "committing my file before I switch to master"

Тогда, когда вы git checkout master, в вашем рабочем каталоге больше не будет этого Перейдите в файл. Чтобы просмотреть изменения, вам нужно вернуться в ветку, в которой вы их зафиксировали:

git checkout my_old_branch
cat your_file.txt
0 голосов
/ 21 апреля 2020

Как уже отмечалось в нескольких ответах и ​​комментариях, незафиксированная работа просто незафиксирована: она еще не «ни на одной» ветви. Ментальная модель, которая вам нужна, чтобы понять, почему это происходит и что происходит, относительно проста, но не так проста, как могла бы быть, если бы Git не было Git. : -)

Помните обо всех этих вещах:

  • В хранилище, содержащемся в ветвях, находятся коммиты . Пока что-то не будет совершено , оно вообще не будет в хранилище.

  • Каждый коммит - это отдельная вещь, в которой вы можете выбрать один и работать с ним. , В каждом коммите хранится полный снимок всех его файлов, а также дополнительная информация, например, о том, кто его сделал, - то, что отображается в git log. Другими словами, Git не хранит изменений , а скорее всего снимков .

    Когда Git показывает вам коммит как изменения , то, что он действительно делает, сравнивает коммит с тем, который предшествует ему - его родительский коммит. Git извлекает и родителя, и ребенка во временную область (в памяти), а затем сравнивает их. Для всех одинаковых файлов Git ничего не говорит. Для каждого файла, который отличается, Git вычисляет рецепт изменения: внесите эти изменения в родительскую копию файла, и вы получите дочернюю копию файла.

    Git может сравнивать любые два коммита - например, дать git diff любые два коммита, например, sh ID, - но он также может сравнивать некоторые другие вещи, которые не совсем коммиты, как мы увидим ниже.

  • Git находит коммиты по их идентификаторам ha sh. Это большие уродливые строки букв и цифр. Каждый коммит имеет уникальный. Они выглядят случайными (но на самом деле полностью детерминированы c). Люди плохо умеют с ними работать, поэтому мы используем имена ветвей , во-первых.

  • Каждый коммит полностью, полностью, на 100% читаем. только когда это сделано. Ничто не может изменить какую-либо часть любого коммита. Файлы внутри каждого коммита хранятся в специальном, только для чтения, Git -сжатом сжатом формате, который может использовать только Git. Они заморожены навсегда и продолжают существовать в сохраненной форме, пока сам коммит продолжает существовать.

Эта последняя часть великолепна, потому что это означает, что вы всегда можете go вернуться к любой версии, которую вы сохранили. Но это также ужасно, потому что это означает, что вы на самом деле не можете выполнить какую-либо работу с файлами внутри коммита.

Из-за этого Git must извлечение коммит. То есть он должен скопировать все замороженные Git -только файлы из коммита и превратить их в обычные повседневные файлы, которые может использовать остальная часть вашего компьютера. Таким образом, есть команда Git, которая означает: Извлечь замороженные файлы из коммита и сделать их обычными файлами, которые я могу видеть и работать с ними. Эта команда git checkout (и в Git 2.23 и новее, git switch также).

Вынув файлы из коммита, теперь вы можете просматривать их и работать с ними. Вот где вы вносите изменения. Эта рабочая область ваша для работы: это не Git. Git просто перезаписывает эти файлы новыми (и / или удаляет некоторые из этих файлов), когда вы говорите это сделать. Таким образом, любые сделанные вами изменения на самом деле нигде не хранятся в Git. Они просто находятся в вашей рабочей области - место, которое Git называет вашим рабочим деревом или рабочим деревом .

Способ, которым вы работаете, состоит в том, что вы выбираете commit - по номеру ha sh или по имени ветви; в любом случае вы выбрали один конкретный коммит - и дали Git, у которого sh идентификатор или имя, с git checkout или git switch. Git затем упорядочивает вещи так, чтобы в вашем рабочем дереве были копии файлов этого коммита. Этот коммит теперь ваш текущий коммит . Если вы дали Git имя ветви, то это имя вашей ветви текущая ветка . (Если вы дали Git необработанный идентификатор * ha 1302 *, вы не находитесь на какой-либо ветви сейчас.)

И текущее имя ветви, и текущий коммит можно найти по специальному названию HEAD. Git может ответить на два разных вопроса о HEAD:

  • Какое название ветви, если таковое имеется, имеет место? (Если у него нет имени ветви, Git называет это detached HEAD .)
  • Какой коммит ha sh ID дает имя?

Команда git status обычно сообщает вам о имени ветки , так как это более полезно для людей, но вы также увидите sh идентификаторы во многих местах, таких как git log или git branch -v output.

Здесь важно знать еще одну вещь. Когда Git сначала копирует все файлы из некоторого коммита, он копирует их - или, по крайней мере, информацию о них, а также о вашем рабочем дереве - в область Git только для формата, которая объединяет Git с вашим рабочим деревом. Эта дополнительная копия помещается во что-то, что Git вызывает, по-разному, index или область подготовки .

В результате существует третий копия каждого файла, 1 как бы между подтвержденной копией и пригодной для использования копией, например:

   HEAD        index      work-tree
---------    ---------    ---------
README.md    README.md    README.md
main.py      main.py      main.py

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

Копия каждого файла в index - Git -только в том же формате как зафиксированный файл - но он не только для чтения: вы можете заменить его в любое время. Команда git add эффективно берет все, что у вас есть в рабочем дереве, и копирует это в индекс. Поэтому после того, как вы изменили файл в своем рабочем дереве, вам нужно использовать git add для замены копии в индексе Git.

Пока вы не обновите git add файлов, копии, которые находящиеся в индексе совпадают с копиями, которые находятся в коммите HEAD. То есть вы начали с того, что git checkout или git switch выбрали коммит. Git скопировал файлы коммита в индекс, затем скопировал файлы индекса в ваше рабочее дерево. Так что HEAD и индекс совпадают.

Когда вы делаете новый коммит, Git просто замораживает копию индекса в новый коммит. Новый коммит добавляется к текущему имени ветки (используя "какое имя ветки содержится в HEAD вопросе), а затем новый коммит становится текущим коммитом (обновление которого sh ID - текущий коммит.) Теперь, когда Git сделал новый коммит из любых копий файлов, которые были в индексе, HEAD и индекс снова совпадает.

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

Когда вы используете git status, он фактически запускает для вас два git diff с:

  • Сначала он печатает имя текущей ветви, а некоторые другая полезная информация, если это уместно.

  • Затем он сравнивает - т. е. использует git diff - HEAD коммит с индексом. Для каждого файла, который одинаков, он ничего не говорит. Для каждого файла, который отличается, git diff покажет вам рецепт для изменения левой си де (HEAD) копировать в правую (индексную) копию; git status обрезает это до только имени файла и статуса (новый, измененный или удаленный). Это изменения, сделанные для коммита .

  • Затем он сравнивает, т. Е. Использует git diff, индекс с вашим рабочим деревом. Для каждого файла, который одинаков, он ничего не говорит. Для каждого файла, который отличается, git status перечисляет имя и статус файла. Это изменения, не подготовленные для фиксации .

  • Наконец, поскольку ваше рабочее дерево принадлежит вам, вы можете создавать новые файлы, которые вообще не включены в индекс. Эти файлы не вышли из предыдущего коммита. Они еще не включены в индекс Git, пока вы не используете git add для их копирования в него. Это ваши неотслеживаемые файлы . Не отслеживаемый файл - это просто файл, который находится в вашем рабочем дереве, но отсутствует в индексе.

  • Если вы перечислите конкретный неотслеживаемый файл в .gitignore, git status не будет упомяните этот файл, и git add не скопирует этот файл в индекс. Это работает только для неотслеживаемых файлов: если файл уже находится в индексе Git, его перечисление в .gitignore не влияет на него.

    Обратите внимание, что индекс загружается из коммита, который вы git checkout, и разные коммиты могут содержать разные файлы, поэтому то, что находится в индексе Git, зависит - по крайней мере, на начальном этапе - от выбранного вами c коммита. После этого вы можете использовать git add и git rm, чтобы помещать новые файлы в индекс Git и полностью извлекать файлы из индекса Git, прежде чем делать новый коммит, поэтому набор файлов в индекс также не заморожен. Только файлы в commitits заморожены.

Если учесть все вышеперечисленное, будет иметь смысл гораздо больше о Git.


1 Технически, индекс содержит ссылку на содержимое файла, а не на собственно файл. Это различие имеет значение только в том случае, если вы начнете использовать git ls-files --stage и git update-index для непосредственной работы с индексом. В основном вам следует использовать git add и аналогичные команды, которые скрывают все эти детали, так что вам не нужно заботиться об этих незначительных различиях.


Заключение

A Коммит может быть в нескольких ветках. Все эти ветви содержат , которые фиксируют. Полезно установить отношения между коммитами: некоторые являются родителями других, некоторые являются детьми других, некоторые являются братьями и сестрами и так далее. Это очень похоже на семейное древо.

В коммите есть снимок, но, сравнивая снимок в parent коммита с моментальным снимком в коммите, вы можете увидеть коммит как изменения .

Вы можете иметь коммиты, которых нет в любой ветке , как работает git stash. Мы не рассмотрели, как здесь работают имена ветвей, но на самом деле они содержат идентификатор ha sh * last commit в этой ветке. Все остальное в самих коммитах. коммиты имеют отношения (родитель / потомок), но имена ветвей не имеют.

коммиты имеют значение здесь. Имена ветвей просто помогают вам (и Git) находят коммиты.

Фиксирует снимки магазина, а не изменения. Так же как и индекс Git - снимок в индексе действует как предлагаемый следующий коммит . Так что, в этом отношении, ваше рабочее дерево: но ваше рабочее дерево ваше , как вы хотите. Git просто создает и удаляет файлы в нем, когда вы указываете Git сделать это (git checkout, git switch и удалить один указанный c файл или набор файлов из обоих индексов и work-tree, git rm).

Мы не рассмотрели это здесь, но можно изменить копии файлов в вашем рабочем дереве (и даже в индексе Git тоже) , а затем все еще переключиться на другую ветку. Но это только иногда возможно. Когда и почему вы можете или не можете переключаться таким образом, становится сложно, хотя есть фундаментальный аспект безопасности: вы можете переключать ветви, если это не разрушит ваши изменения; Вы не можете, если это будет. Подробные сведения см. В Извлечение другой ветки при наличии незафиксированных изменений в текущей ветке .

Незавершенная работа существует только в вашем рабочем дереве и, возможно, также в индексе Git, если вы использовали git add, чтобы скопировать его туда. Его нет ни в одном коммите, и, следовательно, нет ни в одной ветви.

0 голосов
/ 21 апреля 2020

Вы можете знать, какие изменения принадлежат ветви, только когда фиксирует эту ветку. Без фиксации это просто изменения, которые можно спрятать или нет.

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