неоднократно объединять один файл из другой ветки - PullRequest
0 голосов
/ 25 февраля 2020

Я начну с признания того, что я пытаюсь сделать, вероятно, плохая идея. Тем не менее, допустим, я работаю над веткой "B" и хочу объединить файл "foo" из master. Я выдаю эту команду:

git checkout master foo

Итак, я получил foo в "B", и все работает нормально. Коллега вносит изменения в foo на master, и я хочу поднять эти изменения. Я повторяю «git checkout», который заканчивается без каких-либо жалоб или каких-либо сообщений вообще. Я проверяю, соответствует ли foo версии в master, и обнаруживаю, что это не так. С момента первоначальной проверки он не изменился.

Я удаляю foo и повторяю команду git checkout. foo теперь вернулся в каталог, но это оригинальный foo.

Есть ли правильный способ для меня сделать это неправильно?

Ответы [ 3 ]

1 голос
/ 25 февраля 2020

Здесь есть две части:

  1. Это не объединение файла, это перезапись файла.

  2. Синтаксис, который вы хотите: git checkout <em>tree-ish</em> -- <em>path</em>, или, в Git начиная с 2.23, git restore --source <em>tree-ish</em> --staged --worktree -- <em>path</em>.

(будьте осторожны, чтобы не использовать git checkout -- <em>path</em>, который очень отличается.)

tree-ish часть может быть именем ветви, как master, но помните, что когда вы используете master, вы имеете в виду ваше имя филиала master, а не чье-либо имя филиала master. Чтобы сослаться на кого-то чужого master, например, master, который ваш Git запоминает (и получает от) другого Git, который ваш Git запоминает под именем origin, вы хотели бы использовать origin/master, а не master. Вы также можете использовать необработанный коммит ha sh. Например, после запуска git log, если вы заметили конкретный коммит a123456... или что-то еще и хотите скопировать этот файл из этого коммита, вы можете просто использовать га sh ID фиксации. 1

Обычно -- не является обязательным, но я рекомендую использовать его всегда. 2 Это гарантирует , что неважно имя file означает, что Git не будет случайным образом рассматривать его как имя ветви, как опцию, или как угодно. (Например, предположим, что файл называется master, или -f, или что-то похожее. Они выглядят как имена и параметры ветвей. -- говорит Git: Это не имя ветви и не опция, или что-то в этом роде: это имя файла. )

путь часть - это просто путь к файлу, который появляется в коммите.

Опять же, к go обратно к точке # 1, здесь нет слияния . Чтобы объединить , вам нужно три версии файла; он выбирает одну версию - версию, сохраненную в выбранном вами коммите, и говорит записать эту версию файла в индекс и в мое рабочее дерево . 4


1 Причина, по которой в документации говорится, что этот аргумент является tree-i sh, а не commit или commit-i sh - это то, что вы можете использовать все, что разрешено для одного из Git внутренних деревьев объектов. Коммит делает это, поэтому коммит работает; и здесь никогда не будет 3 никаких причин использовать что-либо, кроме коммита, здесь есть sh ID.

2 Я сам не в такой привычке, но обычно Я заметил в случае, когда пропуск -- вызвал бы проблему. Для меня все еще было бы хорошо иметь это как привычку, если я не замечу!

3 Вставьте сюда процедуру Гилберта и Салливана.

4 Индекс , который Git также называет областью подготовки , - это место, где вы строите свой следующий коммит. 5 Ваше рабочее дерево - это место, где вы можете просматривать и работать со своими файлами. Файлы, хранящиеся внутри коммитов, хранятся в специальном, только для чтения, Git -только, замороженном на все время формате. Это делает их отличными для архивирования - что является огромной частью того, что система контроля версий о , в конце концов, - но совершенно бесполезно для выполнения любой работы . Следовательно, рабочее дерево или рабочее дерево , где у вас есть полезные версии файлов, извлеченные из коммитов.

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

0 голосов
/ 25 февраля 2020

Ваши описанные симптомы кажутся мне противоречивыми, я собираюсь ответить, как если бы вы хотели применить последующие изменения к master копии foo к вашей копии в «B».

Самый простой способ - напрямую попросить git применить изменения с момента последнего просмотра, набрав git apply. Вам нужно помнить, когда в последний раз вы смотрели, это зависит от вас, вы можете добавить комментарий в свою копию foo или сохранить его в отдельном списке, что угодно. Я предполагаю, что у вас есть строка last master merge from: 4a0ff3a2d9c42313a9b3b1bb59ba64334650fa74 в вашем файле foo, тогда самая свежая версия вашего обновления -

base=`awk '/last master merge from:/ {print $NF}' foo`
git diff $base master -- foo | git apply -3 
sed -si "1,/last master merge:/s/$base/`git rev-parse master`/" foo

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

0 голосов
/ 25 февраля 2020

Если удаление файла и последующая проверка вернули версию из предыдущего коммита master, то ваш локальный master не был обновлен с изменением. Так что, скорее всего, либо (а) ваш коллега не выдвинул свои изменения, либо (б) вы не втянули их в локального мастера.

У вас не будет никакой видимости изменений, пока он был выдвинут вашим коллегой и доставлен в ваш локальный репозиторий. Однако простая загрузка в локальный репозиторий не обновляет master, поэтому, если вы не хотите pull в master (или merge в master после fetch), вы ' Я должен сделать что-то вроде

git checkout origin/master foo

(что все еще зависит от изменения, которое было передано и затем извлечено).

Используете ли вы master или origin/master, как отмечено в посте Торека лучше добавить -- перед путем, как в

git checkout master -- foo

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

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

Если вы внесли какие-либо локальные изменения или по какой-либо другой запутанной причине, ваша версия изменилась таким образом, что версия origin/master не будет отражать эта процедура отменит эти изменения.

Чтобы убедиться, что кредит дан четко, все это описано в ответе Торека, который более подробно описан. Я рекомендую прочитать и понять это. Я просто написал этот ответ, потому что, основываясь на поведении, которое вы описали, я считаю, что это делает непосредственные проблемы более приоритетными, поэтому, возможно, вы сможете более четко увидеть, что пошло не так.

То есть: просто потому что я описываю поведение этой процедуры, не означает, что я одобряю это. НЕТ правильного способа сделать неправильную вещь.

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