coub css express.js freeware git jquery laravel links linux macos mysql node.js php PostgreSQL python task1 ubuntu vim virtualbox анекдот игры интересно музыка стихи цитаты

Ситуация 1: коммит уже сделан, но пуш ещё НЕ сделан. Обнаружилось что в предыдущий коммит нужно добавить какие-то правки, или что-то убрать из него например. Можно сбросить индекс для последнего коммита в текущей рабочей версии вот так
git reset --soft HEAD^
В таком варианте все изменения в файлах сохранятся (их покажет git status), будет сброшен только последний коммит. Теперь поправим все что нужно и закоммитим все снова, с новым комментарием.
Ситуация 2: кривой коммит сделан и уже отправлен на удаленный репозиторий (после push уже). Коммит этот надо откатить. Можно вообще-то исправить и закоммитить исправления, но мы допустим хотим просто полностью убрать этот кривой коммит чем быстрее тем лучше. Например коммит был сделан в неправильную ветку по ошибке.
# смотрим лог (%h покажет нам хэш коммита в логе)
git log -20 --pretty='%h %an %ar %s'
# делаем коммит с откатом 12f42c8 - это пример хэша
git revert 12f42c8
# пушим этот коммит
git push
Теперь в логе увидим сначала наш кривой коммит, а потом коммит с его (плохого коммита) откатом. См. git help revert
git

Бывает по запарке удаляешь что-то не то из рабочей папки под контролем git. Обычно чтобы просто откатить состояние файла до исходного в текущей версии (даже после ручного удаления), нужно сделать такой чекаут
git checkout -- file_name.ext
В нашем же случае удаление делалось через git rm и так просто счекаутить обратно состояние уже не получится, поскольку git же думает что мы специально файл удалили. Эта проблема возникает иногда из-за того, что умная IDE сама дописывает удаления (и добавления) файлов в git, оставляя нам только ручные коммиты и пуши. Поэтому надо сделать сначала ресет файла в индексе, а уже потом чекаут (см. git help reset)
git reset -- file_name.ext
git checkout -- file_name.ext
Кстати если до коммита вы решили что какой-то файл вы добавили по ошибке (после git add но до коммита), такой же ресет поможет убрать его из следующего коммита. Для папок работает все тоже самое.
git

В очередной раз напоминаю, что я не профессиональный администратор и возможно приведенный ниже вариант не отличается правильностью и безопасностью. Единственное за что я могу поручиться - этот вариант рабочий. Кроме того, здесь не пойдет речь о разделении прав внутри репозитория или репозиториев, все репозитории созданные по такому шаблону будут доступны для всех пользователей, которые будут иметь доступ к отладочному серверу и будут находиться в группе доступа к git. Я пишу о настройке под Debian.

Исходные
  1. Есть NN разработчиков
  2. Есть сервер на котором эти разработчики все вместе трудятся каждый под своей учетной записью
  3. Необходимо на этом сервере разместить git репозиторий с общим доступом для всех этих разработчиков
Порядок действий
  1. Создаем отдельного пользователя
    useradd git
    
    Задаем ему зубодробильный пароль и радостно забываем его.
  2. Теперь надо авторизоваться под этим пользователем (вообще можно и от рута все сделать, но так проще будет) и создать первый общий репозиторий
    su -l git # авторизуемся как пользователь git (тут по идее нужен рутовый пароль)
    mkdir my-repo-name # создаем папку под репозиторий
    chmod 770 my-repo-name # полный доступ владельцу и группе
    chmod +s my-repo-name # устанавливаем в этой папке наследование прав для группы
    cd my-repo-name # заходим в папку репозитория
    git init --bare --shared # инициализировали репозиторий (см. git help init)
    
    С репозиторием все. Теперь нужно раздать доступ.
  3. Всех пользователей, которые будут иметь доступ к git нужно добавить в соответствующую группу. Для этого поглядим что за группа у пользователя git
    whoami # git
    groups # git
    
    Теперь каждого кому нужен доступ в git добавляем в эту группу, делать это нужно с рутовыми привилегиями понятное дело
    usermod -a -G git user_login # добавляем пользователя в группу (см. usermod --help)
    
    Если решим у пользователя доступ к git отобрать надо будет просто его убрать из этой группы, вот так:
    deluser user_login git # удаляем пользователя из группы (см. deluser --help)
    groups user_login # смотрим в каких группах сейчас выбранный пользователь состоит
    
Все, по паролю доступ к git уже есть, то есть вот в такой манере
mkdir test-repo # создали папку под репозиторий
cd test-repo # зашли в неё
git clone ssh://user_login@my-host.com/home/git/test-repo . # клонируем репозиторий
git remote -v # куда смотрит локальный репозиторий (см. git --help remote)
Правда, при каждом push или pull запросе нужно будет вводить пароль. Казалось бы и так нормально, но..

ЕСТЬ СПОСОБ УДОБНЕЕ :)

Чтобы не вводить на каждый pull или push пароль, можно прикрутить доступ по публичному ключу. Для этого каждый разработчик должен сгенерить на своей локальной машине публичный ключ и прислать его нам. Сделать это можно так
ssh-keygen -t rsa # тут нас попросят задать имя ключа и ключевую фразу, нужно её запомнить
После этой процедуры сгенерится два ключа ~/.ssh/key-name и ~/.ssh/key-name.pub который собственно и является публичным ключем. Вот эти публичные ключи и должны прислать вам разработчики. Теперь на сервере их нужно добавить к авторизованным ключам для пользователя git.
su -l git # заходим под пользователем гита
cd ~ # переходим в домашнюю папку
mkdir .ssh # создаем папку для конфигов если её нет
cat key-name.pub >> .ssh/authorized_keys # добавляем в конец файла авторизованных ключей
Теперь на стороне разработчика нужно один раз авторизоваться с указанием конкретного ключа
ssh git@dev-host.com -i ~/.ssh/key-name # попросят ввести пароль от ключа, который был задан при генерации
Все, после этой процедуры постоянно вводить пароль для авторизации не потребуется. Все разработчики будут авторизовываться по ключу как пользователь git, а значит заморока с наследованием прав на папки больше не нужна. И теперь для добавления нового репозитория достаточно просто сделать следующее
su -l git # вошли как пользователь git
cd ~ # перешли в хомяк
mkdir new-repo # папка под репозиторий
cd new-repo # зашли в папку
git init --bare # создали пустой репозиторий
Такой репозиторий тут же станет доступен всем пользователям которые ходят по публичному ключу. Для разработчиков это будет выглядеть вот так:
mkdir new-project
cd new-project
git clone git@dev-host.com:new-repo .
Осталось добавить, что нужно репозитории регулярно резервировать, "во избежание" так сказать. Чтобы отобрать у пользователя доступ к гиту во втором случае (с публичным ключем), нужно определить его публичный ключ и удалить его из ~/.ssh/authorized_keys на сервере. Все ключи подписаны, так что возможно получится вычислить его по подписи. Если же не удастся.. то придется либо перезаписывать всем доступы, либо последовательно их отключать и смотреть у кого отвалится доступ. Как-то так :) В заметке нет ничего нового, почти все это можно прочитать здесь и здесь.
p.s.: хорошо бы заглушить вход в консоль для пользователя git.
sudo vim /etc/passwd
Ищем строку вида: git:x:1000:1000::/home/git:/bin/sh и приводим её к вот такому виду git:x:1000:1000::/home/git:/usr/bin/git-shell. Надо это затем, чтобы пользователь git не мог зайти в консоль и погрохать все репозитории, например.
git

Все приличные команды разработки работают с таск-трекерами, сейчас как мне кажется стандартом стал Jira (ну или другой трекер, суть та же для примера). Поэтому здесь для примера буду писать "таск" или "тикет" подразумевая задачу в Jira. Хорошим тоном сейчас считается указание идентификатора таска в каждом коммите который для решения этого таска делается. Не претендую на истину в последней инстанции, но как один из возможных вариантов опишу здесь свой опыт. Могу дополнить только что для SVN пользовался практически той же схемой, за исключением того, что ветвление на каждую задачу значительно безопаснее как мне кажется, но об этом ниже.

Итого:
  1. В команде есть NN разработчиков
  2. Все разработчики используют единый репозиторий git
  3. В репозитории существуют две (может быть для каких-то целей и больше) основные ветки master и dev
  4. Ветка master существует исключительно для стабильных версий продукта, работающих только в боевой (продакшн) зоне. То есть эта ветка считается последней стабильной версией ПО с которой работают конечные пользователи. Перед каждым релизом на эту ветку ставится тег, с которого собственно и выкатывается стабильная версия. В случае каких-то проблем на боевой откатывается на предыдущий стабильный тег этой ветки (если такой откат возможен конечно после внесенных изменений в БД или какие-то другие жизненно важные части по).
  5. Ветка dev (development) служит для аккумулирования изменений всех разработчиков и собственно обмена последними стабильными изменениями между разработчиками.
  6. Для каждой новой задачи разработчик создает новую ветку от текущей dev и работает в ней, с нее же получая для своей задачи обновления по необходимости
  7. При передаче в тест разработчик синхронизирует свою ветку с текущей dev и отдает на тестирование свою задачу именно на ветке этой задачи
  8. После тестирования разработчик мерджит свою ветку в dev и либо сам проверяет что ничего не сломалось уже на dev либо это опять проверяют тестеры
  9. Перед релизом dev ветка мерджится на master, после чего на мастере ставится тег с которого производится деплой свежего релиза
Вот таким вот нехитрым способом все происходит. Схема вполне рабочая, но возможно можно что-то улучшить, сейчас - как есть.
Что касается git, то описанный процесс происходит примерно так:
  1. Клонируем репозиторий в папку (если необходимо)
    cd /my/project/folder
    git clone ssh://luke@tatuin.com/git/project-repo .
    
  2. Переключаемся на dev ветку и обновляем ее
    git checkout dev
    git pull origin dev
    
  3. Ветвимся от dev в ветку под конкретную задачу (для примера имя ветки здесь это ключ от таска в Jira)
    git checkout -b task-123
    git status
    
    Статус должен показать что вы теперь на ветке task-123
  4. Теперь спокойно работаем на этой ветке и все коммиты по задаче идут на неё
    git commit -am 'task-123 my task commit'
    
  5. Если задача затянулась, то можно подтянуть на ветку обновления от других разработчиков
    git pull origin dev
    
    Для того чтобы сделать pull в этой ситуации, нужно либо все свои изменения закомитить на ветку, либо воспользоваться git stash чтобы спрятать свои изменения, а потом git stash apply чтобы достать свои изменения назад. При каждом коммите нужно тщательно смотреть diff.
  6. Когда задача закончена, и все коммиты по ней отправлены на соответствующую ветку отправляем свою ветку в общий репозиторий
    git push origin task-123
    
    Таким образом ветка станет доступна другим разработчикам и тестерам. Все, в этот момент останавливаем прогресс в таск-трекере и передаем задачу в тестирование.
  7. Посмотреть все лоакльные ветки можно вот так
    git branch
    
    Посмотреть все ветки в удаленном репозитории можно вот так
    git remote show origin
    
  8. Теперь задачу нам вернули из теста, с ней все хорошо, нужно вмерджить свои изменения в dev ветку
    git checkout dev
    git pull origin dev
    git merge task-123
    
    Тут мы переключаемся на dev ветку, обновляем её содержимое из удаленного репозитория и собственно мерджим в ветку dev свою ветку task-123. При необходимости все конфликты разрешаем ручками и коммитим, но уже на dev. Теперь осталось только отправить наши изменения на dev-e в удаленный репозиторий
    git push origin dev
    
  9. Теперь желательно прибрать за собой, то есть убрать больше не нужные ветки. Сначала удалим ветку из удаленного репозитория
    git push origin :task-123
    
    А теперь ветку в локальном репозитории
    git branch -d task-123
    
На этом собственно и все. В начале работы по такой схеме часто возникают типовые ошибки:
  • Работа на другой ветке (забыл переключиться в спешке), тут может выручить stash. С его помощью можно спрятать изменения, а потом выложить их на другой ветке после переключения на неё, важно внимательно смотреть в diff при коммитах чтобы не потереть чужое.
  • Пуш в другую ветку, тут нужно просто быть внимательным при каждом push-e.
  • Ошибки связанные с мерджем, тут тоже нужно помнить что нужно сначала перейти в ветку в которую будем мерджить свои изменения, а уже потом мерджить в неё свою ветку. Нужно просто быть внимательным.
При внешней сложности через пару недель все это прочно оседает в голове и делается почти автоматически. Важно просто быть внимательным в начале работы по этой схеме чтобы не наломать дров в общем репозитории. Особо внимательно стоит смотреть на диффы и во время пушей, что, откуда и куда пушим. Если не сильно торопиться то проблем не будет.
git

Смотрим все прятки
git stash list
это нам даст список вида
stash@{0}: lalala
stash@{1}: lalala
stash@{2}: lalala
Чтобы посмотреть файлы лежащие в конкретном стэше
git stash show stash@{2}
Чтобы посмотреть правки в этих файлах делаем так
git stash show -p stash@{2}
Ну и чтобы применить выбранный стэш
git stash apply stash@{2}
Еще подробности тут и тут
git

Want this blog? Checkout that  here