Система версионного контроля GIT

Площадка для эксперементов

Логин: slavko.lht@gmail.com
Пароль: SqEmH8qR

Установка

Windows

Linux

yum install git-core
apt-get install git-core

Установка имени и электронной почты

git config --global user.name "Your Name"
git config --global user.email "your_email@whatever.com"

Параметры установки окончаний строк

для пользователей Unix/Mac

git config --global core.autocrlf input
git config --global core.safecrlf true

для пользователей Windows

git config --global core.autocrlf true
git config --global core.safecrlf true

Создайте страницу «Hello, World»

Начните работу с создания пустого каталога с именем «hello», затем войдите внего и создайте там файл с именем hello.html с таким содержанием.
mkdir hello
cd hello
echo 'Hello, World' > hello.html
Файл: hello.html
Hello, World

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

git init
$ git init
Initialized empty Git repository in /users/slavko/hello/.git/

Добавьте страницу в репозиторий

Теперь давайте добавим в репозиторий страницу «Hello, World».
git add hello.html
git commit -m "First Commit"
$ git add hello.html
$ git commit -m "First Commit"
[master (root-commit) 911e8c9] First Commit
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 hello.html
		

Измените страницу «Hello, World»

Добавим кое-какие HTML-теги к нашему приветствию. Измените содержимое файла на:
Файл: hello.html
<h1>Hello, World!</h1>

Проверьте состояние

Теперь проверьте состояние рабочего каталога
git status
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   hello.html
#
no changes added to commit (use "git add" and/or "git commit -a")
Первое, что нужно заметить, это то, что git знает, что файл hello.html был изменен, но при этом эти изменения еще не зафиксированы в репозитории. Также обратите внимание на то, что сообщение о состоянии дает вам подсказку о том, что нужно делать дальше. Если вы хотите добавить эти изменения в репозиторий, используйте команду git add В противном случае используйте команду git сheckout для отмены изменений.

Добавьте изменения - Индексация

Теперь дайте команду git проиндексировать изменения. Проверьте состояние
git add hello.html
git status
$ git add hello.html
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	modified:   hello.html
#
Изменения файла hello.html были проиндексированы. Это означает, что git теперь знает об изменении, но изменение пока не перманентно (читай, навсегда) записано в репозиторий. Следующий коммит будет включать в себя проиндексированные изменения. Если вы решили, что не хотите коммитить изменения, команда состояния напомнит вам о том, что с помощью команды git reset можно снять индексацию этих изменений.

Фиксация изменений - Коммит

Давайте сделаем коммит того, что мы проиндексировали, в репозиторий. Когда вы ранее использовали git commit для коммита первоначальной версии файла hello.html в репозиторий, вы включили метку -m, которая делает комментарий в командной строке. Команда commit позволит вам интерактивно редактировать комментарии для коммита. Теперь давайте это проверим. Если вы опустите метку -m из командной строки, git перенесет вас в редактор по вашему выбору. Редактор выбирается из следующего списка (в порядке приоритета):
  • переменная среды GIT_EDITOR
  • параметр конфигурации core.editor
  • переменная среды VISUAL
  • переменная среды EDITOR
  • Сделайте коммит сейчас и проверьте состояние.
    git commit
    git commit
    Waiting for Emacs...
    [master 569aa96] Added h1 tag
     1 files changed, 1 insertions(+), 1 deletions(-)
    

    git status
    $ git status
    # On branch master
    nothing to commit (working directory clean)
    

    Изменения, а не файлы

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

    История

    получение списка произведенных изменений — функция команды git log
    git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=format:"%c" --shortstat
    $ git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=format:"%c"
    * fa3c141 2011-03-09 | Added HTML header (HEAD, master) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    Давайте рассмотрим его в деталях:
  • --pretty="..." — определяет формат вывода.
  • %h — укороченный хэш коммита
  • %d — дополнения коммита («головы» веток или теги)
  • %ad — дата коммита
  • %s — комментарий
  • %an — имя автора
  • --graph — отображает дерево коммитов в виде ASCII-графика
  • --date=format:"%c" — сохраняет формат даты коротким и симпатичным
  • --shortstat - статистика изменений
  • Алиасы

    алиасы и шорткаты для команд git
    git config --global alias.co checkout
    git config --global alias.ci commit
    git config --global alias.st status
    git config --global alias.br branch
    git config --global alias.hist 'log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=format:"%c"'
    
    Добавьте следующее в файл .gitconfig в вашем пользовательском $HOME каталоге
    [alias]
      co = checkout
      ci = commit
      st = status
      br = branch
      hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=format:"%c"
    

    Получение старых версий

    Возвращаться назад в историю очень просто. Команда checkout скопирует любой снимок из репозитория в рабочий каталог.
    git checkout <hash>
    $ git checkout 911e8c9
    Note: checking out '911e8c9'.
    
    You are in 'detached HEAD' state. You can look around, make experimental
    changes and commit them, and you can discard any commits you make in this
    state without impacting any branches by performing another checkout.
    
    If you want to create a new branch to retain commits you create, you may
    do so (now or later) by using -b with the checkout command again. Example:
    
      git checkout -b new_branch_name
    
    HEAD is now at 911e8c9... First Commit
    $ cat hello.html
    Hello, World
    
    Вернитесь к последней версии в ветке master
    git checkout master
    $ git checkout master
    Previous HEAD position was 911e8c9... First Commit
    Switched to branch 'master'
    $ cat hello.html
                            <html>
      <head>
      </head>
      <body>
        <h1>Hello, World!</h1>
      </body>
    </html>

    Создание тегов версий

    Давайте назовем текущую версию страницы hello первой (v1)
    git tag v1 Давайте создадим тег для версии, которая идет перед текущей версией и назовем его v1-beta. В первую очередь нам надо переключиться на предыдущую версию. Вместо поиска до хэш, мы будем использовать ^, обозначающее «родитель v1». Если обозначение v1^ вызывает у вас какие-то проблемы, попробуйте также v1~1, указывающее на ту же версию. Это обозначение можно определить как «первую версию предшествующую v1».
    git checkout v1^
    git tag v1-beta
    Переключение по имени тега
    git checkout v1
    git checkout v1-beta
    Просмотр тегов с помощью команды tag
    $ git tag
    v1
    v1-beta
    
    Просмотр Тегов в логах
    git hist master --all
    $ git hist master --all
    * fa3c141 2011-03-09 | Added HTML header (v1, master) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (HEAD, v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    

    Отмена локальных изменений (до индексации)

    Переключитесь на ветку master
    git checkout master
    Убедитесь, что вы находитесь на последнем коммите ветки master, прежде чем продолжить работу.
    Измените hello.html
    <html>
      <head>
      </head>
      <body>
        <h1>Hello, World!</h1>
        <!-- This is a bad comment.  We want to revert it. -->
      </body>
    </html>
    Проверьте состояние git status
    $ git status
    # On branch master
    # Changes not staged for commit:
    #   (use "git add ..." to update what will be committed)
    #   (use "git checkout -- ..." to discard changes in working directory)
    #
    #	modified:   hello.html
    #
    no changes added to commit (use "git add" and/or "git commit -a")
    
    Мы видим, что файл hello.html был изменен, но еще не проиндексирован.
    Отмена изменений в рабочем каталоге
    Используйте команду checkout для переключения в версию файла hello.html в репозитории.
    git checkout hello.html
    $ git checkout hello.html
    $ git status
    # On branch master
    nothing to commit (working directory clean)
    $ cat hello.html
                            <html>
      <head>
      </head>
      <body>
        <h1>Hello, World!</h1>
      </body>
    </html>
    Команда status показывает нам, что не было произведено никаких изменений, не зафиксированных в рабочем каталоге. И «нежелательный комментарий» больше не является частью содержимого файла.

    Отмена проиндексированных изменений (перед коммитом)


    git reset HEAD hello.html
    Команда reset сбрасывает буферную зону к HEAD. Это очищает буферную зону от изменений, которые мы только что проиндексировали. Команда reset (по умолчанию) не изменяет рабочий каталог. Поэтому рабочий каталог все еще содержит нежелательный комментарий. Мы можем использовать команду checkout из предыдущего урока, чтобы удалить нежелательные изменения в рабочем каталоге.

    Отмена коммитов

    Иногда вы понимаете, что новые коммиты являются неверными, и хотите их отменить. Есть несколько способов решения этого вопроса, здесь мы будем использовать самый безопасный. Мы отменим коммит путем создания нового коммита, отменяющего нежелательные изменения.
    Измените файл и сделайте коммит
    git add hello.html
    git commit -m "Oops, we didn't want this commit"
    Сделайте коммит с новыми изменениями, отменяющими предыдущие Чтобы отменить коммит, нам необходимо сделать коммит, который удаляет изменения, сохраненные нежелательным коммитом.
    git revert HEAD --no-edit

    Удаление коммиттов из ветки

    Revert из предыдущего раздела является мощной командой, которая позволяет отменить любые коммиты в репозиторий. Однако, и оригинальный и «отмененный» коммиты видны в истории ветки (при использовании команды git log). Часто мы делаем коммит, и сразу понимаем, что это была ошибка. Было бы неплохо иметь команду «возврата», которая позволила бы нам сделать вид, что неправильного коммита никогда и не было. Команда «возврата» даже предотвратила бы появление нежелательного коммита в истории git log
    При получении ссылки на коммит (т.е. хэш, ветка или имя тега), Команда reset
  • Перепишет текущую ветку, чтобы она указывала на нужный коммит
  • Опционально сбросит буферную зону для соответствия с указанным коммитом
  • Опционально сбросит рабочий каталог для соответствия с указанным коммитом
  • git reset --hard <hash>
    $ git reset --hard v1
    HEAD is now at fa3c141 Added HTML header
    $ git hist
    * fa3c141 2011-03-09 | Added HTML header (HEAD, v1, master) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    Ничего никогда не теряется
    git hist --all
    $ git hist --all
    * 45fa96b 2011-03-09 | Revert "Oops, we didn't want this commit" (oops) [Marina Pushkova]
    * 846b90c 2011-03-09 | Oops, we didn't want this commit [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (HEAD, v1, master) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    

    Удаление тега oops (уборка)

    Тег oops свою функцию выполнил. Давайте удалим его и коммиты, на которые он ссылался, сборщиком мусора.
    git tag -d oops
    git status
    $ git tag -d oops
    Deleted tag 'oops' (was 45fa96b)
    $ git hist --all
    * fa3c141 2011-03-09 | Added HTML header (HEAD, v1, master) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    

    Внесение изменений в коммиты

    Измените страницу, а затем сделайте коммит После совершения коммита вы понимаете, что любой хороший комментарий должен включать электронную почту автора. Обновите страницу hello.html, включив в нее email.
    git add hello.html
    git commit --amend -m "Add an author/email comment"
    $ git hist
    * 6a78635 2011-03-09 | Add an author/email comment (HEAD, master) [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    

    Перемещение файлов

    Переместите файл hello.html в каталог lib
    git mv hello.html lib
    $ mkdir lib
    $ git mv hello.html lib
    $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD ..." to unstage)
    #
    #	renamed:    hello.html -> lib/hello.html
    #
    
    Перемещая файлы с помощью git, мы информируем git о 2 вещах
  • Что файл hello.html был удален.
  • Что файл lib/hello.html был создан.
  • Оба эти факта сразу же проиндексированы и готовы к коммиту. Команда git status сообщает, что файл был перемещен.

    Config File


    cat .git/config
    $ cat .git/config
    [core]
    	repositoryformatversion = 0
    	filemode = true
    	bare = false
    	logallrefupdates = true
    	ignorecase = true
    [user]
    	name = Marina Pushkova
    	email = marina (at) githowto.com
    
    Это файл конфигурации, создающийся для каждого конкретного проекта. Записи в этом файле будут перезаписывать записи в файле .gitconfig вашего главного каталога, по крайней мере в рамках этого проекта.

    Файл HEAD


    cat .git/HEAD
    $ cat .git/HEAD
    ref: refs/heads/master
    
    Файл HEAD содержит ссылку на текущую ветку, в данный момент это должна быть ветка master.

    Создание ветки


    git checkout -b style
    git add lib/style.css
    git commit -m "Added css stylesheet"
    git add lib/hello.html
    git commit -m "Hello uses style.css"
    git add index.html
    git commit -m "Updated index.html"
    
    Теперь у нас есть новая ветка под названием style с 3 новыми коммитами.

    Навигация по веткам


    git hist --all
    $ git hist --all
    * 07a2a46 2011-03-09 | Updated index.html (HEAD, style) [Marina Pushkova]
    * 649d26c 2011-03-09 | Hello uses style.css [Marina Pushkova]
    * 1f3cbd2 2011-03-09 | Added css stylesheet [Marina Pushkova]
    * 8029c07 2011-03-09 | Added index.html. (master) [Marina Pushkova]
    * 567948a 2011-03-09 | Moved hello.html to lib [Marina Pushkova]
    * 6a78635 2011-03-09 | Add an author/email comment [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    

    Переключение на ветку master git checkout master
    Переключение на ветку style git checkout style

    Слияние веток

    Слияние переносит изменения из двух веток в одну. Давайте вернемся к ветке style и сольем master с style.
    git checkout style
    git merge master
    git hist --all
    $ git checkout style
    Switched to branch 'style'
    $ git merge master
    Merge made by recursive.
     README |    1 +
     1 files changed, 1 insertions(+), 0 deletions(-)
     create mode 100644 README
    $ git hist --all
    *   5813a3f 2011-03-09 | Merge branch 'master' into style (HEAD, style) [Marina Pushkova]
    |\  
    | * 6c0f848 2011-03-09 | Added README (master) [Marina Pushkova]
    * | 07a2a46 2011-03-09 | Updated index.html [Marina Pushkova]
    * | 649d26c 2011-03-09 | Hello uses style.css [Marina Pushkova]
    * | 1f3cbd2 2011-03-09 | Added css stylesheet [Marina Pushkova]
    |/  
    * 8029c07 2011-03-09 | Added index.html. [Marina Pushkova]
    * 567948a 2011-03-09 | Moved hello.html to lib [Marina Pushkova]
    * 6a78635 2011-03-09 | Add an author/email comment [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    Путем периодического слияния ветки master с веткой style вы можете переносить из master любые изменения и поддерживать совместимость изменений style с изменениями в основной ветке. Однако, это делает графики коммитов действительно уродливыми. Позже мы рассмотрим возможность перебазирования, как альтернативы слиянию.

    Разрешение конфликтов

    $ git checkout style
    Switched to branch 'style'
    $ git merge master
    Auto-merging lib/hello.html
    CONFLICT (content): Merge conflict in lib/hello.html
    Automatic merge failed; fix conflicts and then commit the result.
    
    Если вы откроете lib/hello.html вы увидите
    <html>
      <head>
    <<<<<<< HEAD
        <link type="text/css" rel="stylesheet" media="all" href="style.css" />
    =======
        <!-- no style -->
    >>>>>>> master
      </head>
      <body>
        <h1>Hello,World! Life is great!</h1>
      </body>
    </html>
    Вам необходимо вручную разрешить конфликт. Внесите изменения в lib/hello.html для достижения следующего результата.
    $ git add lib/hello.html
    $ git commit -m "Merged master fixed conflict."
    Recorded resolution for 'lib/hello.html'.
    [style 645c4e6] Merged master fixed conflict.
    

    Перебазирование

    перенести изменения в master в нашу ветку style
    git checkout style
    git rebase master
    $ git checkout style
    Switched to branch 'style'
    $
    $ git rebase master
    First, rewinding head to replay your work on top of it...
    Applying: Added css stylesheet
    Applying: Hello uses style.css
    Applying: Updated index.html
    $
    $ git hist
    * 6e6c76a 2011-03-09 | Updated index.html (HEAD, style) [Marina Pushkova]
    * 1436f13 2011-03-09 | Hello uses style.css [Marina Pushkova]
    * 59da9a7 2011-03-09 | Added css stylesheet [Marina Pushkova]
    * 6c0f848 2011-03-09 | Added README (master) [Marina Pushkova]
    * 8029c07 2011-03-09 | Added index.html. [Marina Pushkova]
    * 567948a 2011-03-09 | Moved hello.html to lib [Marina Pushkova]
    * 6a78635 2011-03-09 | Add an author/email comment [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    Конечный результат перебазирования очень похож на результат слияния. Ветка style в настоящее время содержит все свои изменения, а также все изменения ветки master. Однако, дерево коммитов значительно отличается. Дерево коммитов ветки style было переписано таким образом, что ветка master является частью истории коммитов. Это делает цепь коммитов линейной и гораздо более читабельной.

    Когда использовать перебазирование, а когда слияние?

    Не используйте перебазирование:
  • Если ветка является публичной и расшаренной. Переписывание общих веток будет мешать работе других членов команды.
  • Когда важна точная история коммитов ветки (так как команда rebase переписывает историю коммитов).
  • Учитывая приведенные выше рекомендации, я предпочитаю использовать rebase для кратковременных, локальных веток, а слияние для веток в публичном репозитории.

    Клонирование репозиториев

    Создайте клон репозитория hello
    git clone hello cloned_hello
    $ git clone hello cloned_hello
    Cloning into cloned_hello...
    done.
    $ ls
    cloned_hello
    hello
    

    Просмотр клонированного репозитория


    cd cloned_hello
    $ git hist --all
    * 6e6c76a 2011-03-09 | Updated index.html (HEAD, origin/master, origin/style, origin/HEAD, master) [Marina Pushkova]
    * 1436f13 2011-03-09 | Hello uses style.css [Marina Pushkova]
    * 59da9a7 2011-03-09 | Added css stylesheet [Marina Pushkova]
    * 6c0f848 2011-03-09 | Added README [Marina Pushkova]
    * 8029c07 2011-03-09 | Added index.html. [Marina Pushkova]
    * 567948a 2011-03-09 | Moved hello.html to lib [Marina Pushkova]
    * 6a78635 2011-03-09 | Add an author/email comment [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    Вы увидите ветку master (HEAD) в списке истории. Вы также увидите ветки со странными именами (origin/master, origin/style и origin/HEAD)

    Что такое origin?

    имена удаленных репозиториев
    git remote
    $ git remote
    origin
    
    Мы видим, что клонированный репозиторий знает об имени по умолчанию удаленного репозитория
    git remote show origin
    $ git remote show origin
    * remote origin
      Fetch URL: /users/slavko/hello
      Push  URL: /users/slavko/hello
      HEAD branch (remote HEAD is ambiguous, may be one of the following):
        style
        master
      Remote branches:
        style  tracked
        master tracked
      Local branch configured for 'git pull':
        master merges with remote master
      Local ref configured for 'git push':
        master pushes to master (up to date)
    

    Список удаленных веток

    Для того, чтобы увидеть все ветки, попробуйте следующую команду:
    git branch -a
    $ git branch -a
    * master
      remotes/origin/HEAD -> origin/master
      remotes/origin/style
      remotes/origin/master
    
    Git выводит все коммиты в оригинальный репозиторий, но ветки в удаленном репозитории не рассматриваются как локальные. Если мы хотим собственную ветку style, мы должны сами ее создать.

    Извлечение изменений из удаленного репозитория


    git fetch
    git hist --all
    $ git fetch
    From /users/slavko/hello
       6e6c76a..2faa4ea  master     -> origin/master
    $ git hist --all
    * 2faa4ea 2011-03-09 | Changed README in original repo (origin/master, origin/HEAD) [Marina Pushkova]
    * 6e6c76a 2011-03-09 | Updated index.html (HEAD, origin/style, master) [Marina Pushkova]
    * 1436f13 2011-03-09 | Hello uses style.css [Marina Pushkova]
    * 59da9a7 2011-03-09 | Added css stylesheet [Marina Pushkova]
    * 6c0f848 2011-03-09 | Added README [Marina Pushkova]
    * 8029c07 2011-03-09 | Added index.html. [Marina Pushkova]
    * 567948a 2011-03-09 | Moved hello.html to lib [Marina Pushkova]
    * 6a78635 2011-03-09 | Add an author/email comment [Marina Pushkova]
    * fa3c141 2011-03-09 | Added HTML header (v1) [Marina Pushkova]
    * 8c32287 2011-03-09 | Added standard HTML page tags (v1-beta) [Marina Pushkova]
    * 43628f7 2011-03-09 | Added h1 tag [Marina Pushkova]
    * 911e8c9 2011-03-09 | First Commit [Marina Pushkova]
    
    На данный момент в репозитории есть все коммиты из оригинального репозитория, но они не интегрированы в локальные ветки клонированного репозитория.
    В истории выше найдите коммит «Changed README in original repo». Обратите внимание, что коммит включает в себя коммиты «origin/master» и «origin/HEAD».
    Теперь давайте посмотрим на коммит «Updated index.html». Вы увидите, что локальная ветка master указывает на этот коммит, а не на новый коммит, который мы только что извлекли.
    Выводом является то, что команда «git fetch» будет извлекать новые коммиты из удаленного репозитория, но не будет сливать их с вашими наработками в локальных ветках.

    Слияние извлеченных изменений

    Слейте извлеченные изменения в локальную ветку master
    git merge origin/master
    $ git merge origin/master
    Updating 6e6c76a..2faa4ea
    Fast-forward
     README |    1 +
     1 files changed, 1 insertions(+), 0 deletions(-)
    
    git pull = git fetch & git merge origin/master

    Добавление ветки наблюдения

    Ветки, которые начинаются с remotes/origin являются ветками оригинального репозитория. Обратите внимание, что у вас больше нет ветки под названием style, но он знает, что в оригинальном репозитории ветка style была.
    git branch --track style origin/style
    git branch -a
    git hist --max-count=2
    $ git branch --track style origin/style
    Branch style set up to track remote branch style from origin.
    $ git branch -a
      style
    * master
      remotes/origin/HEAD -> origin/master
      remotes/origin/style
      remotes/origin/master
    $ git hist --max-count=2
    * 2faa4ea 2011-03-09 | Changed README in original repo (HEAD, origin/master, origin/HEAD, master) [Marina Pushkova]
    * 6e6c76a 2011-03-09 | Updated index.html (origin/style, style) [Marina Pushkova]
    
    Теперь мы можем видеть ветку style в списке веток и логе.

    Чистые репозитории

    Чистые репозитории (без рабочих каталогов) обычно используются для расшаривания.
    Небольшое пояснение, что же все-таки означает «чистый репозиторий». Обычный git-репозиторий подразумевает, что вы будете использовать его как рабочую директорию, поэтому вместе с файлами проекта в актуальной версии, git хранит все служебные, «чисто-репозиториевские» файлы в поддиректории .git В удаленных репозиториях нет смысла хранить рабочие файлы на диске (как это делается в рабочих копиях), а все что им действительно нужно — это дельты изменений и другие бинарные данные репозитория. Вот это и есть «чистый репозиторий»
    git clone --bare hello hello.git
    $ git clone --bare hello hello.git
    Cloning into bare repository hello.git...
    done.
    $ ls hello.git
    HEAD
    config
    description
    hooks
    info
    objects
    packed-refs
    refs
    
    Как правило, репозитории, оканчивающиеся на «.git» являются чистыми репозиториями. Мы видим, что в репозитории hello.git нет рабочего каталога. По сути, это есть не что иное, как каталог .git нечистого репозитория.

    Добавление удаленного репозитория

    Давайте добавим репозиторий hello.git к нашему оригинальному репозиторию
    cd hello
    git remote add shared ../hello.git

    Отправка изменений в удаленный репозиторий


    git push shared master
    $ git push shared master
    To ../hello.git
       2faa4ea..79f507c  master -> master
    

    Извлечение общих изменений

    cd ../cloned_hello
    git remote add shared ../hello.git
    git branch --track shared master
    git pull shared master
    

    Обьединение двух (и более) репозиториев

    пусть будут 4 каталога с репозиториями git1,git2,git3,unite

    в каждом из каталогов должна быть ветка master

    т.е. выполнены 2 команды git add . & git commit -m 'init'

    $ mkdir git1
    $ cd git1
    $ git init
    $ echo 'git1' > git1.txt
    $ git add .
    $ git commit -m 'git1 init'
    $ cd ..
    $ mkdir git2
    $ cd git2
    $ git init
    $ echo 'git2' > git2.txt
    $ git add .
    $ git commit -m 'git2 init'
    $ cd ..
    $ mkdir git3
    $ cd git3
    $ git init
    $ echo 'git3' > git3.txt
    $ git add .
    $ git commit -m 'git3 init'
    $ cd ..
    $ mkdir unite
    $ cd unite
    $ git init
    $ echo 'unite' > unite.txt
    $ git add .
    $ git commit -m 'unite init'
    

    созданы 4 директория с репозиториями, пока они однозначны, но один директорий носит предательское имя unite что выдает его за сборщик других трех репозиториев git1,git2,git3 переходим в директорию unite и выполняем команды

    $ cd unite
    $ git remote add -f git1 ../git1
    $ git remote add -f git2 ../git2
    $ git remote add -f git3 ../git3
    
    

    чтобы посмотреть список всех подключенных удаленных репозиториев

    $ git remote
    git1
    git2
    git3
    

    теперь сливаем удаленные ветки в ветку master репозитория unite, опция --no-edit - комментарий коммита по умолчанию (без редактора)

    $ git merge git1/master --no-edit
    $ git merge git2/master --no-edit
    $ git merge git3/master --no-edit
    

    в каталоге unite видим файлы из всех удаленных репозиториев

    $ ls
    git1.txt  git2.txt  git3.txt  unite.txt
    

    смотрим коммиты git log

    $ git hist
    *   bc9f7c7 02.03.2019 17:35:09 | Merge remote-tracking branch 'git3/master' (HEAD -> master) [SlavKoVrn]
    |\
    | * 40add1b 02.03.2019 17:23:58 | git3 init (git3/master) [SlavKoVrn]
    *   55fe75f 02.03.2019 17:35:01 | Merge remote-tracking branch 'git2/master' [SlavKoVrn]
    |\
    | * cc01f45 02.03.2019 17:23:11 | git2 init (git2/master) [SlavKoVrn]
    *   d0d1b39 02.03.2019 17:34:51 | Merge remote-tracking branch 'git1/master' [SlavKoVrn]
    |\
    | * 2a4fe20 02.03.2019 17:22:32 | git1 init (git1/master) [SlavKoVrn]
    * 7353059 02.03.2019 17:24:49 | unite init [SlavKoVrn]
    

    теперь изменим чтонить скажем в репо git1 и зафиксируем это коммитом

    $ cd ../git1
    $ echo ' - changes' >> git1.txt
    $ git add .
    $ git commit -m 'changes in git1'
    

    переходим в обьедененный репо unite и закачиваем изменения со всех репо

    команда git fetch --all

    $ cd ../unite
    $ git fetch --all
    Fetching git1
    remote: Counting objects: 3, done.
    remote: Total 3 (delta 0), reused 0 (delta 0)
    Unpacking objects: 100% (3/3), done.
    From ../git1
       2a4fe20..9df2a2f  master     -> git1/master
    Fetching git2
    Fetching git3
    

    видно что изменения закачены только с каталога git1, поэтому и сливаем только ветку git1/master

    $ git merge git1/master --no-edit
    Merge made by the 'recursive' strategy.
     git1.txt | 1 +
     1 file changed, 1 insertion(+)
    

    смотрим историю git log

    $ git hist
    *   257138a 02.03.2019 17:57:01 | Merge remote-tracking branch 'git1/master' (HEAD -> master) [SlavKoVrn]
    |\
    | * 9df2a2f 02.03.2019 17:48:14 | changes in git1 (git1/master) [SlavKoVrn]
    * |   bc9f7c7 02.03.2019 17:35:09 | Merge remote-tracking branch 'git3/master' [SlavKoVrn]
    |\ \
    | * | 40add1b 02.03.2019 17:23:58 | git3 init (git3/master) [SlavKoVrn]
    |  /
    * |   55fe75f 02.03.2019 17:35:01 | Merge remote-tracking branch 'git2/master' [SlavKoVrn]
    |\ \
    | * | cc01f45 02.03.2019 17:23:11 | git2 init (git2/master) [SlavKoVrn]
    |  /
    * |   d0d1b39 02.03.2019 17:34:51 | Merge remote-tracking branch 'git1/master' [SlavKoVrn]
    |\ \
    | |/
    | * 2a4fe20 02.03.2019 17:22:32 | git1 init [SlavKoVrn]
    * 7353059 02.03.2019 17:24:49 | unite init [SlavKoVrn]
    

    видим наш коммит changes in git1

    открываем файл git1.txt и видим наши изменения из репозитория git1

    git1
     - changes
    

    Все работает !!!