Можно ли как-нибудь удалить папку пакета из отслеживаемого, при этом НЕ вызывает удаление пакета с пульта при нажатии фиксации ?
Нет.
К счастью, вам может и не понадобиться.
К сожалению, все, что вы здесь делаете, будет несколько уродливым и болезненным для использования.
У меня есть читайте о предположении-неизменном и пропускаемом-дереве ... но я не уверен, какой из них использовать, и какой эффект любая из этих команд будет иметь (если таковые имеются) конкретно на пульте?
Либо будет работать, но --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.