среда, 20 ноября 2013 г.

Git и Bitbucket за 20 минут


Git - распределенная система контроля версий файлов, созданная под руководством Линуса Торвальдса. Системы контроля версий позволяют хранить несколько версий одних и тех же файлов с возможностью возврата к старому варианту, просмотра изменений, их авторов и т.д.

Распределенная система контроля версий не нуждается в центральном сервере, хранящем версии, вся история хранится на каждом локальном компьютере и при необходимости синхронизируется с аналогичным хранилищем другого компьютера. В этом отличие Git от, например, SVN - можно установить Git только на локальный компьютер и хранить все версии у себя, не дублируя на сервер. Однако в случае командной работы все же удобно иметь сервер, хранящий версии. Такой сервер также можно воспринимать как бэкап всех актуальных файлов и их версий, доступный из любой точки мира.

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

Здесь я приведу краткие данные, позволяющие быстро начать работу с Git и Bitbucket. Bitbucket - это сервис, централизованно хранящий репозитории Git, бесплатный для 5 пользователей и платный для больших команд. Преимущество Bitbucket перед аналогичным сервисом GitHub - возможность создания закрытых репозиториев (не open source).


Установка, настройка


Итак, первое, что нам стоит сделать - установить сам Git для используемой операционной системы (Windows, Linux, Solaris, Mac OS). Второе - зарегистрироваться на Bitbucket и создать репозиторий.

Предположим, что у нас уже есть исходные коды разрабатываемого приложения и мы хотим начать использовать Git для контроля версий и централизованного их хранения на сервере Bitbucket.

Пройдя регистрацию на Bitbucket, создаем новый репозиторий, для чего выбираем Repositories > Create repository. Вводим имя создаваемого репозитория, указываем тип (Git), уровень доступа (Access level) в private - не open source проект. Также можно установить основной язык программирования, используемый в проекте. Завершив создание репозитория, Bitbucket отобразит страницу «Add some code», где мы выберем «I have an existing project to push up» для добавления существующего проекта в репозиторий, после чего система отобразит команды, которые нам необходимо будет выполнить для последующей синхронизации локального репозитория с Bitbucket - не закрывайте окно.

Итак, мы создали репозиторий на Bibucket, теперь необходимо создать локальный репозиторий на локальном компьютере, чтобы впоследствии синхронизировать его с Bitbucket. Для этого мы будем использовать терминальные команды Git, поэтому в случае Windows необходимо добавить в переменную окружения PATH путь к исполняемым файлам Git (как правило, это C:\Program Files (x86)\Git\bin), в случае Linux и Mac OS система уже сделала это за вас при установке.

Таким образом, на текущем этапе у нас установлен Git и в переменной окружения PATH корректно прописан путь к исполняемым файлам Git - неплохо. Открываем терминал/командную строку нашей операционной системы (конечно, для Git существуют и GUI решения, но в этой статье я буду касаться только классических терминальных инструментов).

В первую очередь настроим наш Git - зададим своё имя и email (эта информация будет использоваться в репозитории для отслеживания авторов изменений):

git config --global user.name "Alexey Goloburdin"
git config --global user.email my@mail.com
git config --global core.pager 'less -r'

Теперь всё готово к созданию первого локального Git репозитория.

Создание репозитория


Переходим в терминале в директорию, в которой мы хотим создать репозиторий - директорию с исходными кодами нашего приложения - и инициализируем новый репозиторий:

git init

Добавляем все файлы в созданный репозиторий:

git add *

И делаем commit - то есть сохранение текущей версии репозитория:

git commit -m 'первая версия репозитория'

После атрибута -m вводится комментарий к коммиту - хорошей практикой является описание всех коммитов.

За жизнь


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

Все отслеживаемые файлы могут находиться в трех состояниях - неизмененном (то есть с момента последнего коммита мы этот файл не трогали), измененном (с момента последнего коммита мы внесли изменения, но Git об этом еще не знает) или подготовленном к коммиту (это измененный файл, о котором мы рассказали Git). Таким образом, вот жизненный цикл файла в репозитории:

1. Добавление файла в репозиторий - файл имеет статус «неизмененный»
2. Файл изменен, но мы не сообщили об этом Git - файл имеет статус «измененный»
3. Мы сообщаем соответствующей командой Git об изменении файла - файл получает статус «подготовленного к коммиту»
4. Мы делаем коммит, после которого файл снова получает статус «неизменённого». Затем цикл повторяется.

При этом важно понимать, что все эти действия сейчас происходят локально на нашем компьютере, хранящем все версии репозитория, мы еще не производили синхронизацию с удаленным сервером Bitbucket.

Работа с Git


Итак, в данный момент мы имеем чистый репозиторий с одной версией. Внесем изменения в какой-то файл репозитория и подготовим файл к коммиту:

git add FILENAME

Команда git add не только добавляет новый файл к репозиторию, но и отслеживает изменения в уже присутствующих в репозитории файлах. Сделаем второй коммит:

git commit -m 'вторая версия, мы внесли офигенные правки в наш проект'

Конечно, совсем необязательно запоминать все файлы, в которых мы произвели изменения с последнего коммита для того, чтобы потом перечислить их в git add (то есть подготовить к коммиту). Есть два варианта. Первый: использовать "git add *" и затем "git commit", второй короче: использовать сразу одну команду "git commit -a". В обоих случаях Git переберет все файлы каталога и подготовит к коммиту все отслеживаемые файлы, но первый вариант также добавит в репозиторий новые файлы (созданные после последнего коммита), в то время как второй вариант их проигнорирует.

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

git rm FILENAME

Просто удаление файла в директории, без указания Git не отслеживать его, приведет к попыткам Git найти этот файл, его статус в репозитории будет «изменён, но не закоммичен». Конечно, можно удалять файлы из директории проекта, не заботясь о ручном удалении их из Git репозитория по одному - вместо этого можно выполнить одну команду:

git add -u

Кстати, узнать текущий статус по репозиторию можно командой

git status

Просмотреть историю коммитов:

git log

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

Синхронизация с Bitbucket

Как мы уже говорили, вся текущая работа с репозиторием происходила на локальном компьютере без подключения к серверу Bitbucket - пришло время синхронизироваться! Для этого нужно выполнить команды, которые сообщил нам Bitbucket после создания удаленного репозитория:
git remote add origin https://livedev@bitbucket.org/livedev/repositoryName.git
git push -u origin --all
Первая команда подключит удаленный репозиторий, вторая зальет на него наш локальный репозиторий. Система спросит пароль для подключения к Bitbucket, после чего загрузит репозиторий на сервер - в успехе можно удостовериться в веб-интерфейсе Bitbucket. Теперь мы можем продолжать работу над проектом, сохранять файлы, делать коммиты - они будут сохраняться в локальном репозитории даже без подключения к Интернет. Проводить синхронизацию с удаленным сервером не обязательно при каждом коммите - все коммиты все равно зальются на сервер при выполнении команды git push. Если мы работаем в команде и коммиты на сервер делает кто-то кроме нас, то перед коммитом нужно сначала загрузить все изменения, которые произвели другие члены команды в репозитории на сервере, для этого используется команда git pull:
git pull origin master
Master здесь - это ветка репозитория, с которой мы работаем, их может быть несколько, а origin - название соединения c Bitbucket. Таким образом, для заливки репозитория на сервер используется команда
git push origin master
а для обновления локального репозитория с сервера команда
git pull origin master
Крутых production версий вам!

39 комментариев:

  1. Спасибо за статью очень помогла !

    ОтветитьУдалить
  2. Алексей, спасибо за статью. А как привлечь пользователей гитхаба к своему проекту?

    ОтветитьУдалить
    Ответы
    1. Рад, что помогло. Привлечь пользователей гитхаба к своему проекту - задача более интересная, чем сам гит:) PR, публикации на ресурсах.

      Удалить
  3. Алексей, спасибо за статью. Скажите а как скачать себе все файлы? если я новый участник команды.

    ОтветитьУдалить
    Ответы
    1. Рад, что помогло!
      Все файлы можно скачать, выполнив команду git clone директории, в которой Вы хотите клонировать проект (=загрузить все файлы + все их версии) - она в Bitbucket находится в левом верхнем улгу в сайдбаре, когда вы в проекте, Actions-Clone.

      Второй вариант - в Bitbucket можно загрузить все файлы, не клонируя проект - загрузятся только последние версии, без истории. Когда вы в проекте, в левом сайдбаре кнопка Downloads.

      Удалить
  4. Писал вчера, по-моему не отправилось.
    У меня такая схема: есть главный репозиторий на BitBucket, и два сайта, главный и тестовый. Я на тестовом накодил, сделал коммиты, и что делать дальше? Как разместить коммиты на главный сайт?

    ОтветитьУдалить
    Ответы
    1. Денис, не понял вопрос. Главный и тестовый сайты - это разные ветки или одна ветка репозитория? Скорее всего, одна. Сведите их вместе просто.
      Есть репозиторий А (тестовый сайт), репозиторий B (главный сайт) и репозиторий Bitbucket - просто центральное хранилище всех версий. Закоммитьте все изменения на главном и тестовом сайтах, затем залейте возможные отличия от Bitbucket через git pull, затем обновите версию на самом Bitbucket через git push. Таким образом, в локальном и удаленном (bitbucket) репозиториях будет акутуальная текущая версия.

      Удалить
    2. Да, я недостаточно подробно описал суть.
      Есть главный репозиторий, созданный на BitBucket. Тестовый сайт и главный это идентичные копии. Через PHPStorm сайт был залит на локальный диск, туда же был добавлен GIT с BitBucket и был первый коммит со всеми файлами (за исключением не нужных, кэша, логов, картинок).
      Как-бы тестовый то я редактирую в PHPStorm по кусочкам и делаю коммиты на BitBucket. Но как быть с главным сайтом? Его я хочу не редактировать, а просто обновлять версиями. Неужели тоже надо будет делать проект, заливать весь оригинал, делать Pull и заливать через FTP? Должен ведь быть альтернативный вариант заливки версий на удаленный сервер.
      Да и потом, если надо будет реактивно откатиться, вряд ли в PHPStorm это можно будет назвать "реактивно". Более того, он у меня при Pull не сохраняет изменения в файлах и простым CTRL+S не отправляет файлы. Тут либо просматривать все возвращенные коммиты, запоминать файлы в них и заливать их на сервер, либо синхронизировать весь сайт.
      В общем хочется с сайтом также как по локалке: git checkout, и все изменилось. Насколько я слышал это можно сделать посредством входа на сервер по SSH.

      Удалить
  5. Интересное начало, но сразу же сталкиваюсь с проблемой: есть 2 папки, одна в локалхосте (где много других сайтов) и одна папка на уровень выше с логикой. Как их можно объединить в один проект?

    ОтветитьУдалить
    Ответы
    1. Положить в репозиторий папку самого высокого уровня. Все лежащие в ней папки так же окажутся в репозитории. Папки которые не нужно отслеживать внести в файл .gitignore И гит не будет о них знать.

      Удалить
  6. Интересно и доступно. Спасибо.

    ОтветитьУдалить
  7. на компьютере, в папке проекта, при компиляции создаётся папка pkg, где хранятся файлы классов и тд, в общем файлы, которые на битбакете вовсе не нужны. Как мне перевести в неотслеживаемые именно этот каталог, весь. То есть чтобы при очередной коммите они не лились на битбакет?

    ОтветитьУдалить
    Ответы
    1. Это не проблема. Надо создать в корне проекта файл .gitignore (именно так - пустое название, расширение gitignore) и в него внести одну строку:
      /pkg/*

      Сохранить файл, добавить его в репозиторий (git add .gitignore), закоммитить (git commit -m "added gitignore"), после этого директория pkg будет игнорироваться Git'ом.

      Здесь много примеров для .gitignore: https://orlov.io/ru/articles/podrobnee-o-faile-gitignore+

      Удалить
    2. Большое спасибо, команда git add * не захватит каталог тоже? Я просто ею пользуюсь после внесения любых изменений в файлах

      Удалить
    3. Да, я тоже добавляю через *. Всё, что включено в .gitignore, не будет добавляться в репозиторий, будет игнорироваться. Если ненужная папка сейчас есть в репозитории - ее надо удалить через git -rm, потом добавить в репозиторий .gitignore, закоммитить, и больше она не будет появляться.

      Удалить
    4. Спасибо, всё сработало

      Удалить
  8. спасибо за статью, помогло :)

    ОтветитьУдалить
  9. Спасибо за статью... помогло разобраться быстро...

    ОтветитьУдалить
  10. Спасибо за статью... помогло разобраться быстро...

    ОтветитьУдалить
  11. Спасибо за статью... помогло бысрто разобраться

    ОтветитьУдалить
  12. Спасибо большое, очень помогло!!!

    ОтветитьУдалить
  13. единственный ман по гит/битбакет, из которого все понятно!
    статья в избранном.

    ОтветитьУдалить
  14. Отличная статья, разобрался. Спасибо!

    ОтветитьУдалить
  15. Подскажите пожалуйста как быть. У меня на bitbucket лежит тестовая версия, все изменения залетают туда. Как мне соединить тестовый сайт с рабочим через git или bitbucket???

    ОтветитьУдалить
    Ответы
    1. 1. Прочитайте всю статью:)
      2. На сервере с сайтом поставить гит, настроить его, как описано в статье, сделать git pull origin master

      Удалить
  16. Спасибо за статью! Очень помогло!

    ОтветитьУдалить
  17. Этот комментарий был удален автором.

    ОтветитьУдалить
  18. "Не занимайтесь хренью"

    я бы не сказал что на хабре супер статья, разве что ты ее написал и флудишь!
    автор норм пацан, классная статья!!! Спасибо, заделал меньше чем за 10 мин!

    ОтветитьУдалить
  19. Спасибо Автор ты супермегакруто всё объяснил что даже я понял)

    ОтветитьУдалить
  20. Этот комментарий был удален автором.

    ОтветитьУдалить
  21. Этот комментарий был удален автором.

    ОтветитьУдалить
  22. Привет! Спасибо за статью. А как быть если мне надо заливать проект с сервера и на git и на bitbucket. На git залил, но если пробую добавить remoute add origin для bitbucket, то получаю fatal: remote origin already exists

    ОтветитьУдалить
  23. не первый год юзаю именно эту инструкцию, спасибо автору!
    бывает всякое, иногда помогает инструкция битбакета.

    Разместите локальный репозиторий Git на Bitbucket
    Шаг 1. Перейдите в директорию репозитория

    cd /path/to/your/repo
    Шаг 2. Подключите свой репозиторий к Bitbucket

    git remote add origin https://alexGaydukow@bitbucket.org/alexGaydukow/ritualrgs.git
    git push -u origin master


    если косякнуть - бывает ошибка с origin - вот решение
    http://qaru.site/questions/18602/github-fatal-remote-origin-already-exists

    ОтветитьУдалить
  24. Пожалуй самая лучшая статья, которые я прочёл за последнюю неделю (изучая git).
    Спасибо автору, очень полезно и информативно

    ОтветитьУдалить
  25. Подскажите пожалуйста. У меня существует две папки с файлами (например папка "1" с файлом "1.json" и папка "2" с файлом "2.json" с содержимым в каждом файле например {"name" : "строка"}). Затем я добавляю в папку "1" файл "1_1.json" с содержимым {"name" : "строка"} и в папку "2" файл "2_2.json" с содержимым {"name" : "строка"} . После commit and push в битбакете после пулл реквеста во вкладке diff изменения следующие: в папке "1" файл "1_1.json" почему-то считается измененным файлом "1.json" (соответственно теперь вместо двух файлов "1" и "1_1" только "1_1"), а в папке "2" все как должно быть два файла "2.json" и "2_2.json" . Как определяется что файл изменен, хотя название разные, папки разные?

    ОтветитьУдалить