Git: Как применить изменения одного файла из ветви A к другому файлу в ветви B того же репо? - PullRequest
0 голосов
/ 13 июля 2020

В репозитории X у меня есть ветка A, в которой я хотел бы применить изменения из ветки B. Я хотел бы применить сумму всех изменений файла d (с master в качестве базы) из ветка B в другой файл c в ветке A (которая также имеет master в качестве основы):

Branch A (based on master)

app/file_c (should receive the changes from app/file_d on branch B)
app/file_d


Branch B (based on master)

app/file_c
app/file_d (has the changes I'm interested in)

Я попытался переместить файл d из ветки B в расположение файла c а затем отбирать изменения как фиксацию из ветки B, когда в ветке A, но это перезапишет весь файл и сделает историю git менее читаемой.

Какие команды git могут помочь мне добиться этого обновления?

1 Ответ

0 голосов
/ 14 июля 2020

Запомните эти элементы:

  • Фиксирует удержание снимков. Это не изменения , это полные копии каждого файла. (Git выполняет автоматическое c дедупликацию, поэтому тот факт, что многие коммиты повторно используют множество файлов, означает, что они действительно повторно используют файл, даже если у каждого из них есть полный снимок. у них есть один снимок этого файла, общий для всех снимков, имеющих эту единственную версию этого файла.)

  • Имена ветвей просто идентифицируют одну конкретную фиксацию. Каждая фиксация ссылается на предыдущую, или родительский , фиксация. 1 Фиксация, которую выбирает ветвь, по определению является последней фиксацией в этой ветке . (Это, в свою очередь, означает, что некоторые коммиты выполняются одновременно на многих или даже на каждой ветке.)

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

  • Сами коммиты полностью доступны только для чтения. Вы никогда не можете изменить что-либо внутри любого существующего коммита. Что вам нужно Git, так это извлечь существующую фиксацию в рабочую область. Вы можете внести любые изменения в эту рабочую область, а затем использовать git add и git commit, чтобы сделать новый коммит. Новый коммит добавляет в репозиторий; существующие коммиты остаются без изменений.

1 A merge commit относится к более чем одной предыдущей фиксации, и по крайней мере одна фиксация в каждом репозитории - самая первая - буквально не может относится к предыдущей фиксации, поэтому это не так. Но большинство коммитов в основном имеют одного родителя, которым является предыдущий коммит. Это то, что история есть в репозитории Git: эта обратная цепочка коммитов, переходящая от фиксации к родительскому, к дедушке и дедушке и так далее. Каждый из этих коммитов имеет полный снимок всех файлов.

У меня есть ветка A, в которой я хотел бы применить изменения из ветки B.

Давайте нарисуем это, причем более ранние коммиты слева, а более поздние - справа. Мы будем использовать одиночные заглавные буквы для обозначения реальных Git commit ha sh ID, но зарезервировать A и B для имен веток:

       I--J   <-- A
      /
...--G--H   <-- master
         \
          K--L   <-- B

Конечно, я не Я не знаю, как выглядят ваши ветки, но здесь у нас есть три ветки:

  • A заканчивается фиксацией J;
  • B заканчивается фиксацией L ; и
  • master заканчивается фиксацией H.

Родителем фиксации J является фиксация I, родителем которого является фиксация G. Родителем коммита L является коммит K, а родительским элементом K является коммит H, чьим родителем также является коммит G. Это означает, что фиксация G выполняется во всех трех ветвях; фиксация H находится на master и B; и коммиты I-J и K-L находятся только на A и B соответственно.

Я бы хотел применить сумму всех изменений файла d (с master в качестве основы) из ветки B в другой файл c в ветке A (которая также имеет master в качестве базы) ...

Хорошо, возможно, мне следовало нарисовать это как:

          I--J   <-- A
         /
...--G--H   <-- master
         \
          K--L   <-- B

Теперь ваша цель - найти изменений в каком-то файле d, как это видно в фиксации - вероятно, H, как определено именем master - версии этого файла, как видно в коммите L, идентифицируемом именем ветки B.

Команда git diff выполняет следующие действия:

git diff master B

покажет вам, что изменилось в все файлы в фиксации H (найдены по имени master) в все файлы в фиксации L (найдены с использованием имени B), как если бы в игре «найди разницу». Вы можете вернуть Git обратно, чтобы просто показать все, что отличается в файле d, игнорируя все другие файлы, попросив git diff ограничить его вывод:

git diff master B -- d

Возможно, вы захотите перенаправить вывод git diff во временный файл:

git diff master B -- d > /tmp/the_diff

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

в другой файл c в ветке A

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

git checkout A

или (в Git с 2.23):

git switch A

(эти конкретные вызовы делают то же самое; новая команда git switch просто более удобна для пользователя, чем старая команда git checkout, потому что многие операции git checkout, которые незаметно перезаписывают вашу работу без запроса, были перемещены в отдельная команда, поэтому git switch безопаснее использовать).

В вашем рабочем дереве теперь есть изменяемая копия файла c. Теперь вам нужно изменить его, используя инструкции, которые Git создал для , как изменить копию d, которая находится в фиксации H, чтобы она выглядела как копия, которая находится в фиксации L. Для этого вы сначала измените инструкции , чтобы они ссылались на файл c вместо файла d. Затем вы можете запустить:

git apply /tmp/the_diff

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

Если все пойдет хорошо, Git применит все изменения. Если некоторые из них не применяются правильно, у вас есть различные варианты, например --reject или --3way.

Обратите внимание, что по умолчанию git apply не будет обрабатывать изменения, которые нужно зафиксировать; это оставляет это вам. Использование git apply --index изменит это.

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