Копирование отдельных изменений


В предыдущем пункте мы указали, что и вы и Салли, в месте, в разных ветках вносите изменения в integer.c. Если посмотреть на лог сообщение Салли для правки 344, вы увидите, что она исправила несколько орфографических ошибок. Конечно же, в вашей копии этого файла эти ошибки остались. Возможно, что ваши будущие изменения для этого файла коснутся областей которые содержат орфографические ошибки и таким образом вы получите несколько потенциальных конфликтов при последующем объединении вашей ветки. Поэтому, лучше получить изменения Салли сейчас, до того, как вы начнете вплотную работать в этих областях файла.

Настал момент воспользоваться командой svn merge. Эта команда, оказывается, является очень близким родственником команды svn diff (о которой вы читали Главе 3). Обе эти команды способны сравнивать любые два объекта в хранилище и показывать изменения. Например, вы можете попросить svn diff показать все изменения сделанные Салли в правке 344:

$ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk Index: integer.c =================================================================== --- integer.c (revision 343) +++ integer.c (revision 344) @@ -147,7 +147,7 @@ case 6: sprintf(info->operating_system, "HPFS (OS/2 or NT)"); break; case 7: sprintf(info->operating_system, "Macintosh"); break; case 8: sprintf(info->operating_system, "Z-System"); break; - case 9: sprintf(info->operating_system, "CPM"); break; + case 9: sprintf(info->operating_system, "CP/M"); break; case 10: sprintf(info->operating_system, "TOPS-20"); break; case 11: sprintf(info->operating_system, "NTFS (Windows NT)"); break; case 12: sprintf(info->operating_system, "QDOS"); break; @@ -164,7 +164,7 @@ low = (unsigned short) read_byte(gzfile); /* read LSB */ high = (unsigned short) read_byte(gzfile); /* read MSB */ high = high << 8; /* interpret MSB correctly */ - total = low + high; /* add them togethe for correct total */ + total = low + high; /* add them together for correct total */ info->extra_header = (unsigned char *) my_malloc(total); fread(info->extra_header, total, 1, gzfile); @@ -241,7 +241,7 @@ Store the offset with ftell() ! */ if ((info->data_offset = ftell(gzfile))== -1) { - printf("error: ftell() retturned -1.\n"); + printf("error: ftell() returned -1.\n"); exit(1); } @@ -249,7 +249,7 @@ printf("I believe start of compressed data is %u\n", info->data_offset); #endif - /* Set postion eight bytes from the end of the file. */ + /* Set position eight bytes from the end of the file. */ if (fseek(gzfile, -8, SEEK_END)) { printf("error: fseek() returned non-zero\n");

Команда svn merge ведет себя практически полностью идентично. Но вместо вывода различий на терминал, применяет их к рабочей копии в виде локальных изменений:

$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk U integer.c $ svn status M integer.c

Вывод команды svn merge показывает, что к вашей копии integer.c был применен патч. Теперь она содержит изменения Салли — изменения Салли были «скопированы» из главной линии разработки в вашу рабочую копию, вашей личной ветки и теперь существуют в виде локальных изменений. С этого момента вы можете просмотреть локальные изменения и убедиться в том, что они корректно работают.

По другому сценарию, возможно, что не все будет так хорошо и integer.c может оказаться в состоянии конфликта. Вам необходимо будет при помощи стандартной процедуры (см. Главу 3) решить конфликт, либо если вы прейдете к мнению, что объединение было плохой идеей, просто отказаться от него, отменив локальные изменения командой svn revert.

После просмотра результата объединения изменений, можно их как обычно зафиксировать (svn commit). После этого изменения будут внесены в вашу ветку хранилища. В терминах контроля версий такую процедуру копирования изменений между ветками обычно называют портированием изменений.

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

$ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk." Sending integer.c Transmitting file data . Committed revision 360.

Как вы увидите в последующих разделах, очень важно следовать подобному «хорошему стилю» организации работы.

Почему бы не использовать вместо этого патчи?

Вопрос, который может крутиться у вас в голове, особенно если вы пользователь Unix: зачем вообще связываться с svn merge? Почему просто не использовать команду операционной системы patch для выполнения этой работы? Например:

$ svn diff -r 343:344 http://svn.example.com/repos/calc/trunk > patchfile $ patch -p0 < patchfile Patching file integer.c using Plan A... Hunk #1 succeeded at 147. Hunk #2 succeeded at 164. Hunk #3 succeeded at 241. Hunk #4 succeeded at 249. done

Для этого конкретного случая, да, действительно разницы нет. Однако, svn merge имеет специфические функции благодаря которым превосходит программу patch. Формат файлов, используемый программой patch довольно таки ограниченный; он способен передавать только изменения содержимого файлов. Он не имеет способа для представления изменений дерева файлов, таких, как добавление, удаление или переименование файлов и директорий. Если скажем, в результате изменений Салли, добавилась новая директория то в выводе svn diff упоминания об этом не будет. Вывод svn diff представляет собой только ограниченный патч-формат, по этому некоторые понятия он просто не может передать. [14] Команда svn merge, напротив, может передавать изменения в структуре файлов и свойств, непосредственно применяя их к рабочей копии.

Небольшое предупреждение: несмотря на то, что svn diff и svn merge очень похожи в основе, в большинстве случаев они имеют разные правила записи. Обязательно прочтите об этом в Главе 9, или спросите у svn help. Например, svn merge требует в качестве целевого объекта путь в рабочей копии, т. е. место, где ей нужно применить изменения структуры файлов. Если целевой объект не указан, предполагается, что делается попытка выполнить одну из следующих операций:

  1. Вы хотите объединить изменения директории с вашей текущей рабочей директорией.

  2. Вы хотите объединить изменения в конкретном файле с файлом имеющим тоже имя в текущей рабочей директории.

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

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

$ svn merge -r 343:344 http://svn.example.com/repos/calc/trunk my-calc-branch U my-calc-branch/integer.c

Содержание раздела