Composer конфликт пакетов в git хранилище; как отследить файлы, но избежать удаления файлов при нажатии на удаленный - PullRequest
0 голосов
/ 21 января 2020

Я установил пакет в свое веб-приложение через composer. И добавил папку с пакетом в .gitignore, в то же время фиксируя composer.json и composer.lock

. Для развертывания на нашем сервере мы подключаем Pu sh к чистому Git удаленному серверу, который, в свою очередь, выдвигает измененные файлы в соответствующем месте на сервере.

Этот рабочий процесс работал нормально.

Позже кто-то еще работавший с хранилищем добавил файлы пакета в хранилище и удалил пакет из gitignore.

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

Пока единственная моя идея выполните следующие действия:

  1. Удалите файлы из репозитория и добавьте папку пакета обратно в gitignore. Зафиксируйте это.
  2. Pu sh на удаленном компьютере (который, очевидно, будет pu sh удаленные файлы)
  3. быстро запустит composer update на сервере после нажатия, чтобы переустановить удаленный пакет .

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

Можно ли как-нибудь удалить папку пакета из отслеживаемого, в то время как НЕ заставляет пакет удаляться с пульта при нажатии на коммит ?

Я читал о assume-unchanged и skip-worktree здесь (Git - разница между «предположим, без изменений» и «пропустить рабочее дерево» ), но я Я не уверен, какой из них использовать и какой эффект будет иметь (если таковая имеется) одна из этих команд, особенно на пульте дистанционного управления?

1 Ответ

1 голос
/ 21 января 2020

Можно ли как-нибудь удалить папку пакета из отслеживаемого, при этом НЕ вызывает удаление пакета с пульта при нажатии фиксации ?

Нет.

К счастью, вам может и не понадобиться.

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

У меня есть читайте о предположении-неизменном и пропускаемом-дереве ... но я не уверен, какой из них использовать, и какой эффект любая из этих команд будет иметь (если таковые имеются) конкретно на пульте?

Либо будет работать, но --skip-worktree это тот, который вы должны использовать здесь. Ни один из них не окажет никакого влияния на любой другой Git репозиторий.


Чтобы понять все это, вам нужна правильная модель того, что на самом деле делает Git.

Сначала запомните, что базовая c единица хранения в Git - это commit . Каждый коммит имеет уникальный, большой уродливый идентификатор sh, например 083378cc35c4dbcc607e4cdd24a5fca440163d17. Этот ha sh ID является «истинным именем» коммита. Каждый репозиторий Git повсюду соглашается, что , что га sh ID зарезервирован для , что коммит, даже если рассматриваемый репозиторий Git не имеет что совершить еще. (Вот откуда все настоящие маги c в Git: уникальность этих, казалось бы, случайных, но на самом деле совершенно не случайных, ха sh идентификаторов.)

Что за коммит Хранилище состоит из двух частей: data , которые состоят из снимка всех ваших файлов; плюс метаданные , где Git хранит информацию, например, кто совершил коммит, когда (отметки даты и времени) и почему (сообщение журнала). В качестве важной части метаданных каждый коммит также хранит некоторый набор предыдущих коммитов ha sh ID в виде необработанных ha sh ID в тексте. Это позволяет Git go от любого данного коммита, в обратном направлении , до некоторого предыдущего коммита.

Фактический идентификатор ha sh для любого коммита Git является просто контрольной суммой все его данные. (Технически это просто контрольная сумма метаданных, потому что сам моментальный снимок хранится как отдельный объект Git, чей идентификатор ha sh входит в объект фиксации. Однако идентификатор ha sh этого отдельного объекта также является контрольной суммой Таким образом, благодаря математике деревьев Меркля все это работает.) Это , почему все в коммите полностью доступно только для чтения, заморожено на все времена. Если вы попытаетесь что-то изменить внутри коммита, вы на самом деле не измените коммита. Вместо этого вы получаете новый коммит с новым и другим га sh ID. Старый коммит все еще существует, с его неизменным идентификатором ha sh.

Итак: Git это все о коммитах, а Git находит коммиты по их идентификаторам ha sh. Но мы, люди, не можем иметь дело с sh идентификаторами (быстро, это было что-то 08337 или что-то 03887?). Нам бы хотелось иметь имен , например master. Между тем, Git хотел бы быстрый способ найти последний коммит в некоторой цепочке коммитов, которая заканчивается в какой-то момент. Поэтому Git предлагает нам имена, позволяя нам создавать имена ветвей .

Имя ветви просто содержит идентификатор ha sh * last commit в некоторых цепь. Этот коммит содержит в качестве parent идентификатор ha sh предыдущего предыдущего коммита в цепочке. Родительский коммит в качестве своего родителя - прародителя нашего последнего коммита - ha sh ID коммита на шаг назад и так далее:

... <-F <-G <-H   <-- master

Если коммит ha sh ID были одинарными буквы типа H, это может быть точный рисунок: имя master будет содержать ha sh ID H, commit H будет содержать ha sh ID G в качестве родителя, commit G будет содержать ha sh ID F в качестве родителя и т. д.

Процесс создания new commit состоит из:

  • выписывать снимок всех файлов; и
  • добавление соответствующих метаданных: вы как автор и коммиттер, "сейчас" как метки даты и времени и так далее. parent этого нового коммита должен быть таким, каким является current commit, как записано в текущем имени ветки. Если master указывает на H, тогда родитель нового коммита - который мы назовем I - будет H, так что I points back to H`.

Имея на самом деле сделал этот коммит (и обнаружил его ha sh ID в процессе), Git просто записывает новый ha sh ID I в имя ветви master:

... <-F <-G <-H <-I   <-- master

и у нас есть новый коммит.

Чтобы увидеть, что произошло в коммите, таком как I, Git, извлекает коммит - все его файлы - во временную область, затем извлекает файлы предыдущего коммита H во временную область и сравнивают их. Для тех, кто одинаков, Git ничего не говорит. Для тех, кто отличается, Git показывает разницу. Для тех, кто являются новыми, Git говорит, что они «добавлены», а для тех, кто находится в предыдущем коммите, но не в этом коммите, git говорит, что они «удалены».

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

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

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

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

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

Когда вы запускаете git status , Git запускает два отдельных сравнения:

  • Сначала git status сравнивает все файлы в текущем (HEAD) коммите со всеми файлами в индекс. Для каждого файла один и тот же , Git ничего не говорит. Для каждого файла, который отличается , Git говорит, что этот файл подготовлен для фиксации . Если файл в индексе новый, а не в HEAD - Git, он называется новым; и если файл ушел из индекса, Git говорит, что удален .

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

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

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

Это, наконец, место, куда приходят --assume-unchanged и --skip-worktree . Это флаги, которые вы можете установить для файлов, которые имеют в индексе. При установке любого флага Git: Привет, когда вы собираетесь рассмотреть копию этого файла в рабочем дереве ... вы можете просто пропустить его сейчас. То есть git add просматривает индекс и рабочее дерево, а также проверяет файлы .gitignore, чтобы увидеть, что отслеживается, что не отслеживается, что новее в рабочем дереве и нуждается в обновлении в предлагаемом следующем коммите, и так далее. Если какой-либо файл не отслежен и указан в .gitignore, git add пропустит его. Если он отслежен , Git добавит его, если копия рабочего дерева отличается ... , если не установлены флажки пропуска. Если установлен флаг --assume-unchanged, Git будет предполагать, что не изменился, и не добавит его. Если установлен флаг --skip-worktree, Git знает, что он определенно не должен добавлять его, даже если файл действительно изменен.

Итак, --skip-worktree означает то, что мы хотим здесь: не git add этот файл, даже если он изменился. Флаг --assume-unchanged также работает, потому что Git предполагает, что он не изменился и, следовательно, git add тоже не работает. Сегодня нет никакой разницы в фактической работе, но «пропустить рабочее дерево» выражает правильное намерение .

Обратите внимание, что, поскольку эти флаги установлены в index (иначе - staging- область) копия файла, они работают только с отслеживаемыми файлами. Отслеживаемые файлы - это те, которые находятся в области индекса / промежуточной области. Файл должен быть в индексе, прежде чем вы сможете установить флаги. И, если файл находится в индексе, эта копия файла - та, которая сейчас находится в индексе - будет той, которая будет в следующем коммите, который вы делаете.

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

Что делает это болью в заднице является то, что если мы git checkout некоторые другие коммит, а другой коммит имеет другую копию файла в нем, Git собирается заменить нашу индексную копию на тот из коммита, на который мы пытаемся перейти. Копирование этого в индекс не приведет к удалению установленного нами флага, но перезапишет копию рабочего дерева. Если мы изменили копию рабочего дерева, Git либо перезапишет ее без запроса (это, вероятно, плохо), либо скажет: Я не могу проверить этот коммит, он перезапишет ваш (предполагается / пропущен, но я не буду упоминать это) копия этого файла в рабочем дереве. На практике Git использует последний подход.

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

Но, если вы git rm эти файлы, что случится с кем-то еще , который переходит от коммита, в котором есть файлы , чтобы совершить это не так? Например, возможно, на пульте, на который вы нажимаете, этот файл извлечен прямо сейчас, и они затем git checkout a new подтвердят, что не есть эти файлы. Конечно, их Git покорно удалит эти файлы из их Git индекса и из их Git рабочего дерева пользователя. Это то, что вы не хотите, так что теперь вы застряли с их копией этого файла в вашем Git индексе, чтобы он вошел в ваши новые коммиты .

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


1 Технически в индексе есть ссылка на замороженную копию. Обновление индексной копии состоит из создания новой замороженной копии, готовой к фиксации, и записи новой ссылки в индекс. Эти детали имеют значение, если вы начнете использовать git update-index напрямую для добавления новых файлов или использовать git ls-files --stage для просмотра индекса: вы увидите внутренние blob объекта ha sh ID Git Вот. Но вы можете просто думать об индексе как о сохранении полной копии каждого файла во внутреннем замороженном формате: эта ментальная модель работает достаточно хорошо для уровня, на котором вы обычно работаете с Git.

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