Git
================================================================================

Ссылки
------
  * Книга "Pro Git"
        http://progit.org/book/
  * Книга "Git Community Book"
        http://book.git-scm.com/
  * Книга "Git Magic"
        http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html
        перевод: http://habrahabr.ru/blogs/Git/80909/
  * Сравнение команд Git-SVN
        http://git.or.cz/course/svn.html
  * Редактирование истории в git
        http://gq.net.ru/2009/12/16/git-history-rewrite/


Установка
---------

  Win:
    http://code.google.com/p/msysgit/
    Надо везде указать UTF-8


Настройка
---------

  1. Отредактировать файл ~/.gitconfig
        [user]
            name  = Maxim Oleinik
            email = maxim.oleinik@gmail.com

        [color]
            diff   = auto
            status = auto
            branch = auto

        [alias]
            st = status
            ci = commit
            br = branch
            co = checkout
            di = diff
            plog = log --pretty=format:'%h %Cblue%cn %Creset%cr %Cgreen%s'

        [core]
            whitespace = trailing-space, space-before-tab, cr-at-eol

    Или использовать команду git config:
        git config --global user.name  "Maxim Oleinik"
        git config --global user.email "maxim.oleinik@gmail.com"

    !!! Далее все примеры будут использовать указанные алиасы.

  2. Чтобы игнорировать конфигурационные файлы личного IDE и других, которые не
     не должны фигурировать в .gitignore, указать все эти файлы в PROJECT_DIR/.git/info/exclude


Общее
-----

  # Утилита для просмотра дерева коммитов
  gitk --all &

  # Создать репозитарий в текущей директории
  git init

  # Клонировать существующий репозитарий
  git clone /path/to/repo
  git clone http://github.com/symfony/symfony.git

  # Игнорирование файлов
  Перечислить все в PROJECT_DIR/.gitignore

  # Полностью обновить свой репозитарий
  git fetch
  git fetch --tags
  git remote prune origin     # Убрать ссылки на удаленные ветки
  git co master
  git merge origin/master
  git submodule update --init # Обновить ссылки на субмодули


Рабочий процесс
---------------

  # показать статус - список измененных незакоммиченных файлов
  git st

  # Staged - промежуточный коммит
  git add <file>
  git add myFile*
  git add <dir1> <dir2> <file1>
  git add .
  git add -p      # добавлять правки чанками

  git rm          # удалить файл или диреткорию
  git mv          # перименовать файл
                  # фактически это 2 команды add NEW + rm OLD

  # Diff
  git di --cached # просмотреть изменения, которые будут закоммичены (добавлены как git add)
  git di          # просмотреть изменения, которые не "добавлены"
  git di HEAD     # просмотреть все измения
  git di -b -w    # посмотреть диф без учета пробелов

  # Новые файлы (не добавленные через git add) diff не показывает

  # Коммит
  git сi          # закоммитить изменения добавленные через git add
  git сi -a       # закоммитить все изменения
                  # новые файлы (не добавленные через git add) не коммитятся
  git сi <file1> <dir> - закоммитить указанные файлы (независимо от git add)

  # Откатить правки
  git co <file1> <dir>         # откатить не "добавленные" измения
  git reset HEAD <file1> <dir> # отменить git add


Ветки
-----

  git br    # показать список локальных веток
  git br -r # показать список веток внешнего репозитария

  git br my-branch           # создать ветку my-branch с текущей позиции
  git co -b my-branch master # создать ветку my-branch от master и переключиться на нее
  git co -b some-branch origin/some-branch # создать ветку some-branch из origin репозитария

  git br -d my-branch        # безопасно удалить ветку (смерджена в текущую)
  git br -D my-branch        # принудительно удалить ветку

  git co my-branch           # переключиться на указанную ветку

  # Merge

      A - B - C (master)
        \
          D - E (my-branch)

      git co master
      git merge my-branch

      A - B - C - F (master)
        \       /
          D - E  (my-branch)


  # Cherry-pick - положить указанный коммит в текущую ветку

      A - B - C (master)
        \
          D (my-branch)

      git co master
      git cherry-pick D

      A - B - C - D' (master)
        \
          D (my-branch)


  # Подтянуть ветку

      A - B - C (master)
        \
          D - E (my-branch)

      git co my-branch
      git rebase master

      A - B - C (master)
              \
                D - E  (my-branch)


  # Пененести ветку (поменять родителя)

      A - B - C (master)
        \
          D - E (branch-1)
              \
                F - G (branch-2)

      git co branch-2
      git rebase --onto master branch-1 branch-2

      A - B - C (master)
       \       \
        \       F - G (branch-2)
         \
          D - E (branch-1)


Работа с удаленным репозитарием
-------------------------------

  git remote    # см. git help remote

  git fetch     # загрузить изменения из внешнего репозитария
                # в локальный репозитарий изменения не применяются

  git pull origin master     # загрузить в ТЕКУЩУЮ ветку изменения из origin/master
                             # аналог git merge origin/master

  git push origin master     # отправить свои коммиты из local/master в origin/master
  git push origin my-branch  # экспортировать локальную ветку в my-branch в origin/master
  git push origin my-branch:remote-branch
                             # отправить правки из локальной ветки my-branch
                             # во внешнюю remote-branch

  git push origin :remote-branch  # удалить ветку `remote-branch` из внешнего репозитария

  # Удалить у себя все упоминания origin веток, которые кто-то уже удалил
  git remote prune origin


Управление коммитами, откат изменений
-------------------------------------
см. http://gq.net.ru/2009/12/16/git-history-rewrite/

  git revert HEAD     # создаст новый зеркальный коммит
  git commit --amend  # изменить сообщения последнего коммита

  # Откатить коммит, отредактировать и закоммитить заново
  git reset --soft HEAD^      # откатить последний коммит
  ... внести измения
  git commit                  # закоммитить

  # Объединить коммиты, удалить, изменить порядок
  git rebase -i HEAD~3  # последние 3 коммита
  # откроется редактор со списком коммитов с командой напротив каждого коммита
  # там есть справка, какие команды есть, и что они делают


Пример командной работы над задачей в отдельной ветке
-----------------------------------------------------

  # Обновить свой репозитарий
  git fetch
  git co master
  git merge origin/master

  # Создать ветку "t314-article-form" под текущую задачу и переключиться на нее
  git co -b t314-article-form
  # ... работа и коммиты в новой ветке

  # Пока работал, master уже ушел вперед, надо обновить свою локальную копию master
  git fetch
  git co master
  git merge origin/master

  # Обратно в ветку и подтянуть ее к мастеру
  git co t314-article-form
  git rebase master  # Подтянуть ветку к новым правкам,
                     # теперь ветка со всеми коммитами будет начинаться из новой точки

  # Отправить ветку в общий (origin) репозитарий на ревью
  git push origin t314-article-form

  # После ревью слить и удалить ненужную теперь ветку
  git co master
  git merge t314-article-form
  git br -d t314-article-form        # Удалить локальную ветку
  git push origin :t314-article-form # Удалить ветку из общего репозитария

  # Все участники команды по-прежнему видят удаленную ветку. Удаляют ссылки у себя:
  git remote prune origin


Stash
-----
см. git help shash

  Пример работы над 2 задачами с изпользованием stash

  # Сохранить текущие незакоммиченные правки, чтобы переключиться в другую ветку
  # для срочной работы
  git stash save my-stash-name

  # ... переключаемся в другую ветку, работаем там и возвращаемся обратно

  # Восстанавливаем спрятанные правки
  git stash apply  # поднимет последнее сохранение или указать имя
  git stash apply my-stash-name
  git stas clear   # полностью очистить всю хоронушку
    или
  git stash pop    # восстановить правки и удалить запись о них

  # Просмотреть список всех сохраненных состояний
  git stash list


История
-------

  git show - выводит информацию об объектах (коммитах, метках, деревьях и пр.)
    ---------
    git show            # показать последний коммит
    git show fb47ddb2   # показать указанный коммит
    git show HEAD^      # предыдущий коммит (второй с конца)
    git show HEAD^^     # третий коммит с конца
    git show HEAD~4     # пятый коммит с конца
    -- слияния
    git show HEAD^1     # show the first parent of HEAD
    git show HEAD^2     # show the second parent of HEAD
    ----
    git show my-branch:fs/locks.c # посмотреть версию конкретного файла

  git log - вывести список коммитов по условию
    ----
    git log v2.5..        # commits since (not reachable from) v2.5
    git log test..master  # commits reachable from master but not test
    git log master..test  # ...reachable from test but not master
    git log master...test # ...reachable from either test or master, but not both
    git log --since="2 weeks ago" # commits from the last 2 weeks
    git log Makefile      # commits which modify Makefile
    git log fs/           # ... which modify any file under fs/
    git log -S'foo()'     # commits which add or remove any file data
                          # matching the string 'foo()'
    ----
    git log origin/master..master # разница с внешним хранилищем - что надо закоммитить


Субмодули
---------
  см. git help submodule

  # Добавить субмодуль
  git submodule add http://github.com/maxim-oleinik/symfony-dev-rules ./doc/rules
  # Чтобы коммитить в субмодуль, надо изменить конфиг ./doc/rules/.git/config
  url = git@github.com:/maxim-oleinik/symfony-dev-rules.git

  # Обновить ссылки на субмодули
  git submodule update
  git submodule update --init

  # Выполнить указанную команду для каждого субмодуля
  git submodule foreach <command>
  git submodule foreach 'git st; exit 0'

  # Удалить субмодуль
    1. Удалить из .gitmodules
    2. Удалить из .git/config.
    3. Удалить файлы git rm --cached path/to/submodule
    4. Закоммитить результат

  # Обновить конфиг проекта, при переключении модуля на другой репозитарий
  git submodule sync


Прочее
------

  # Работа с тегами
  git help tag

  # Очистить все файлы и директории, которые не стоят под контролем
  git clean -fd
  git clean -fdx  # !!! Удалит все файлы перечисленные в .gitignore

  # Лог всех манипуляций с репозитарием. Здесь можно искать потерянные коммиты
  git reflog

  # Оптимизировать и перепаковать репозитарий
  git gc

  # Работа с патчами
  git format-patch HEAD~2       # Создать набор патчей от указанной точки
  git format-patch master..test
  git apply /path/to/patch/file # Применить патч
  git send-email patch_files    # Отправить набор патчей по email