git rebase: следующие неотслеживаемые файлы рабочего дерева будут перезаписаны извлечением (хотя файлы отслеживаются) - PullRequest
1 голос
/ 13 марта 2020

При попытке интерактивного перебазирования, git говорит:

error: The following untracked working tree files would be overwritten by checkout:
        # some files here
Please move or remove them before you switch branches.
Aborting
error: could not detach HEAD

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

Почему git делает это? Как мне это исправить?

Спасибо!

Ответы [ 2 ]

2 голосов
/ 13 марта 2020

Git жалуется, потому что файлы не отслеживаются.

Я знаю, что вы сказали:

[] файлы отслеживаются

, но это не так: вы также сказали:

Они ... окончательно удалены в последующем коммите.

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

В частности, это:

error: could not detach HEAD

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

git rebase -i <start-point>

но фиксация идентифицировано здесь есть их в этом. Git потребуется git checkout для этого коммита, но при проверке этого коммита он будет перезаписывать неотслеживаемые файлы отслеживаемыми файлами.

Если этот последний бит дал вам запись-царапина / WTF шум в вашей голове ? не волнуйтесь: это действительно сбивает с толку.

Индекс, в Git, является важным маленьким зверем ie, который часто не объяснил должным образом. Чтобы понять это, вы должны понимать, что Git всегда имеет три - ну, до 3 - копии каждого файла, над которым вы работаете / с которым , Одна копия замораживается на все время, в коммите: коммит, который вы извлекли прямо сейчас. Вторая копия 1 находится в index . Это то, что делает файл отслеженным . Третья копия - единственная, которую вы можете увидеть ... но Git даже не использует ее , так как это ваша копия в вашей работе. tree.

Индекс, который Git также вызывает область подготовки , содержит копию (снова см. сноску 1) каждого файла, который go перейдет в следующий коммит вы делаете . Таким образом, он изначально копирует из коммита, который вы git checkout, когда вы выбираете коммит для работы. Git затем копирует индексную копию в специальном формате Git из вашего рабочего дерева 1062 *, куда Git помещает все файлы снимков, чтобы вы могли с ними работать и работать.

Как только Git скопировал их, это в основном делается с ними. Вы вносите изменения в свою копию рабочего дерева, а затем запускаете git add, чтобы сообщить Git: скопировать копию рабочего дерева обратно в / поверх верхней части индексной копии . (Опять же, см. Сноску 1.) Причины этого немного сложны, но, если хотите, подумайте об этом следующим образом:

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

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

Вы можете удалить или заменить копию индекса в любое время. Чтобы заменить его, используйте git add, чтобы скопировать файл рабочего дерева поверх того, что находится в индексе, под этим именем. Чтобы полностью удалить его, используйте git rm <em>file</em>.

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

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

(Если он отслеживается, Git знает, безопасно ли он сохранен в коммите. Если это так, Git может перезаписать его.)

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

Концепция ключа: , является ли файл отслеженным или без отслеживания зависит от того, есть ли копия в индексе. Индексная копия в основном невидима, 3 , но это жизненно важно! Индекс является временной областью. В основном он содержит следующий коммит, который вы сделаете; Git должен заполнить его в из коммита, когда вы git checkout делаете коммит.

Следовательно, отслеживаемое / неотслеживаемое состояние некоторого файла может внезапно измениться. Когда Git заполняет индекс из коммита, при необходимости он создает файл в индексе и создает его в рабочем дереве в это время; или удалит файл из рабочего дерева, если необходимо - если он не входит в коммит, на который вы перемещаетесь - и в это время он удалит файл из тоже рабочего дерева.


1 Технически, индекс содержит ссылку на объект blob, для каждого файла быть преданным. Объект BLOB-объектов заморожен на все времена, и коммиты ссылаются на него, как и индекс. Когда вы git add файл, Git сжимает и хэширует содержимое, и если с этими данными уже есть большой двоичный объект, Git может повторно использовать существующий большой двоичный объект. В противном случае Git создает новый, и этот BL ха sh входит в индекс.

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

2 Если вы используете git commit -a, это создает секунда , но временный индекс, git add - все файлы во временный индекс и фиксируются из временного индекса. Если все это работает, временный индекс становится новым; в случае неудачи Git просто удаляет временный индекс, и все возвращается к тому, что было до запуска git commit -a. TL; DR - то, что Git все еще фиксирует из индекса. Это всего лишь секунда, дополнительный индекс для бита.

3 Команда git status сравнивает индекс с коммитом HEAD и сообщает вам, что такое разные . Поэтому, если файл «пропал без вести», вы увидите удаление как , подготовленное для фиксации . Затем отдельно он сравнивает индекс с рабочим деревом и сообщает вам, что отличается . Таким образом, если файл находится в индексе, но отсутствует в рабочем дереве, вы увидите удаление как , не подготовленное для фиксации .

Если файл существует в HEAD, но ушел из индекса, а затем назад в рабочем дереве, вы увидите поэтапное удаление и неотслеживаемый файл с одинаковым именем.

1 голос
/ 13 марта 2020

Предположим, у вас есть:

  • история коммитов, где файл foo.txt был изменен, а затем удален;
  • на данный момент, рядом с вашими отслеживаемыми файлами, у вас также есть неотслеживаемая версия foo.txt на вашем диске.

В этой ситуации: git rebase будет жаловаться, поскольку не знает, что делать с текущим (неотслеживаемым) файлом foo.txt без удаления его содержание.

...