Git добавление файла только в определенную ветку - PullRequest
0 голосов
/ 23 сентября 2018

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

Как сообщить Git, что этот файл связан только с этой веткой?

1 Ответ

0 голосов
/ 23 сентября 2018

В Git такого нет.

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

Справочная информация: коммиты и ветвлениеимена

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

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


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


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

Предположим, мы начинаем с репозитория, в котором всего три коммита.Вместо больших уродливых хеш-идентификаторов давайте дадим им заглавные буквы.Первый коммит A, второй B и т. Д.Мы перестанем иметь возможность делать новые коммиты, как только у нас будет 26 коммитов, но этого будет достаточно для нас.

Поскольку коммит A является первым коммитом, он имеет нет родитель.Если мы сделали B из A, то B помнит A как родителя B, и если мы сделали C из B, C помнит B.Поскольку коммиты не могут быть изменены после внесения, A не может запомнить B, а B не может запомнить C: эта вещь "я помню", эта стрелка, указывающая от более позднего коммита обратно к более раннему, должен идти назад:

A  <-B  <-C

Что если мы сделаем C, используя A вместо B?Тогда C укажет не на B, а на A:

A--B
 \
  C

, но на данный момент давайте придерживаться прямой линии коммитов:

A--B--C

(где нам лень рисовать наконечники стрел, но на самом деле это отчасти потому, что у нас будут проблемы с наклонными).Теперь, помня, что эти удобные заглавные буквы обозначают настоящие большие уродливые хеш-идентификаторы, спросите себя: как мы - или Git - вспомним фактический хеш-идентификатор коммита C?C запоминает идентификатор B, который запоминает идентификатор A, поэтому нам не нужно запоминать эти два.Но нам do необходимо запомнить последний коммит в цепочке.

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

A--B--C   <-- master

Теперь давайте сделаем новый коммит.Мы назовем это D, но на самом деле у него есть какой-то уникальный уродливый хеш-идентификатор.Мы делаем , запустив:

git checkout master
... edit some files ...
git add ... some files ...
git commit

Когда мы делаем D, мы фиксируем коммит C.Так что C будет родителем нового коммита D.Git соберет ваше лог-сообщение, сделает снимок всех файлов, а не только git add -ed;мы вернемся к этому чуть позже - используя ваше имя и текущее время для данных автора и коммиттера, и сделаем новый, постоянный, неизменяемый коммит D, который помнит C в качестве родителя:

A--B--C--D

Но теперь имя master должно изменить .Это было воспоминание C;теперь он должен помнить D.Таким образом, последний шаг для git commit состоит в том, чтобы записать фактический хэш-идентификатор D в имя master, что дает нам следующее:

A--B--C--D   <-- master

Допустим, теперь мы используем git checkout, чтобы вернутьсясовершить B и сделать - или, проще, уже иметь - имя ветки, которое указывает на фиксацию B, чтобы мы могли нарисовать наш график следующим образом:

     C--D   <-- master
    /
A--B   <-- branch

Теперь мы делаем другоеновый коммит E.Git запишет новый коммит как обычно, сделав снимок и установив родителя E в B, потому что это тот, который мы извлекли.Когда это будет сделано, branch укажет на новый коммит E:

     C--D   <-- master
    /
A--B
    \
     E   <-- branch

Как Git узнал, что нужно переместить имя branch, а не имя master?Вот тут и приходит HEAD. Когда вы запустили:

git checkout branch

Git прикрепил вашу / свою ГОЛОВКУ к названию этой ветви, так что мы действительно должны записать это как:

     C--D   <-- master
    /
A--B
    \
     E   <-- branch (HEAD)

Теперь вы можете спросить, какие коммиты веток A и B включены.Из рисунка видно, что C и D находятся на master - и Git знает это, потому что Git начинается с end из master, commit D и работает в обратном направлениидостичь C.Мы можем видеть, что E является вершиной branch.Но какая ветвь B включена?

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

Вообще говоря, ветви имеют тенденцию к росту новых коммитов.Как мы видели выше, добавление коммита к branch не повлияло на master.Мы можем сделать больше новых коммитов:

     C--D   <-- master
    /
A--B
    \
     E--F--G--H   <-- branch (HEAD)

и master по-прежнему указывают на D.Но если мы git checkout master (прикрепить HEAD к master), а затем используем git merge к объединить commit H в master, мы получим это:

     C--D---------I   <-- master (HEAD)
    /            /
A--B            /
    \          /
     E--F--G--H   <-- branch

, и теперь ветвь master возвращается от I через D и H, так что все коммитына master снова.

Я пошел довольно быстро, поэтому на этом этапе вам может потребоваться некоторое время для работы через веб-сайт Think Like (a) Git , который имеетподробнее о том, как работает этот граф.

Вот почему нет такого понятия, как специфичный для ветви файл

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

У вас могут быть файлы, относящиеся к конкретным коммитам , но эти коммитыможет внезапно появиться во многих ветвях, особенно после того, как кто-то использует git merge.

Индекс и рабочее дерево, или, откуда берутся файлы в снимке?

После того, как вы использовалиПройдя немного времени, вы почувствуете, как коммиты хранят замороженные версии файлов, и, используя git checkout <some old commit>, вы можете получить эти версии обратно.Мы также упоминали выше, что Git сохраняет снимок каждого файла, или, точнее, всех отслеживаемых файлов.

Поскольку каждый commit (снимок) сохраняет каждый файл, Git нужен способ, чтобы они не занимали слишком много места.Git делает это частично, сжимая файлы.Не вдаваясь в технические детали, Git может сжать некоторые файлы.Эти суперсжатые файлы имеют специальный формат Git-only, такой же постоянный и неизменный, как и сами коммиты.Но это означает, что никакая другая программа не может иметь дело с этими файлами.Вам нужно вывести файлы - через git checkout - в форме, где вы можете их видеть, редактировать и использовать с другими программами.

Итак, Git предоставляет вам область, которую он называет рабочее дерево или рабочее дерево .Файлы здесь находятся в их обычной форме, а не в каком-то специальном формате Git-only.Это тоже довольно просто.

Другие системы контроля версий на этом останавливаются: у них есть замороженные зафиксированные файлы и файлы рабочего дерева.Когда вы запускаете hg commit или svn commit или что-то еще, они часами анализируют, что находится в вашем рабочем дереве, чтобы выяснить, как это сделать.ОК, на самом деле это не часы, а просто часы.Во всяком случае, это медленно.Но когда вы запускаете git commit, это молниеносно.Git получает свою огромную скорость благодаря тому, что Git называет, по-разному, index , область подготовки или кеш , в зависимости от того, какой бит документации Git илиКоманда выполняет вызов.

Хитрость в том, что когда вы git checkout делаете коммит, Git не просто разворачивает все замороженные файлы в обычную распакованную форму в вашем рабочем дереве.Git сначала копирует замороженные файлы в формате Git в этот index , сохраняя их в специальном формате Git-only, но размораживая их.Только тогда это может привести к распаковке их в дерево работы.Следовательно, этот индекс отслеживает - и это слово снова - набор файлов в вашем рабочем дереве.

Когда вы запускаете git add <em>file</em>, Git сжимает копию рабочего дереваfile в специальный формат Git-only, затем запишите это в индекс .Если в индексе была какая-то другая версия файла, то теперь он обновляется до новой из рабочего дерева.Если файл ранее не был в индексе, то теперь он равен .В любом случае, файл теперь готов к работе.

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

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

...--F--G   <-- somebranch (HEAD)

, потому что вы запустили git checkout somebranch.Индекс и рабочее дерево теперь заполнены всеми файлами из коммита G.Вы изменяете некоторый файл рабочего дерева, запускаете git add, чтобы скопировать измененный файл обратно в индекс, затем запускаете git commit.Git делает новый коммит H из индекса, меняет имя somebranch, чтобы указать на новый коммит H, и у вас есть:

...--F--G--H   <-- somebranch (HEAD)

с коммитом Hсовпадение с индексом!

Это также объясняет, почему, если вы забыли git add файл и зафиксировали, коммит получает old версию файла.Коммит получает все, что находится в индексе , который является старой версией предыдущего коммита.

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

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

О git status и .gitignore

Команда git status выводит несколько интересных фактов, например«На ветке master», во-первых, она знает, на какой ветке вы находитесь, к которой прикреплено имя HEAD.Затем он сообщает вам о файлах , подготовленных для фиксации и / или файлах , не подготовленных для фиксации .

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

Давайте еще раз посмотрим на это, потому что это важно:

  • Если индексный файл соответствуетHEAD file, Git ничего не говорит.
  • Если индексный файл отличается от HEAD файла, Git сообщает, что он подготовлен для коммита .

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

Вторая половина этого посвящена тому, что вы могли бы еще git add.Если вы изменили (или создали или удалили) некоторые файлы в вашем рабочем дереве, но не сопоставили индекс, вы могли бы запустить git add, чтобы обновить индекс досоответствовать рабочему дереву.Итак, второе сравнение - index-vs-work-tree, и:

  • Если файл индекса соответствует файлу рабочего дерева, Git ничего не говорит.
  • Если индексный файл отличается от файла рабочего дерева, Git говорит, что файл не подготовлен для фиксации .

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

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

Перечисление файла в .gitignore будет сообщать Git, что массовое «добавление», такое как git add . или git add *, не должно добавлять файл, если он еще не в указатель.Но когда он по какой-то причине попадает в индекс, файл отслеживается, и записи .gitignore больше не применяются.Они применяются только к неотслеживаемым (не в индексе) файлам.

Заключение

Вы не можете получить то, что хотите. Хорошая идея - избегать фиксации файлов, специфичных для хоста или сайта, таких как конфигурации, по крайней мере в репозитории для обычного программного обеспечения.Вместо этого передайте пример или набор настроек по умолчанию, а затем VCS игнорирует фактическую конфигурацию, если она находится в том же каталоге.Сохраните фактическую конфигурацию в отдельном репозитории, если вы хотите создать версию конфигурации.

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