Основные понятия SVN
Система контроля версий (VCS) — это программное обеспечение, которое помогает разработчикам программного обеспечения работать вместе и вести полную историю своей работы.
Ниже приведены цели системы контроля версий.
- Разрешить разработчикам работать одновременно.
- Не перезаписывайте изменения друг друга.
- Поддерживать историю каждой версии всего.
VCS делится на две категории.
- Централизованная система контроля версий (CVCS), и
- Распределенная / децентрализованная система контроля версий (DVCS).
В этом руководстве мы сконцентрируемся только на централизованной системе контроля версий и особенно на Subversion . Subversion относится к централизованной системе контроля версий, что означает, что он использует центральный сервер для хранения всех файлов и обеспечивает совместную работу команды.
Терминология контроля версий
Давайте начнем с обсуждения некоторых терминов, которые мы будем использовать в этом руководстве.
-
Репозиторий: Репозиторий является сердцем любой системы контроля версий. Это центральное место, где разработчики хранят всю свою работу. Репозиторий хранит не только файлы, но и историю. Доступ к репозиторию осуществляется через сеть, выступая в роли сервера и инструмента контроля версий, выступающего в роли клиента. Клиенты могут подключаться к хранилищу, а затем они могут сохранять / извлекать свои изменения в / из хранилища. Сохраняя изменения, клиент делает эти изменения доступными для других людей, а путем извлечения изменений клиент воспринимает изменения других людей как рабочую копию.
-
Магистраль: Магистраль — это каталог, в котором происходит вся основная разработка, и обычно проверяется разработчиками для работы над проектом.
-
Теги : каталог тегов используется для хранения именованных снимков проекта. Работа с тегами позволяет задавать описательные и запоминающиеся имена конкретной версии в репозитории.
Например, LAST_STABLE_CODE_BEFORE_EMAIL_SUPPORT более запоминающимся, чем
UUID репозитория: 7ceef8cb-3799-40dd-a067-c216ec2e5247 и
Редакция: 13
-
Ветви: Операция ветвления используется для создания другой линии развития. Это полезно, когда вы хотите, чтобы процесс разработки проходил в двух разных направлениях. Например, когда вы выпускаете версию 5.0, вы можете захотеть создать ветку, чтобы разработка функций 6.0 могла быть отделена от исправлений ошибок 5.0.
-
Рабочая копия: Рабочая копия — это снимок хранилища. Репозиторий является общим для всех команд, но люди не изменяют его напрямую. Вместо этого каждый разработчик проверяет рабочую копию. Рабочая копия — это личное рабочее место, где разработчики могут выполнять свою работу, оставаясь изолированными от остальной части команды.
-
Фиксация изменений. Фиксация — это процесс сохранения изменений с частного рабочего места на центральный сервер. После фиксации изменения становятся доступными для всей команды. Другие разработчики могут получить эти изменения, обновив свою рабочую копию. Фиксация — это атомарная операция. Либо весь коммит успешен, либо откатан. Пользователи никогда не видят наполовину завершенный коммит.
Репозиторий: Репозиторий является сердцем любой системы контроля версий. Это центральное место, где разработчики хранят всю свою работу. Репозиторий хранит не только файлы, но и историю. Доступ к репозиторию осуществляется через сеть, выступая в роли сервера и инструмента контроля версий, выступающего в роли клиента. Клиенты могут подключаться к хранилищу, а затем они могут сохранять / извлекать свои изменения в / из хранилища. Сохраняя изменения, клиент делает эти изменения доступными для других людей, а путем извлечения изменений клиент воспринимает изменения других людей как рабочую копию.
Магистраль: Магистраль — это каталог, в котором происходит вся основная разработка, и обычно проверяется разработчиками для работы над проектом.
Теги : каталог тегов используется для хранения именованных снимков проекта. Работа с тегами позволяет задавать описательные и запоминающиеся имена конкретной версии в репозитории.
Например, LAST_STABLE_CODE_BEFORE_EMAIL_SUPPORT более запоминающимся, чем
UUID репозитория: 7ceef8cb-3799-40dd-a067-c216ec2e5247 и
Редакция: 13
Ветви: Операция ветвления используется для создания другой линии развития. Это полезно, когда вы хотите, чтобы процесс разработки проходил в двух разных направлениях. Например, когда вы выпускаете версию 5.0, вы можете захотеть создать ветку, чтобы разработка функций 6.0 могла быть отделена от исправлений ошибок 5.0.
Рабочая копия: Рабочая копия — это снимок хранилища. Репозиторий является общим для всех команд, но люди не изменяют его напрямую. Вместо этого каждый разработчик проверяет рабочую копию. Рабочая копия — это личное рабочее место, где разработчики могут выполнять свою работу, оставаясь изолированными от остальной части команды.
Фиксация изменений. Фиксация — это процесс сохранения изменений с частного рабочего места на центральный сервер. После фиксации изменения становятся доступными для всей команды. Другие разработчики могут получить эти изменения, обновив свою рабочую копию. Фиксация — это атомарная операция. Либо весь коммит успешен, либо откатан. Пользователи никогда не видят наполовину завершенный коммит.
Настройка среды SVN
Установка SVN
Subversion — это популярный инструмент контроля версий с открытым исходным кодом. Это с открытым исходным кодом и доступно бесплатно через Интернет. Он поставляется по умолчанию с большинством дистрибутивов GNU / Linux, поэтому он может быть уже установлен в вашей системе. Чтобы проверить, установлен он или нет, используйте следующую команду.
[jerry@CentOS ~]$ svn --version
Если клиент Subversion не установлен, команда сообщит об ошибке, в противном случае будет отображена версия установленного программного обеспечения.
[jerry@CentOS ~]$ svn --version -bash: svn: command not found
Если вы используете основанную на RPM GNU / Linux, используйте для установки команду yum . После успешной установки выполните команду svn —version .
[jerry@CentOS ~]$ su - Password: [root@CentOS ~]# yum install subversion [jerry@CentOS ~]$ svn --version svn, version 1.6.11 (r934486) compiled Jun 23 2012, 00:44:03
А если вы используете GNU / Linux на основе Debian, то для установки используйте команду apt .
[jerry@Ubuntu]$ sudo apt-get update [sudo] password for jerry: [jerry@Ubuntu]$ sudo apt-get install subversion [jerry@Ubuntu]$ svn --version svn, version 1.7.5 (r1336830) compiled Jun 21 2013, 22:11:49
Настройка Apache
Мы видели, как установить клиент Subversion в GNU / Linux. Давайте посмотрим, как создать новый репозиторий и разрешить доступ пользователям.
На сервере мы должны установить модуль Apache httpd и инструмент svnadmin .
[jerry@CentOS ~]$ su - Password: [root@CentOS ~]# yum install mod_dav_svn subversion
Пакет mod_dav_svn позволяет получить доступ к хранилищу по HTTP, через сервер Apache httpd, а пакет subversion устанавливает инструмент svnadmin.
Subversion считывает свою конфигурацию из файла /etc/httpd/conf.d/subversion.conf . После добавления конфигурации файл subversion.conf выглядит следующим образом:
LoadModule dav_svn_module modules/mod_dav_svn.so LoadModule authz_svn_module modules/mod_authz_svn.so <Location /svn> DAV svn SVNParentPath /var/www/svn AuthType Basic AuthName "Authorization Realm" AuthUserFile /etc/svn-users Require valid-user </Location>
Давайте создадим пользователей Subversion и предоставим им доступ к хранилищу. Команда htpasswd используется для создания и обновления текстовых файлов, которые используются для хранения имен пользователей и паролей для базовой аутентификации пользователей HTTP. Опция ‘-c’ создает файл паролей , если файл паролей уже существует, он перезаписывается. Поэтому используйте опцию -c только в первый раз. Опция ‘-m’ включает шифрование MD5 для паролей.
Настройка пользователя
Давайте создадим пользователя Том .
[root@CentOS ~]# htpasswd -cm /etc/svn-users tom New password: Re-type new password: Adding password for user tom
Давайте создадим пользователя Джерри
[root@CentOS ~]# htpasswd -m /etc/svn-users jerry New password: Re-type new password: Adding password for user jerry [root@CentOS ~]#
Создайте родительский каталог Subversion для хранения всей работы (см. /Etc/httpd/conf.d/subversion.conf ).
[root@CentOS ~]# mkdir /var/www/svn [root@CentOS ~]# cd /var/www/svn/
Настройка репозитория
Создайте репозиторий проекта с именем project_repo . Команда svnadmin создаст новый репозиторий и несколько других каталогов внутри него для хранения метаданных.
[root@CentOS svn]# svnadmin create project_repo [root@CentOS svn]# ls -l project_repo total 24 drwxr-xr-x. 2 root root 4096 Aug 4 22:30 conf drwxr-sr-x. 6 root root 4096 Aug 4 22:30 db -r--r--r--. 1 root root 2 Aug 4 22:30 format drwxr-xr-x. 2 root root 4096 Aug 4 22:30 hooks drwxr-xr-x. 2 root root 4096 Aug 4 22:30 locks -rw-r--r--. 1 root root 229 Aug 4 22:30 README.txt
Давайте изменим пользователя и группу владельцев хранилища.
[root@CentOS svn]# chown -R apache.apache project_repo/
Проверьте, включен ли SELinux или нет с помощью инструмента состояния SELinux.
[root@CentOS svn]# sestatus SELinux status: enabled SELinuxfs mount: /selinux Current mode: enforcing Mode from config file: enforcing Policy version: 24 Policy from config file: targeted
Для нашего сервера SELinux включен, поэтому мы должны изменить контекст безопасности SELinux.
[root@CentOS svn]# chcon -R -t httpd_sys_content_t /var/www/svn/project_repo/
Чтобы разрешить фиксацию по HTTP, выполните следующую команду.
[root@CentOS svn]# chcon -R -t httpd_sys_rw_content_t /var/www/svn/project_repo/
Перезапустите сервер Apache, и мы закончили с настройкой сервера Apache.
[root@CentOS svn]# service httpd restart Stopping httpd: [FAILED] Starting httpd: httpd: apr_sockaddr_info_get() failed for CentOS httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName [ OK ] [root@CentOS svn]# service httpd status httpd (pid 1372) is running... [root@CentOS svn]#
Мы успешно настроили сервер Apache, теперь настроим хранилище. Предоставить доступ к хранилищу только аутентичным пользователям и использовать файл авторизации по умолчанию; добавьте следующие строки в файл project_repo / conf / svnserve.conf .
anon-access = none authz-db = authz
Традиционно, у каждого проекта Subversion есть каталоги стволов, тегов и веток непосредственно в корневом каталоге проекта.
Магистраль — это каталог, в котором происходит вся основная разработка, и обычно проверяется разработчиками для работы над проектом.
Каталог тегов используется для хранения именованных снимков проекта. При создании производственного выпуска команда помечает код, который входит в выпуск.
Каталог веток используется, когда вы хотите заниматься разными направлениями развития.
Давайте создадим структуру каталогов стволов, тегов и ветвей в репозитории проекта.
[root@CentOS svn]# mkdir /tmp/svn-template [root@CentOS svn]# mkdir /tmp/svn-template/trunk [root@CentOS svn]# mkdir /tmp/svn-template/branches [root@CentOS svn]# mkdir /tmp/svn-template/tags
Теперь импортируйте каталоги из / tmp / svn-template в репозиторий.
[root@CentOS svn]# svn import -m 'Create trunk, branches, tags directory structure' /tmp/svn-template/ Adding /tmp/svn-template/trunk Adding /tmp/svn-template/branches Adding /tmp/svn-template/tags Committed revision 1. [root@CentOS svn]#
Готово! Мы успешно создали хранилище и разрешили доступ Тому и Джерри . Отныне они могут выполнять все поддерживаемые операции с хранилищем.
Жизненный цикл SVN
Жизненный цикл системы контроля версий обсуждается в этой главе. В последующих главах мы увидим команду Subversion для каждой операции.
Создать репозиторий:
Хранилище является центральным местом, где разработчики хранят всю свою работу. Хранилище хранит не только файлы, но и историю изменений. Это означает, что он поддерживает историю изменений, внесенных в файлы.
Операция ‘create’ используется для создания нового хранилища. В большинстве случаев эта операция выполняется только один раз. Когда вы создаете новый репозиторий, ваша VCS будет ожидать, что вы скажете что-то для его идентификации, например, где вы хотите, чтобы он был создан, или какое имя должно быть присвоено репозиторию.
Проверять, выписываться
Операция «Оформить заказ» используется для создания рабочей копии из хранилища. Рабочая копия — это личное рабочее место, где разработчики вносят свои изменения, а затем отправляют эти изменения в хранилище.
Обновить
Как следует из названия, операция обновления используется для обновления рабочей копии. Эта операция синхронизирует рабочую копию с хранилищем. Поскольку репозиторий является общим для всех команд, другие разработчики могут зафиксировать свои изменения, и ваша рабочая копия становится старше.
Предположим, Том и Джерри — два разработчика, работающие над проектом. Оба проверяют последнюю версию из репозитория и начинают работать. На данный момент их рабочие копии полностью синхронизированы с хранилищем. Джерри завершает свою работу очень эффективно и вносит свои изменения в хранилище.
Теперь рабочая копия Тома устарела. Операция обновления извлечет последние изменения Джерри из хранилища и обновит рабочую копию Тома .
Выполнить изменения
После оформления заказа можно выполнять различные операции для внесения изменений. Редактировать это самая распространенная операция. Можно редактировать существующий файл, чтобы добавить / удалить содержимое из файла.
Можно добавлять файлы / каталоги. Но сразу же эти файлы / каталоги не становятся частью репозитория, вместо этого они добавляются в ожидающий список изменений и становятся частью репозитория после операции фиксации.
Точно так же можно удалить файлы / каталоги. Операция удаления немедленно удаляет файл из рабочей копии, но фактическое удаление файла добавляется в ожидающий список изменений, и изменения вносятся в репозиторий после операции фиксации.
Операция «Переименовать» изменяет имя файла / каталога. Операция «Перемещение» используется для перемещения файлов / каталогов из одного места в другое в дереве хранилища.
Обзор изменений
Когда вы извлекаете рабочую копию или обновляете рабочую копию, ваша рабочая копия полностью синхронизируется с хранилищем. Но когда вы вносите изменения в свою рабочую копию, она становится новее, чем хранилище. Хорошей практикой является проверка ваших изменений перед операцией ‘commit’.
Операция «Состояние» перечисляет изменения, которые были внесены в рабочую копию. Как мы уже упоминали ранее, каждый раз, когда вы вносите изменения в рабочую копию, все эти изменения становятся частью ожидающего изменения списка. И операция «статус» используется, чтобы увидеть ожидающий список изменений.
Операция «Статус» предоставляет только список изменений, но не подробную информацию о них. Можно использовать операцию diff для просмотра деталей изменений, которые были внесены в рабочую копию.
Исправить ошибки
Давайте предположим, что кто-то внес изменения в свою рабочую копию, но теперь он хочет отбросить эти изменения. В этой ситуации поможет операция «возврат».
Операция возврата отменяет изменения, внесенные в рабочую копию. Можно восстановить один или несколько файлов / каталогов. Также есть возможность вернуть всю рабочую копию. В этом случае операция «возврат» уничтожит отложенный список изменений и вернет рабочую копию в исходное состояние.
Разрешить конфликты:
Конфликты могут возникнуть во время слияния. Операция «Слияние» автоматически обрабатывает все, что можно сделать безопасно. Все остальное считается конфликтом. Например, файл «hello.c» был изменен в ветви и удален в другой ветви. Такая ситуация требует, чтобы человек принял решение. Операция ‘resolve’ используется, чтобы помочь пользователю разобраться в вещах и проинформировать VCS о способах обработки конфликтов.
Зафиксировать изменения
Операция ‘Зафиксировать’ используется для применения изменений из рабочей копии в хранилище. Эта операция изменяет хранилище, и другие разработчики могут видеть эти изменения, обновляя свою рабочую копию.
Перед фиксацией необходимо добавить файлы / каталоги в ожидающий список изменений. Это место, где изменения ждут своего подтверждения. При коммите мы обычно предоставляем сообщение журнала, чтобы объяснить, почему кто-то внес изменения Это сообщение журнала становится частью истории хранилища. Фиксация — это атомарная операция, которая означает, что вся фиксация завершается успешно или выполняется откат. Пользователи никогда не видят недоделанный коммит.
Процесс проверки SVN
Subversion предоставляет команду checkout для извлечения рабочей копии из хранилища. Команда ниже создаст новый каталог в текущем рабочем каталоге с именем project_repo . Не беспокойтесь об URL хранилища, поскольку в большинстве случаев он уже предоставлен администратором Subversion с соответствующим доступом.
[tom@CentOS ~]$ svn checkout http://svn.server.com/svn/project_repo --username=tom
Приведенная выше команда даст следующий результат.
A project_repo/trunk A project_repo/branches A project_repo/tags Checked out revision 1.
После каждой успешной операции оформления заказа будет напечатан номер редакции. Если вы хотите просмотреть дополнительную информацию о хранилище, выполните команду info .
[tom@CentOS trunk]$ pwd /home/tom/project_repo/trunk [tom@CentOS trunk]$ svn info
Приведенная выше команда даст следующий результат.
Path: . URL: http://svn.server.com/svn/project_repo/trunk Repository Root: http://svn.server.com/svn/project_repo Repository UUID: 7ceef8cb-3799-40dd-a067-c216ec2e5247 Revision: 1 Node Kind: directory Schedule: normal Last Changed Author: jerry Last Changed Rev: 0 Last Changed Date: 2013-08-24 18:15:52 +0530 (Sat, 24 Aug 2013) [tom@CentOS trunk]$
SVN выполнить изменения
Джерри проверяет последнюю версию репозитория и начинает работать над проектом. Он создает файл array.c внутри директории транка.
[jerry@CentOS ~]$ cd project_repo/trunk/ [jerry@CentOS trunk]$ cat array.c
Приведенная выше команда даст следующий результат.
#include <stdio.h> #define MAX 16 int main(void) { int i, n, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); printf("Enter the elements\n"); for (i = 0; i < n; ++i) scanf("%d", &arr[i]); printf("Array has following elements\n"); for (i = 0; i < n; ++i) printf("|%d| ", arr[i]); printf("\n"); return 0; }
Он хочет проверить свой код перед коммитом.
[jerry@CentOS trunk]$ make array cc array.c -o array [jerry@CentOS trunk]$ ./array Enter the total number of elements: 5 Enter the elements 1 2 3 4 5 Array has following elements |1| |2| |3| |4| |5|
Он скомпилировал и протестировал свой код, и все работает, как и ожидалось, теперь пришло время вносить изменения.
[jerry@CentOS trunk]$ svn status ? array.c ? array
Subversion показывает ‘?’ перед именами файлов, потому что он не знает, что делать с этими файлами.
Перед фиксацией Джерри необходимо добавить этот файл в список ожидающих изменений.
[jerry@CentOS trunk]$ svn add array.c A array.c
Давайте проверим это с помощью операции «status». Subversion показывает A перед array.c , это означает, что файл успешно добавлен в ожидающий список изменений.
[jerry@CentOS trunk]$ svn status ? array A array.c
Чтобы сохранить файл array.c в хранилище, используйте команду commit с опцией -m, за которой следует сообщение commit. Если вы опустите опцию -m, Subversion откроет текстовый редактор, в котором вы можете напечатать многострочное сообщение.
[jerry@CentOS trunk]$ svn commit -m "Initial commit" Adding trunk/array.c Transmitting file data . Committed revision 2.
Теперь файл array.c успешно добавлен в хранилище, а номер ревизии увеличивается на единицу.
Изменения в обзоре SVN
Джерри уже добавил файл array.c в хранилище. Том также проверяет последний код и начинает работать.
[tom@CentOS ~]$ svn co http://svn.server.com/svn/project_repo --username=tom
Выше команда даст следующий результат.
A project_repo/trunk A project_repo/trunk/array.c A project_repo/branches A project_repo/tags Checked out revision 2.
Но он обнаружил, что кто-то уже добавил код. Поэтому ему интересно, кто это сделал, и он проверяет сообщение в журнале, чтобы увидеть более подробную информацию, используя следующую команду:
[tom@CentOS trunk]$ svn log
Выше команда даст следующий результат.
------------------------------------------------------------------------ r2 | jerry | 2013-08-17 20:40:43 +0530 (Sat, 17 Aug 2013) | 1 line Initial commit ------------------------------------------------------------------------ r1 | jerry | 2013-08-04 23:43:08 +0530 (Sun, 04 Aug 2013) | 1 line Create trunk, branches, tags directory structure ------------------------------------------------------------------------
Когда Том наблюдает за кодом Джерри , он сразу замечает ошибку в этом. Джерри не проверял переполнение массива, которое могло вызвать серьезные проблемы. Поэтому Том решает исправить эту проблему. После модификации array.c будет выглядеть следующим образом.
#include <stdio.h> #define MAX 16 int main(void) { int i, n, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); /* handle array overflow condition */ if (n > MAX) { fprintf(stderr, "Number of elements must be less than %d\n", MAX); return 1; } printf("Enter the elements\n"); for (i = 0; i < n; ++i) scanf("%d", &arr[i]); printf("Array has following elements\n"); for (i = 0; i < n; ++i) printf("|%d| ", arr[i]); printf("\n"); return 0; }
Том хочет использовать операцию статуса, чтобы увидеть ожидающий изменения список.
[tom@CentOS trunk]$ svn status M array.c
Файл array.c модифицируется, поэтому Subversion показывает букву M перед именем файла. Затем Том компилирует и тестирует свой код, и он работает нормально. Прежде чем вносить изменения, он хочет проверить его еще раз, просмотрев внесенные изменения.
[tom@CentOS trunk]$ svn diff Index: array.c =================================================================== --- array.c (revision 2) +++ array.c (working copy) @@ -9,6 +9,11 @@ printf("Enter the total number of elements: "); scanf("%d", &n); + if (n > MAX) { + fprintf(stderr, "Number of elements must be less than %d\n", MAX); + return 1; + } + printf("Enter the elements\n"); for (i = 0; i < n; ++i)
Том добавил несколько строк в файл array.c , поэтому Subversion показывает знак + перед новыми строками. Теперь он готов совершить свои изменения.
[tom@CentOS trunk]$ svn commit -m "Fix array overflow problem"
Приведенная выше команда даст следующий результат.
Sending trunk/array.c Transmitting file data . Committed revision 3.
Изменения Тома успешно переданы в хранилище.
Процесс обновления SVN
Джерри совершил первую версию кода. Но он считает, что ему следует написать две функции для приема ввода и отображения содержимого массива. После модификации array.c выглядит следующим образом.
#include <stdio.h> #define MAX 16 void accept_input(int *arr, int n) { int i; for (i = 0; i < n; ++i) scanf("%d", &arr[i]); } void display(int *arr, int n) { int i; for (i = 0; i < n; ++i) printf("|%d| ", arr[i]); printf("\n"); } int main(void) { int i, n, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); printf("Enter the elements\n"); accept_input(arr, n); printf("Array has following elements\n"); display(arr, n); return 0; }
Джерри компилирует и тестирует свой код и готов принять изменения. Перед этим он хочет просмотреть изменения, используя следующую команду.
[jerry@CentOS trunk]$ svn diff
Приведенная выше команда даст следующий результат.
Index: array.c =================================================================== --- array.c (revision 2) +++ array.c (working copy) @@ -2,6 +2,24 @@ #define MAX 16 +void accept_input(int *arr, int n) +{ + int i; + + for (i = 0; i & n; ++i) + scanf("%d", &arr[i]); +} + +void display(int *arr, int n) +{ + int i; + + for (i = 0; i < n; ++i) + printf("|%d| ", arr[i]); + + printf("\n"); +} + int main(void) { int i, n, arr[MAX]; @@ -10,15 +28,10 @@ scanf("%d", &n); printf("Enter the elements\n"); + accept_input(arr, n); - for (i = 0; i < n; ++i) - scanf("%d", &arr[i]); - printf("Array has following elements\n"); - for (i = 0; i < n; ++i) - printf("|%d| ", arr[i]); - - printf("\n"); + display(arr, n); return 0; }
Для новых добавленных строк Subversion показывает знак + перед строкой, а для удаленной строки — знак. Теперь Джерри пытается зафиксировать изменения, используя следующую команду:
[jerry@CentOS trunk]$ svn commit -m "Add function to accept input and to display array contents"
Приведенная выше команда даст следующий результат.
Sending trunk/array.c svn: Commit failed (details follow): svn: File or directory 'array.c' is out of date; try updating svn: resource out of date; try updating
Subversion не позволяет зафиксировать изменения Джерри , потому что Том уже изменил хранилище, а рабочая копия Джерри устарела. Чтобы избежать перезаписи изменений друг друга, Subversion не выполняет эту операцию. Джерри должен обновить рабочую копию, прежде чем вносить свои изменения. Поэтому он использует команду обновления, как показано ниже.
[jerry@CentOS trunk]$ svn update G array.c Updated to revision 3.
Subversion показывает букву G перед именем файла, что означает, что этот файл был объединен.
[jerry@CentOS trunk]$ svn diff
Приведенная выше команда даст следующий результат.
Index: array.c =================================================================== --- array.c (revision 3) +++ array.c (working copy) @@ -2,6 +2,24 @@ #define MAX 16 +void accept_input(int *arr, int n) +{ + int i; + + for (i = 0; i < n; ++i) + scanf("%d", &arr[i]); +} + +void display(int *arr, int n) +{ + int i; + + for (i = 0; i < n; ++i) + printf("|%d| ", arr[i]); + + printf("\n"); +} + int main(void) { int i, n, arr[MAX]; @@ -15,15 +33,10 @@ } printf("Enter the elements\n"); + accept_input(arr, n); - for (i = 0; i < n; ++i) - scanf("%d", &arr[i]); - printf("Array has following elements\n"); - for (i = 0; i < n; ++i) - printf("|%d| ", arr[i]); - - printf("\n"); + display(arr, n); return 0; }
Subversion показывает только изменения Джерри , но файл array.c объединен. Если вы внимательно наблюдаете, Subversion теперь показывает номер редакции 3. В предыдущем выводе он показывал номер редакции 2. Просто посмотрите, кто внес изменения в файл и для какой цели.
jerry@CentOS trunk]$ svn log ------------------------------------------------------------------------ r3 | tom | 2013-08-18 20:21:50 +0530 (Sun, 18 Aug 2013) | 1 line Fix array overflow problem ------------------------------------------------------------------------ r2 | jerry | 2013-08-17 20:40:43 +0530 (Sat, 17 Aug 2013) | 1 line Initial commit ------------------------------------------------------------------------ r1 | jerry | 2013-08-04 23:43:08 +0530 (Sun, 04 Aug 2013) | 1 line Create trunk, branches, tags directory structure ------------------------------------------------------------------------
Теперь рабочая копия Джерри синхронизирована с хранилищем, и он может безопасно зафиксировать свои изменения.
[jerry@CentOS trunk]$ svn commit -m "Add function to accept input and to display array contents" Sending trunk/array.c Transmitting file data . Committed revision 4.
SVN исправить ошибки
Предположим, что Джерри случайно изменил файл array.c и получил ошибки компиляции. Теперь он хочет выбросить изменения. В этой ситуации поможет операция «возврат». Операция возврата отменит все локальные изменения в файле или каталоге и разрешит все конфликтующие состояния.
[jerry@CentOS trunk]$ svn status
Выше команда даст следующий результат.
M array.c
Попробуем сделать массив следующим образом:
[jerry@CentOS trunk]$ make array
Выше команда даст следующий результат.
cc array.c -o array array.c: In function ‘main’: array.c:26: error: ‘n’ undeclared (first use in this function) array.c:26: error: (Each undeclared identifier is reported only once array.c:26: error: for each function it appears in.) array.c:34: error: ‘arr’ undeclared (first use in this function) make: *** [array] Error 1
Джерри выполняет операцию возврата к файлу array.c .
[jerry@CentOS trunk]$ svn revert array.c Reverted 'array.c' [jerry@CentOS trunk]$ svn status [jerry@CentOS trunk]$
Теперь скомпилируйте код.
[jerry@CentOS trunk]$ make array cc array.c -o array
После операции возврата его рабочая копия возвращается в исходное состояние. Операция возврата может вернуть как отдельный файл, так и полный каталог. Чтобы восстановить каталог, используйте параметр -R, как показано ниже.
[jerry@CentOS project_repo]$ pwd /home/jerry/project_repo [jerry@CentOS project_repo]$ svn revert -R trunk
До сих пор мы видели, как отменить изменения, внесенные в рабочую копию. Но что, если вы хотите отменить исправленную ревизию! Инструмент Системы контроля версий не позволяет удалять историю из хранилища. Мы можем только добавить историю. Это произойдет, даже если вы удалите файлы из хранилища. Чтобы отменить старую ревизию, мы должны отменить все изменения, внесенные в старую ревизию, и затем зафиксировать новую ревизию. Это называется обратным слиянием.
Допустим, Джерри добавляет код для операции линейного поиска. После проверки он фиксирует свои изменения.
[jerry@CentOS trunk]$ svn diff Index: array.c =================================================================== --- array.c (revision 21) +++ array.c (working copy) @@ -2,6 +2,16 @@ #define MAX 16 +int linear_search(int *arr, int n, int key) +{ + int i; + + for (i = 0; i < n; ++i) + if (arr[i] == key) + return i; + return -1; +} + void bubble_sort(int *arr, int n) { int i, j, temp, flag = 1; [jerry@CentOS trunk]$ svn status ? array M array.c [jerry@CentOS trunk]$ svn commit -m "Added code for linear search" Sending trunk/array.c Transmitting file data . Committed revision 22.
Джерри любопытно, что делает Том. Поэтому он проверяет сообщения журнала Subversion.
[jerry@CentOS trunk]$ svn log
Приведенная выше команда даст следующий результат.
------------------------------------------------------------------------ r5 | tom | 2013-08-24 17:15:28 +0530 (Sat, 24 Aug 2013) | 1 line Add binary search operation ------------------------------------------------------------------------ r4 | jerry | 2013-08-18 20:43:25 +0530 (Sun, 18 Aug 2013) | 1 line Add function to accept input and to display array contents
Просматривая сообщения журнала, Джерри понимает, что совершил серьезную ошибку. Потому что Том уже реализовал операцию двоичного поиска, которая лучше, чем линейный поиск; его код избыточен, и теперь Джерри должен вернуть свои изменения в предыдущую версию. Итак, сначала найдите текущую ревизию хранилища. В настоящее время репозиторий находится в редакции 22, и мы должны вернуть его к предыдущей редакции, то есть редакции 21.
[jerry@CentOS trunk]$ svn up At revision 22. [jerry@CentOS trunk]$ svn merge -r 22:21 array.c --- Reverse-merging r22 into 'array.c': U array.c [jerry@CentOS trunk]$ svn commit -m "Reverted to revision 21" Sending trunk/array.c Transmitting file data . Committed revision 23.
Том решает добавить файл README для своего проекта. Поэтому он создает файл README и добавляет в него список TODO. После добавления этого файла хранилище находится в редакции 6.
[tom@CentOS trunk]$ cat README /* TODO: Add contents in README file */ [tom@CentOS trunk]$ svn status ? README [tom@CentOS trunk]$ svn add README A README [tom@CentOS trunk]$ svn commit -m "Added README file. Will update it's content in future." Adding trunk/README Transmitting file data . Committed revision 6.
Джерри проверяет последний код, который находится в редакции 6. И сразу же он начинает работать. Через несколько часов Том обновляет файл README и фиксирует свои изменения. Модифицированный README будет выглядеть следующим образом.
[tom@CentOS trunk]$ cat README * Supported operations: 1) Accept input 2) Display array elements [tom@CentOS trunk]$ svn status M README [tom@CentOS trunk]$ svn commit -m "Added supported operation in README" Sending trunk/README Transmitting file data . Committed revision 7.
Сейчас хранилище находится на 7-й редакции, а рабочая копия Джерри устарела. Джерри также обновляет файл README и пытается зафиксировать свои изменения.
Файл README Джерри выглядит следующим образом.
[jerry@CentOS trunk]$ cat README * File list 1) array.c Implementation of array operation. 2) README Instructions for user. [jerry@CentOS trunk]$ svn status M README [jerry@CentOS trunk]$ svn commit -m "Updated README" Sending trunk/README svn: Commit failed (details follow): svn: File or directory 'README' is out of date; try updating svn: resource out of date; try updating
Шаг 1: Просмотр конфликтов
Subversion обнаружила, что файл README изменился с момента последнего обновления. Итак, Джерри должен обновить свою рабочую копию.
[jerry@CentOS trunk]$ svn up Conflict discovered in 'README'. Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options:
Subversion жалуется, что существует конфликт с файлом README, и Subversion не знает, как решить эту проблему. Поэтому Джерри выбирает опцию df для рассмотрения конфликта.
[jerry@CentOS trunk]$ svn up Conflict discovered in 'README'. Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: df --- .svn/text-base/README.svn-base Sat Aug 24 18:07:13 2013 +++ .svn/tmp/README.tmp Sat Aug 24 18:13:03 2013 @@ -1 +1,11 @@ -/* TODO: Add contents in README file */ +<<<<<<< .mine +* File list + +1) array.c Implementation of array operation. +2) README Instructions for user. +======= +* Supported operations: + +1) Accept input +2) Display array elements +>>>>>>> .r7 Select: (p) postpone, (df) diff-full, (e) edit, (r) resolved, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options:
Шаг 2: отложить конфликты
Далее Джерри выбирает параметры отсрочки (p) , чтобы он мог разрешить конфликт.
Select: (p) postpone, (df) diff-full, (e) edit, (r) resolved, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: p C README Updated to revision 7. Summary of conflicts: Text conflicts: 1
После открытия README в текстовом редакторе он понимает, что Subversion включил и код Тома, и его код с маркерами конфликта.
[jerry@CentOS trunk]$ cat README <<<<<<< .min * File list 1) array.c Implementation of array operation. 2) README Instructions for user. ======= * Supported operations: 1) Accept input 2) Display array elements >>>>>>> .r7
Джерри хочет изменений Тома так же, как и его, поэтому он просто удаляет строки, содержащие маркеры конфликта.
Итак, модифицированный файл README будет выглядеть следующим образом.
[jerry@CentOS trunk]$ cat README * File list 1) array.c Implementation of array operation. 2) README Instructions for user. * Supported operations: 1) Accept input 2) Display array elements
Джерри разрешил конфликт и он повторил коммит.
[jerry@CentOS trunk]$ svn commit -m "Updated README" svn: Commit failed (details follow): svn: Aborting commit: '/home/jerry/project_repo/trunk/README' remains in conflict [jerry@CentOS trunk]$ svn status ? README.r6 ? README.r7 ? README.mine C README
Шаг 3: Разрешить конфликты
В приведенном выше коммите буква C указывает на наличие конфликта в файле README. Джерри разрешил конфликт, но не сказал Subversion, что он разрешил конфликт. Он использует команду разрешения, чтобы сообщить Subversion о разрешении конфликта.
[jerry@CentOS trunk]$ svn resolve --accept=working README Resolved conflicted state of 'README' [jerry@CentOS trunk]$ svn status M README [jerry@CentOS trunk]$ svn commit -m "Updated README" Sending trunk/README Transmitting file data . Committed revision 8.
Теги SVN
Система контроля версий поддерживает работу с тегами , используя такую концепцию, что можно дать осмысленное имя конкретной версии кода. Тэг позволяет дать описательные и запоминающиеся имена для конкретной версии кода. Например, BASIC_ARRAY_OPERATIONS более запоминающимся, чем редакция 4 .
Давайте посмотрим на работу тега с примером. Том решает создать тег, чтобы ему было легче получать доступ к коду.
[tom@CentOS project_repo]$ svn copy --revision=4 trunk/ tags/basic_array_operations
Выше команда даст следующий результат.
A tags/basic_array_operations/array.c Updated to revision 4. A tags/basic_array_operations
После успешного завершения новый каталог будет создан внутри каталога тегов .
[tom@CentOS project_repo]$ ls -l tags/ total 4 drwxrwxr-x. 3 tom tom 4096 Aug 24 18:18 basic_array_operations
Том хочет перепроверить это перед фиксацией. Операция состояния показывает, что операция с тегом прошла успешно, поэтому он может безопасно зафиксировать свои изменения.
[tom@CentOS project_repo]$ svn status A + tags/basic_array_operations [tom@CentOS project_repo]$ svn commit -m "Created tag for basic array operations" Adding tags/basic_array_operations Committed revision 5.
SVN Ветвление
Работа филиала создает другую линию развития. Это полезно, когда кто-то хочет, чтобы процесс разработки проходил в двух разных направлениях. Допустим, вы выпустили продукт версии 1.0, возможно, вы захотите создать новую ветку, чтобы разработка 2.0 могла быть отделена от исправлений ошибок 1.0.
В этом разделе мы увидим, как создавать, обходить и объединять ветки. Джерри не счастлив из-за конфликта, поэтому он решает создать новую частную ветвь.
[jerry@CentOS project_repo]$ ls branches tags trunk [jerry@CentOS project_repo]$ svn copy trunk branches/jerry_branch A branches/jerry_branch [jerry@CentOS project_repo]$ svn status A + branches/jerry_branch [jerry@CentOS project_repo]$ svn commit -m "Jerry's private branch" Adding branches/jerry_branch Adding branches/jerry_branch/README Committed revision 9. [jerry@CentOS project_repo]$
Сейчас Джерри работает в своем частном филиале. Он добавляет операцию сортировки для массива. Модифицированный код Джерри выглядит следующим образом.
[jerry@CentOS project_repo]$ cd branches/jerry_branch/ [jerry@CentOS jerry_branch]$ cat array.c
Приведенная выше команда даст следующий результат.
#include <stdio.h> #define MAX 16 void bubble_sort(int *arr, int n) { int i, j, temp, flag = 1; for (i = 1; i < n && flag == 1; ++i) { flag = 0; for (j = 0; j < n - i; ++j) { if (arr[j] > arr[j + 1]) { flag = 1; temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } void accept_input(int *arr, int n) { int i; for (i = 0; i < n; ++i) scanf("%d", &arr[i]); } void display(int *arr, int n) { int i; for (i = 0; i < n; ++i) printf("|%d| ", arr[i]); printf("\n"); } int main(void) { int i, n, key, ret, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); /* Error handling for array overflow */ if (n >MAX) { fprintf(stderr, "Number of elements must be less than %d\n", MAX); return 1; } printf("Enter the elements\n"); accept_input(arr, n); printf("Array has following elements\n"); display(arr, n); printf("Sorted data is\n"); bubble_sort(arr, n); display(arr, n); return 0; }
Джерри компилирует и тестирует свой код и готов принять его изменения.
[jerry@CentOS jerry_branch]$ make array cc array.c -o array [jerry@CentOS jerry_branch]$ ./array
Приведенная выше команда даст следующий результат.
Enter the total number of elements: 5 Enter the elements 10 -4 2 7 9 Array has following elements |10| |-4| |2| |7| |9| Sorted data is |-4| |2| |7| |9| |10| [jerry@CentOS jerry_branch]$ svn status ? array M array.c [jerry@CentOS jerry_branch]$ svn commit -m "Added sort operation" Sending jerry_branch/array.c Transmitting file data . Committed revision 10.
Тем временем в багажнике Том решает выполнить операцию поиска. Том добавляет код для операции поиска, и его код выглядит следующим образом.
[tom@CentOS trunk]$ svn diff
Приведенная выше команда даст следующий результат.
Index: array.c =================================================================== --- array.c (revision 10) +++ array.c (working copy) @@ -2,6 +2,27 @@ #define MAX 16 +int bin_search(int *arr, int n, int key) +{ + int low, high, mid; + + low = 0; + high = n - 1; + mid = low + (high - low) / 2; + + while (low <= high) { + if (arr[mid] == key) + return mid; + if (arr[mid] > key) + high = mid - 1; + else + low = mid + 1; + mid = low + (high - low) / 2; + } + + return -1; +} + void accept_input(int *arr, int n) { int i; @@ -22,7 +43,7 @@ int main(void) { - int i, n, arr[MAX]; + int i, n, ret, key, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); @@ -39,5 +60,16 @@ printf("Array has following elements\n"); display(arr, n); + printf("Enter the element to be searched: "); + scanf("%d", &key); + + ret = bin_search(arr, n, key); + if (ret < 0) { + fprintf(stderr, "%d element not present in array\n", key); + return 1; + } + + printf("%d element found at location %d\n", key, ret + 1); + return 0; }
После проверки он фиксирует свои изменения.
[tom@CentOS trunk]$ svn status ? array M array.c [tom@CentOS trunk]$ svn commit -m "Added search operation" Sending trunk/array.c Transmitting file data . Committed revision 11.
Но Тому любопытно, что Джерри делал в своей частной ветке.
[tom@CentOS trunk]$ cd ../branches/ [tom@CentOS branches]$ svn up A jerry_branch A jerry_branch/array.c A jerry_branch/README [tom@CentOS branches]$ svn log ------------------------------------------------------------------------ r9 | jerry | 2013-08-27 21:56:51 +0530 (Tue, 27 Aug 2013) | 1 line Added sort operation ------------------------------------------------------------------------
Просматривая лог-сообщение Subversion, Том обнаружил, что Джерри реализовал операцию сортировки. Том реализовал операцию поиска, используя алгоритм двоичного поиска, он всегда ожидает данные в отсортированном порядке. Но что, если пользователь предоставляет данные в несортированном порядке? В этой ситуации операция двоичного поиска не будет выполнена. Поэтому он решает взять код Джерри для сортировки данных перед операцией поиска. Поэтому он просит Subversion объединить код из ветви Джерри в транк.
[tom@CentOS trunk]$ pwd /home/tom/project_repo/trunk [tom@CentOS trunk]$ svn merge ../branches/jerry_branch/ --- Merging r9 through r11 into '.': U array.c
После слияния массив array.c будет выглядеть следующим образом.
[tom@CentOS trunk]$ cat array.c
Приведенная выше команда даст следующий результат.
#include <stdio.h> #define MAX 16 void bubble_sort(int *arr, int n) { int i, j, temp, flag = 1; for (i = 1; i < n && flag == 1; ++i) { flag = 0; for (j = 0; j < n - i; ++j) { if (arr[j] > arr[j + 1]) { flag = 1; temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } int bin_search(int *arr, int n, int key) { int low, high, mid; low = 0; high = n - 1; mid = low + (high - low) / 2; while (low <= high) { if (arr[mid] == key) return mid; if (arr[mid] > key) high = mid - 1; else low = mid + 1; mid = low + (high - low) / 2; } return -1; } void accept_input(int *arr, int n) { int i; for (i = 0; i < n; ++i) scanf("%d", &arr[i]); } void display(int *arr, int n) { int i; for (i = 0; i < n; ++i) printf("|%d| ", arr[i]); printf("\n"); } int main(void) { int i, n, ret, key, arr[MAX]; printf("Enter the total number of elements: "); scanf("%d", &n); /* Error handling for array overflow */ if (n > MAX) { fprintf(stderr, "Number of elements must be less than %d\n", MAX); return 1; } printf("Enter the elements\n"); accept_input(arr, n); printf("Array has following elements\n"); display(arr, n); printf("Sorted data is\n"); bubble_sort(arr, n); display(arr, n); printf("Enter the element to be searched: "); scanf("%d", &key); ret = bin_search(arr, n, key); if (ret < 0) { fprintf(stderr, "%d element not present in array\n", key); return 1; } printf("%d element found at location %d\n", key, ret + 1); return 0; }
После компиляции и тестирования Том фиксирует свои изменения в хранилище.