Git как найти ветку

Given N <references>, the first N lines are the one-line
description from their commit message. The branch head that is
pointed at by $GIT_DIR/HEAD is prefixed with an asterisk *
character while other heads are prefixed with a ! character.

Following these N lines, one-line log for each commit is
displayed, indented N places. If a commit is on the I-th
branch, the I-th indentation character shows a + sign;
otherwise it shows a space. Merge commits are denoted by
a - sign. Each commit shows a short name that
can be used as an extended SHA-1 to name that commit.

The following example shows three branches, «master», «fixes»
and «mhf»:

$ git show-branch master fixes mhf
* [master] Add 'git show-branch'.
 ! [fixes] Introduce "reset type" flag to "git reset"
  ! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
---
  + [mhf] Allow "+remote:local" refspec to cause --force when fetching.
  + [mhf~1] Use git-octopus when pulling more than one heads.
 +  [fixes] Introduce "reset type" flag to "git reset"
  + [mhf~2] "git fetch --force".
  + [mhf~3] Use .git/remote/origin, not .git/branches/origin.
  + [mhf~4] Make "git pull" and "git fetch" default to origin
  + [mhf~5] Infamous 'octopus merge'
  + [mhf~6] Retire git-parse-remote.
  + [mhf~7] Multi-head fetch.
  + [mhf~8] Start adding the $GIT_DIR/remotes/ support.
*++ [master] Add 'git show-branch'.

These three branches all forked from a common commit, [master],
whose commit message is «Add ‘git show-branch'».
The «fixes» branch adds one commit «Introduce «reset type» flag to
«git reset»». The «mhf» branch adds many other commits.
The current branch is «master».

Шпаргалка по консольным командам Git

Консольные команды

Создать новый репозиторий

git init # создать новый проект в текущей папке
git init folder-name # создать новый проект в указанной папке

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

git clone git@github.com:nicothin/web-design.git # клонировать удаленный репозиторий в одноименную папку
git clone git@github.com:nicothin/web-design.git foldername # клонировать удаленный репозиторий в папку «foldername»
git clone git@github.com:nicothin/web-design.git . # клонировать репозиторий в текущую папку

Добавление файлов к отслеживанию, индексация отслеживаемых

git add text.txt # добавить к отслеживанию этот существующий файл
git add . # добавить к отслеживанию все новые файлы из текущей папки и её подпапок, индексировать отслеживаемые файлы
git add -i # запуск оболочки интерактивного индексирования для добавления в индекс только выбранных файлов (см. [git-scm.com](http://git-scm.com/book/ru/v1/%D0%98%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D1%8B-Git-%D0%98%D0%BD%D1%82%D0%B5%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%B2%D0%BD%D0%BE%D0%B5-%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5))
git add -p # поочередный просмотр файлов с показом изменений и задаваемым вопросом об отслеживании/индексировании (удобно для добавления в коммит только каких-то конкретных файлов)

Убирание файла, папки из отслеживания

git rm --cached readme.txt # удалить файл из отслеживаемых (файл останется на месте)
git rm --cached -r folder # удалить папку из отслеживаемых (папка останется на месте)

Отмена индексации

git reset HEAD # убрать из индекса все индексированные файлы
git reset HEAD text.txt # убрать из индекса указанный файл

Просмотр изменений

git diff # посмотреть непроиндексированные изменения (если есть, иначе ничего не выведет)
git diff --staged # посмотреть проиндексированные изменения (если есть, иначе ничего не выведет)

Отмена изменений

git checkout -- text.txt # ОПАСНО: отменить все изменения, внесенные в отслеживаемый файл со времени предыдущего коммита (файл не добавлен в индекс)
git checkout -- .     # ОПАСНО: отменить изменения во всех непроиндексированных отслеживаемых файлах
git checkout text.txt # ОПАСНО: отменить изменения в непроиндексированном файле

Коммиты

git commit -m "Name of commit" # закоммитить отслеживаемые индексированные файлы (указано название коммита)
git commit -a -m "Name of commit" # закоммитить отслеживаемые индексированные файлы (указано название коммита, не требует git add, не добавит в коммит неотслеживаемые файлы)
git commit # закоммитить отслеживаемые индексированные файлы (откроется редактор для введения названия коммита)
git commit --amend # изменить последний коммит (Insert — режим ввода, : — командный режим; в командном режиме: :wq — сохранить и выйти)
git commit --amend -m "Новое название" # переименовать последний коммит (только если ещё не был отправлен в удалённый репозиторий)

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

git revert HEAD --no-edit # создать новый коммит, отменяющий изменения последнего коммита без запуска редактора сообщения
git revert b9533bb --no-edit # создать новый коммит, отменяющий изменения указанного (b9533bb) коммита без запуска редактора сообщения (указаны первые 7 символов хеша коммита)
git reset --hard 75e2d51 # вернуть репозиторий в состояние коммита с указанным хешем ОПАСНО! пропадет вся работа, сделанная после этого коммита

Временно переключиться на другой коммит

git checkout b9533bb # временно переключиться на коммит с указанным хешем
git checkout master # вернуться к последнему коммиту в указанной ветке

Переключиться на другой коммит и продолжить работу с него

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

git checkout -b new-branch 5589877 # создать ветку new-branch, начинающуюся с коммита 5589877

Удаление файла (просто удалить отслеживаемый файл из папки недостаточно, нужно сделать его неотслеживаемым и отправить коммит)

git rm text.txt # удалить из отслеживаемых неиндексированный файл (файл будет удален из папки)
git rm -f text.txt # удалить из отслеживаемых индексированный файл (файл будет удален из папки)
git rm -r log/ # удалить из отслеживаемых всё содержимое папки log/ (папка будет удалена)
git rm ind* # удалить из отслеживаемых все файлы с именем, начинающимся на «ind» в текущей папке (файлы будут удалены из папки)
git rm --cached readme.txt # удалить из отслеживаемых индексированный файл (файл останется на месте)

Перемещение/переименование файлов (Git не отслеживает перемещения/переименование, но пытается его угадать)

git mv text.txt test_new.txt # переименовать файл «text.txt» в «test_new.txt»
git mv readme_new.md folder/ # переместить файл readme_new.md в папку folder/ (должна существовать)

История изменений

git log -p index.html # показать историю изменений файла index.html (выход из длинного лога: Q)
git log -p -5 index.html # показать историю изменений файла index.html (последние 5 коммитов, выход из длинного лога: Q)
git log -2 # показать последние 2 коммита
git log -2 --stat # показать последние 2 коммита и статистику внесенных ими изменений
git log -p -22 # показать последние 22 коммита и внесенную ими разницу на уровне строк (выход из длинного лога: Q)
git log --pretty=format:"%h - %an, %ar : %s" -4 # показать последние 4 коммита с форматированием выводимых данных
git log --graph -10 # показать последние 10 коммитов с ASCII-представлением ветвления
git log --since=2.weeks # показать коммиты за последние 2 недели
git log --pretty=format:"%h %ad | %s%d [%an]" --graph --date=short # мой формат вывода, висящий на алиасе оболочки
git log master..branch_99 # показать коммиты из ветки branch_99, которые не влиты в master
git log branch_99..master # показать коммиты из ветки master, которые не влиты в branch_99
git show 60d6582 # показать изменения из коммита с указанным хешем
git show HEAD^ # показать данные о предыдущем коммите

Ветки

git branch # показать список веток
git branch -v # показать список веток и последний коммит в каждой
git branch new_branch # создать новую ветку с указанным именем
git checkout new_branch # перейти в указанную ветку
git checkout -b new_branch # создать новую ветку с указанным именем и перейти в неё
git merge hotfix # влить в ветку, в которой находимся, данные из ветки hotfix
git branch -d hotfix # удалить ветку hotfix (если её изменения уже влиты в главную ветку)
git branch --merged # показать ветки, уже слитые с активной (их можно удалять)
git branch --no-merged # показать ветки, не слитые с активной
git branch -a # показать все имеющиеся ветки (в т.ч. на удаленных репозиториях)
git branch -m old_branch_name new_branch_name # переименовать локально ветку old_branch_name в new_branch_name
git branch -m new_branch_name # переименовать локально ТЕКУЩУЮ ветку в new_branch_name
git push origin :old_branch_name new_branch_name # применить переименование в удаленном репозитории
git branch --unset-upstream # завершить процесс переименования

Удалённые репозитории

git remote -v # показать список удалённых репозиториев, связанных с этим
git remote remove origin # убрать привязку удалённого репозитория с сокр. именем origin
git remote add origin git@github.com:nicothin/test.git # добавить удалённый репозиторий (с сокр. именем origin) с указанным URL
git remote rm origin # удалить привязку удалённого репозитория
git remote show origin # получить данные об удалённом репозитории с сокращенным именем origin
git fetch origin # скачать все ветки с удаленного репозитория (с сокр. именем origin), но не сливать со своими ветками
git fetch origin master # то же, но скачивается только указанная ветка
git checkout origin/github_branch # посмотреть ветку, скачанную с удалённого репозитория (локальной редактируемой копии не создаётся! если нужно редактировать, придётся влить)
git checkout --track origin/github_branch # создать локальную ветку github_branch (данные взять из удалённого репозитория с сокр. именем origin, ветка github_branch) и переключиться на неё
git push origin master # отправить в удалённый репозиторий (с сокр. именем origin) данные своей ветки master
git pull origin # влить изменения с удалённого репозитория (все ветки)
git pull origin master # влить изменения с удалённого репозитория (только указанная ветка)

Разное

git clean -f -d # удалить из репозитория все неотслеживаемые папки и файлы (папки и файлы, добавленные в .gitignore останутся на месте)

Примеры

Собираем коллекцию простых и сложных примеров работы

Начало работы

Создание нового репозитория, первый коммит, привязка удалённого репозитория с gthub.com, отправка изменений в удалённый репозиторий.

# указана последовательность действий:
git init # инициируем гит в этой папке
touch readme.md # создаем файл readme.md
git add readme.md # делаем этот файл отслеживаемым
git commit -m "Первый коммит" # создаем первый коммит с вменяемым названием
git remote add origin git@github.com:nicothin/test.git # добавляем предварительно созданный пустой удаленный репозиторий
git push origin master # отправляем данные из локального репозитория в удаленный (в ветку master)

Обычный рабочий процесс

Создание нового репозитория на github.com, клонирование к себе, работа, периодическая «синхронизация с github.com».

# указана последовательность действий:
# создаём на github.com репозиторий, копируем его URL клонирования (SSH)
# в консоли попадаем в свою папку для всех проектов
git clone АДРЕС_РЕПОЗИТОРИЯ ПАПКА_ПРОЕКТА # клонируем удалённый репозиторий к себе на компьютер (если не указать ПАПУ_ПРОЕКТА, будет создана папка, совпадающая по имени с названием репозитория)
cd ПАПКА_ПРОЕКТА # переходим в папку проекта (указана команда для git bash)
# редактируем файлы, добавляем файлы и/или папки (если удаляем файлы — см. секцию про удаление файлов)
git add . # делаем все новые файлы в этой папке отслеживаемыми и готовыми к коммиту
git commit -m "НАЗВАНИЕ_КОММИТА" # создаем коммит с вменяемым названием
git push origin master # отправляем данные из локального репозитория в удаленный (в ветку master)
# снова вносим какие-то изменения (если удаляем файлы — см. секцию про удаление файлов)
# возвращаемся к шагу с git add . и проходим цикл заново

Не обязательно после каждого коммита отправлять изменения в удаленный репозиторий, можно сделать это один раз в конце работы.

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

# указана последовательность действий:
subl inc/header.html # редактируем и сохраняем разметку «шапки»
git add inc/header.html # индексируем измененный файл
git commit -m "Убрал телефон из шапки" # делаем коммит
# ВНИМАНИЕ: коммит пока не был отправлен в удалённый репозиторий
# сознаём, что нужно было еще что-то сделать в этом коммите
# вносим изменения
git add inc/header.html # индексируем измененный файл (можно git add .)
git commit --amend -m "«Шапка»: выполнена задача №34 (вставить-вынуть)" # заново делаем коммит

Работа с ветками

Есть master (публичная версия сайта), хотим масштабно что-то поменять (переверстать «шапку»), но по ходу работ возникает необходимость подправить критичный баг (неправильно указан контакт в «подвале»).

# указана последовательность действий:
git checkout -b new_page_header # создадим новую ветку для задачи изменения «шапки» и перейдём в неё
subl inc/header.html # редактируем и сохраняем разметку «шапки»
git commit -a -m "Новая шапка: смена логотипа" # делаем первый коммит (работа еще не завершена)
# тут выясняется, что есть баг с контактом в «подвале»
git checkout master # возвращаемся к ветке master
git checkout -b footer_hotfix # создаём ветку (основанную на master) для решения проблемы
subl inc/footer.html # устраняем баг и сохраняем разметку «подвала»
git commit -a -m "Исправление контакта в подвале" # делаем коммит
git checkout master # переключаемся в ветку master
git merge footer_hotfix # вливаем в master изменения из ветки footer_hotfix
git branch -d footer_hotfix # удаляем ветку footer_hotfix
git checkout new_page_header # переключаемся в ветку new_page_header для продолжения работ над «шапкой»
subl inc/header.html # редактируем и сохраняем разметку «шапки»
git commit -a -m "Новая шапка: смена навигации" # делаем коммит (работа над «шапкой» завершена)
git checkout master # переключаемся в ветку master
git merge new_page_header # вливаем в master изменения из ветки new_page_header
git branch -d new_page_header # удаляем ветку new_page_header

Работа с ветками, конфликт слияния

Есть master (публичная версия сайта), в двух параллельных ветках (branch_1 и branch_2) было отредактировано одно и то же место одного и того же файла, первую ветку (branch_1) влили в master, попытка влить вторую вызывает конфликт.

# указана последовательность действий:
git checkout master # переключаемся на ветку master
git checkout -b branch_1 # создаём ветку branch_1, основанную на ветке master
subl . # редактируем и сохраняем файлы
git commit -a -m "Правка 1" # коммитим (теперь имеем 1 коммит в ветке branch_1)
git checkout master # возвращаемся к ветке master
git checkout -b branch_2 # создаём ветку branch_2, основанную на ветке master
subl . # редактируем и сохраняем файлы
git commit -a -m "Правка 2" # коммитим (теперь имеем 1 коммит в ветке branch_2)
git checkout master # возвращаемся к ветке master
git merge branch_1 # вливаем изменения из ветки branch_1 в текущую ветку (master), удача (автослияние)
git merge branch_2 #  вливаем изменения из ветки branch_2 в текущую ветку (master), КОНФЛИКТ автослияния
# Automatic merge failed; fix conflicts and then commit the result.
subl . # выбираем в конфликтных файлах те участки, которые нужно оставить, сохраняем
git commit -a -m "Устранение конфликта" # коммитим результат устранения конфликта

Синхронизация репозитория-форка с мастер-репозиторием

Есть некий репозиторий на github.com, он него нами был сделан форк, добавлены какие-то изменения. Оригинальный (мастер-) репозиторий был как-то обновлён. Задача: стянуть с мастер-репозитория изменения (которые там внесены уже после того, как мы его форкнули).

# указана последовательность действий:
git remote add upstream git@github.com:address.git # добавляем удаленный репозиторий: сокр. имя — upstream, URL мастер-репозитория
git fetch upstream # качаем все ветки мастер-репозитория, но пока не сливаем со своими
git checkout master # переключаемся на ветку master своего репозитория
git merge upstream/master # вливаем ветку master удалённого репозитория upstream в свою ветку master

Ошибка в работе: закоммитили в мастер, но поняли, что нужно было коммитить в новую ветку (ВАЖНО: это сработает только если коммит еще не отправлен в удалённый репозиторий)

# указана последовательность действий:
# сделали изменения, проиндексировали их, закоммитили в master, но ЕЩЁ НЕ ОТПРАВИЛИ (не делали git push)
git checkout -b new-branch # создаём новую вертку из master
git checkout master # переключаемся на master
git reset HEAD~ --hard # жОско сбрасываем состояние master
git checkout new-branch # переключаемся обратно на новую ветку

Нужно вернуть содержимое файла к состоянию, бывшему в каком-либо коммите (известна SHA коммита)

# указана последовательность действий:
git checkout f26ed88 -- index.html # указана SHA коммита, к состоянию которого нужно вернуть файл и имя файла
git status # изменения внесены в файл, файл сразу проиндексирован
git diff --staged # показать изменения в файле
git commit -am "Navigation fixs" # коммит

При любом действии с github (или другим удалённым сервисом) запрашивается логин/пароль

Речь именно о запросе пароля, а не ключевой фразы.

# указана последовательность действий:
git remote -v # показать список удалённых репозиториев с адресами (у проблемного будет адрес по https), предположим, это origin
git remote add origin git@github.com:address.git # добавляем удаленный репозиторий, сокр. имя — origin
# если возникает ошибка добавления с сообщением о том, что origin «уже задан», то: 
git remote rm origin # удаляем привязанный удалённый репозиторий
git remote add origin git@github.com:address.git # добавляем удаленный репозиторий, сокр. имя — origin

Git Reference


book

Branching and Merging

Branching in Git is one of its many great features. If you have used other
version control systems, it’s probably helpful to forget most of what you
think about branches — in fact, it may be more helpful to think of them
practically as contexts since that is how you will most often be
using them. When you checkout different branches, you change contexts
that you are working in and you can quickly context-switch back and forth
between several different branches.

In a nutshell you can create a branch with
git branch (branchname), switch into that context with
git checkout (branchname), record commit snapshots while
in that context, then can switch back and forth easily. When you switch
branches, Git replaces your working directory with the snapshot of the
latest commit on that branch so you don’t have to have multiple directories
for multiple branches. You merge branches together with
git merge. You can easily merge multiple times from the same
branch over time, or alternately you can choose to delete a branch
immediately after merging it.


docs  
book

git branch
list, create and manage working contexts


docs  
book

git checkout
switch to a new branch context

The git branch command is a general branch management tool
for Git and can do several different things. We’ll cover the basic ones
that you’ll use most — listing branches, creating branches and deleting
branches. We will also cover basic git checkout here which
switches you between your branches.

git branch
list your available branches

Without arguments, git branch will list out the local
branches that you have. The branch that you are currently working on will
have a star next to it and if you have
coloring turned on,
will show the current branch in green.

$ git branch
* master

This means that we have a ‘master’ branch and we are currently on it.
When you run git init it will automatically create a ‘master’
branch for you by default, however there is nothing special about the name —
you don’t actually have to have a ‘master’ branch but since it’s the default
that is created, most projects do.

git branch (branchname)
create a new branch

So let’s start by creating a new branch and switching to it. You can do
that by running git branch (branchname).

$ git branch testing
$ git branch
* master
  testing

Now we can see that we have a new branch. When you create a branch this
way it creates the branch at your last commit so if you record some commits
at this point and then switch to ‘testing’, it will revert your working
directory context back to when you created the branch in the first place —
you can think of it like a bookmark for where you currently are. Let’s see
this in action — we use git checkout (branch) to switch the
branch we’re currently on.

$ ls
README   hello.rb
$ echo 'test content' > test.txt
$ echo 'more content' > more.txt
$ git add *.txt
$ git commit -m 'added two files'
[master 8bd6d8b] added two files
 2 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 more.txt
 create mode 100644 test.txt
$ ls
README   hello.rb more.txt test.txt
$ git checkout testing
Switched to branch 'testing'
$ ls
README   hello.rb

So now we can see that when we switch to the ‘testing’ branch, our new
files were removed. We could switch back to the ‘master’ branch and see
them re-appear.

$ ls
README   hello.rb
$ git checkout master
Switched to branch 'master'
$ ls
README   hello.rb more.txt test.txt

git branch -v
see the last commit on each branch

If we want to see last commits on each branch
we can run git branch -v to see them.

$ git branch -v
* master      54b417d fix javascript issue
  development 74c111d modify component.json file
  testing     62a557a update test scripts

git checkout -b (branchname)
create and immediately switch to a branch

In most cases you will be wanting to switch to the branch immediately, so
you can do work in it and then merging into a branch that only contains
stable work (such as ‘master’) at a later point when the work in your new
context branch is stable. You can do this pretty easily with
git branch newbranch; git checkout newbranch, but Git gives
you a shortcut for this: git checkout -b newbranch.

$ git branch
* master
$ ls
README   hello.rb more.txt test.txt
$ git checkout -b removals
Switched to a new branch 'removals'
$ git rm more.txt 
rm 'more.txt'
$ git rm test.txt 
rm 'test.txt'
$ ls
README   hello.rb
$ git commit -am 'removed useless files'
[removals 8f7c949] removed useless files
 2 files changed, 0 insertions(+), 2 deletions(-)
 delete mode 100644 more.txt
 delete mode 100644 test.txt
$ git checkout master
Switched to branch 'master'
$ ls
README   hello.rb more.txt test.txt

You can see there how we created a branch, removed some of our files
while in the context of that branch, then switched back to our main branch
and we see the files return. Branching safely isolates work that we do into
contexts we can switch between.

If you start on work it is very useful to
always start it in a branch (because it’s fast and easy to do) and then
merge it in and delete the branch when you’re done. That way if what you’re
working on doesn’t work out you can easily discard it and if you’re forced
to switch back to a more stable context your work in progress is easy to put
aside and then come back to.

git branch -d (branchname)
delete a branch

If we want to delete a branch (such as the ‘testing’ branch in the
previous example, since there is no unique work on it),
we can run git branch -d (branch) to remove it.

$ git branch
* master
  testing
$ git branch -d testing
Deleted branch testing (was 78b2670).
$ git branch
* master

git push (remote-name) :(branchname)
delete a remote branch

When you’re done with a remote branch, whether it’s been merged
into the remote master or you want to abandon it and sweep it under
the rug, you’ll issue a git push command with a specially
placed colon symbol to remove that branch.

$ git push origin :tidy-cutlery
To git@github.com:octocat/Spoon-Knife.git
 - [deleted]         tidy-cutlery

In the above example you’ve deleted the «tidy-cutlery» branch
of the «origin» remote. A way to remember this is to think of the
git push remote-name local-branch:remote-branch syntax.
This states that you want to push your local branch to match that
of the remote. When you remove the local-branch portion
you’re now matching nothing to the remote, effectively telling the
remote branch to become nothing.

Alternatively, you can run
git push remote-name --delete branchname
which is a wrapper for the colon refspec (a source:destination pair)
of deleting a remote branch.

In a nutshell you use git branch to list your
current branches, create new branches and delete unnecessary or
already merged branches.


docs  
book

git merge
merge a branch context into your current one

Once you have work isolated in a branch, you will eventually want to
incorporate it into your main branch. You can merge any branch into your
current branch with the git merge command. Let’s take as a
simple example the ‘removals’ branch from above. If we create a branch
and remove files in it and commit our removals to that branch, it is
isolated from our main (‘master’, in this case) branch. To include those
deletions in your ‘master’ branch, you can just merge in the ‘removals’
branch.

$ git branch
* master
  removals
$ ls
README   hello.rb more.txt test.txt
$ git merge removals
Updating 8bd6d8b..8f7c949
Fast-forward
 more.txt |    1 -
 test.txt |    1 -
 2 files changed, 0 insertions(+), 2 deletions(-)
 delete mode 100644 more.txt
 delete mode 100644 test.txt
$ ls
README   hello.rb

more complex merges

Of course, this doesn’t just work for simple file additions and
deletions. Git will merge file modifications as well — in fact, it’s very
good at it. For example, let’s see what happens when we edit a file in
one branch and in another branch we rename it and then edit it and then
merge these branches together. Chaos, you say? Let’s see.

$ git branch
* master
$ cat hello.rb 
class HelloWorld
  def self.hello
    puts "Hello World"
  end
end

HelloWorld.hello

So first we’re going to create a new branch named ‘change_class’ and
switch to it so your class renaming changes are isolated. We’re going to
change each instance of ‘HelloWorld’ to ‘HiWorld’.

$ git checkout -b change_class
Switched to a new branch 'change_class'
$ vim hello.rb 
$ head -1 hello.rb 
class HiWorld
$ git commit -am 'changed the class name'
[change_class 3467b0a] changed the class name
 1 files changed, 2 insertions(+), 4 deletions(-)

So now we’ve committed the class renaming changes to the ‘change_class’
branch. To switch back to the ‘master’ branch the class name will
revert to what it was before we switched branches. Here we can change
something different (in this case the printed output) and at the same
time rename the file from hello.rb to ruby.rb.

$ git checkout master
Switched to branch 'master'
$ git mv hello.rb ruby.rb
$ vim ruby.rb 
$ git diff
diff --git a/ruby.rb b/ruby.rb
index 2aabb6e..bf64b17 100644
--- a/ruby.rb
+++ b/ruby.rb
@@ -1,7 +1,7 @@
 class HelloWorld

   def self.hello
-    puts "Hello World"
+    puts "Hello World from Ruby"
   end

 end
$ git commit -am 'added from ruby'
[master b7ae93b] added from ruby
 1 files changed, 1 insertions(+), 1 deletions(-)
 rename hello.rb => ruby.rb (65%)

Now those changes are recorded in the ‘master’ branch. Notice that the
class name is back to ‘HelloWorld’, not ‘HiWorld’. To incorporate
the ‘HiWorld’ change we can just merge in the ‘change_class’
branch. However, the name of the file has changed since we branched,
what will Git do?

$ git branch
  change_class
* master
$ git merge change_class
Renaming hello.rb => ruby.rb
Auto-merging ruby.rb
Merge made by recursive.
 ruby.rb |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)
$ cat ruby.rb
class HiWorld
  def self.hello
    puts "Hello World from Ruby"
  end
end

HiWorld.hello

Well, it will just figure it out. Notice that there are no merge conflicts
and the file that had been renamed now has the ‘HiWorld’ class name change
that was done in the other branch. Pretty cool.

merge conflicts

So, Git merges are magical, we never ever have to deal with merge
conflicts again, right? Not quite. In situations where the same block
of code is edited in different branches there is no way for a computer
to figure it out, so it’s up to us. Let’s see another example of changing
the same line in two branches.

$ git branch
* master
$ git checkout -b fix_readme
Switched to a new branch 'fix_readme'
$ vim README 
$ git commit -am 'fixed readme title'
[fix_readme 3ac015d] fixed readme title
 1 files changed, 1 insertions(+), 1 deletions(-)

Now we have committed a change to one line in our README file in a
branch. Now let’s change the same line in a different way back on
our ‘master’ branch.

$ git checkout master
Switched to branch 'master'
$ vim README 
$ git commit -am 'fixed readme title differently'
[master 3cbb6aa] fixed readme title differently
 1 files changed, 1 insertions(+), 1 deletions(-)

Now is the fun part — we will merge the first branch into our master
branch, causing a merge conflict.

$ git merge fix_readme
Auto-merging README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
$ cat README 
<<<<<<< HEAD
Many Hello World Examples
=======
Hello World Lang Examples
>>>>>>> fix_readme

This project has examples of hello world in
nearly every programming language.

You can see that Git inserts standard merge conflict markers, much like
Subversion, into files when it gets a merge conflict. Now it’s up to us
to resolve them. We will do it manually here, but check out
git mergetool
if you want Git to fire up a graphical mergetool
(like kdiff3, emerge, p4merge, etc) instead.

$ vim README   # here I'm fixing the conflict
$ git diff
diff --cc README
index 9103e27,69cad1a..0000000
--- a/README
+++ b/README
@@@ -1,4 -1,4 +1,4 @@@
- Many Hello World Examples
 -Hello World Lang Examples
++Many Hello World Lang Examples

  This project has examples of hello world in

A cool tip in doing merge conflict resolution in Git is that if you
run git diff, it will show you both sides of the conflict
and how you’ve resolved it as shown here. Now it’s time to mark
the file as resolved. In Git we do that with git add
to tell Git the file has been resolved you have to stage it.

$ git status -s
UU README
$ git add README 
$ git status -s
M  README
$ git commit 
[master 8d585ea] Merge branch 'fix_readme'

And now we’ve successfully resolved our merge conflict and committed
the result.

In a nutshell you use git merge to combine another
branch context into your current branch. It automatically figures out
how to best combine the different snapshots into a new snapshot with the
unique work of both.


docs  
book

git log
show commit history of a branch

So far we have been committing snapshots of your project and switching
between different isolated contexts, but what if we’ve forgotten how we’ve
got to where we are? Or what if we want to know how one branch differs
from another? Git provides a tool that shows you all the commit messages
that have lead up to the snapshot you are currently on, which is called
git log.

To understand the log command, you have to understand what information
is stored when you run the git commit command to store a
snapshot. In addition to the manifest of files and commit message and
information about the person who committed it, Git also stores the commit
that you based this snapshot on. That is, if you clone a project, what was
the snapshot that you modified to get to the snapshot that you saved? This
is helpful to give context to how the project got to where it is and allows
Git to figure out who changed what. If Git has the snapshot you save and
the one you based it on, then it can automatically figure out what you
changed. The commit that a new commit was based on is called the «parent».

To see a chronological list of the parents of any branch, you can run
git log when you are in that branch. For example, if we run
git log in the Hello World project that we have been working
on in this section, we’ll see all the commit messages that we’ve done.

$ git log
commit 8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d
Merge: 3cbb6aa 3ac015d
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:59:47 2010 +0200

    Merge branch 'fix_readme'

    Conflicts:
        README

commit 3cbb6aae5c0cbd711c098e113ae436801371c95e
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:58:53 2010 +0200

    fixed readme title differently

commit 3ac015da8ade34d4c7ebeffa2053fcac33fb495b
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:58:36 2010 +0200

    fixed readme title

commit 558151a95567ba4181bab5746bc8f34bd87143d6
Merge: b7ae93b 3467b0a
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jun 4 12:37:05 2010 +0200

    Merge branch 'change_class'
...

To see a more compact version of the same history, we can use the
--oneline option.

$ git log --oneline
8d585ea Merge branch 'fix_readme'
3cbb6aa fixed readme title differently
3ac015d fixed readme title
558151a Merge branch 'change_class'
b7ae93b added from ruby
3467b0a changed the class name
17f4acf first commit

What this is telling us is that this is the history of the development
of this project. If the commit messages are descriptive, this can inform
us as to what all changes have been applied or have influenced the current
state of the snapshot and thus what is in it.

We can also use it to see when the history was branched and merged with
the very helpful --graph option. Here is the same command
but with the topology graph turned on:

$ git log --oneline --graph
*   8d585ea Merge branch 'fix_readme'
|
| * 3ac015d fixed readme title
* | 3cbb6aa fixed readme title differently
|/
*   558151a Merge branch 'change_class'
|
| * 3467b0a changed the class name
* | b7ae93b added from ruby
|/
* 17f4acf first commit

Now we can more clearly see when effort diverged and then was merged
back together. This is very nice for seeing what has happened or what
changes are applied, but
it is also incredibly useful for managing your branches. Let’s create a new
branch, do some work in it and then switch back and do some work in our
master branch, then see how the log command can help us figure
out what is happening on each.

First we’ll create a new branch to add the Erlang programming language
Hello World example — we want to do this in a branch so that we don’t
muddy up our stable branch with code that may not work for a while so we
can cleanly switch in and out of it.

$ git checkout -b erlang
Switched to a new branch 'erlang'
$ vim erlang_hw.erl
$ git add erlang_hw.erl 
$ git commit -m 'added erlang'
[erlang ab5ab4c] added erlang
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100644 erlang_hw.erl

Since we’re having fun playing in functional programming languages we
get caught up in it and also add a Haskell example program while still in
the branch named ‘erlang’.

$ vim haskell.hs
$ git add haskell.hs 
$ git commit -m 'added haskell'
[erlang 1834130] added haskell
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 haskell.hs

Finally, we decide that we want to change the class name of our Ruby
program back to the way it was. So, we can go back to the master branch
and change that and we decide to just commit it directly in the master
branch instead of creating another branch.

$ git checkout master
Switched to branch 'master'
$ ls
README  ruby.rb
$ vim ruby.rb 
$ git commit -am 'reverted to old class name'
[master 594f90b] reverted to old class name
 1 files changed, 2 insertions(+), 2 deletions(-)

So, now say we don’t work on the project for a while, we have other
things to do. When we come back we want to know what the ‘erlang’ branch
is all about and where we’ve left off on the master branch. Just by looking
at the branch name, we can’t know that we made Haskell changes in there, but
using git log we easily can. If you give Git a branch name,
it will show you just the commits that are «reachable» in the history of
that branch, that is the commits that influenced the final snapshot.

$ git log --oneline erlang
1834130 added haskell
ab5ab4c added erlang
8d585ea Merge branch 'fix_readme'
3cbb6aa fixed readme title differently
3ac015d fixed readme title
558151a Merge branch 'change_class'
b7ae93b added from ruby
3467b0a changed the class name
17f4acf first commit

This way, it’s pretty easy to see that we have Haskell code included in
the branch (highlighted in the output). What is even cooler is that we can
easily tell Git that we only are interested in the commits that are
reachable in one branch that are not reachable in another, in other words
which commits are unique to a branch in comparison to another.

In this case if we are interested in merging in the ‘erlang’ branch we
want to see what commits are going to effect our snapshot when we do
that merge. The way we tell Git that is by putting a ^ in
front of the branch that we don’t want to see. For instance, if we want
to see the commits that are in the ‘erlang’ branch that are not in the
‘master’ branch, we can do erlang ^master, or vice versa.
Note that the Windows command-line treats ^ as a special
character, in which case you’ll need to surround ^master
in quotes.

$ git log --oneline erlang ^master
1834130 added haskell
ab5ab4c added erlang
$ git log --oneline master ^erlang
594f90b reverted to old class name

This gives us a nice, simple branch management tool. It allows us to
easily see what commits are unique to which branches so we know what
we’re missing and what we would be merging in if we were to do a merge.

In a nutshell you use git log to list out the commit
history or list of changes people have made that have lead to the snapshot
at the tip of the branch. This allows you to see how the project in that
context got to the state that it is currently in.


docs  
book

git tag
tag a point in history as important

If you get to a point that is important and you want to forever remember
that specific commit snapshot, you can tag it with git tag.
The tag command will basically put a permanent bookmark at
a specific commit so you can use it to compare to other commits in the
future. This is often done when you cut a release or ship something.

Let’s say we want to release our Hello World project as version «1.0».
We can tag the last commit (HEAD) as «v1.0» by running
git tag -a v1.0. The -a means «make an annotated
tag», which allows you to add a tag message to it, which is what you almost
always want to do. Running this without the -a works too, but
it doesn’t record when it was tagged, who tagged it, or let you add a tag
message. It’s recommended you always create annotated tags.

$ git tag -a v1.0 

When you run the git tag -a command, Git will open your editor
and have you write a tag message, just like you would write a commit
message.

Now, notice when we run git log --decorate, we can see our
tag there.

$ git log --oneline --decorate --graph
* 594f90b (HEAD, tag: v1.0, master) reverted to old class name
*   8d585ea Merge branch 'fix_readme'
|
| * 3ac015d (fix_readme) fixed readme title
* | 3cbb6aa fixed readme title differently
|/
*   558151a Merge branch 'change_class'
|
| * 3467b0a changed the class name
* | b7ae93b added from ruby
|/
* 17f4acf first commit

If we do more commits, the tag will stay right at that commit, so we have
that specific snapshot tagged forever and can always compare future
snapshots to it.

We don’t have to tag the commit that we’re on, however. If we forgot to
tag a commit that we released, we can retroactively tag it by running the
same command, but with the commit SHA at the end. For example, say we had
released commit 558151a (several commits back) but forgot to
tag it at the time. We can just tag it now:

$ git tag -a v0.9 558151a
$ git log --oneline --decorate --graph
* 594f90b (HEAD, tag: v1.0, master) reverted to old class name
*   8d585ea Merge branch 'fix_readme'
|
| * 3ac015d (fix_readme) fixed readme title
* | 3cbb6aa fixed readme title differently
|/
*   558151a (tag: v0.9) Merge branch 'change_class'
|
| * 3467b0a changed the class name
* | b7ae93b added from ruby
|/
* 17f4acf first commit

Tags pointing to objects tracked from branch heads will be
automatically downloaded when you fetch from a remote
repository. However, tags that aren’t reachable from branch heads
will be skipped. If you want to make sure all tags are always
included, you must include the --tags option.

$ git fetch origin --tags
remote: Counting objects: 1832, done.
remote: Compressing objects: 100% (726/726), done.
remote: Total 1519 (delta 1000), reused 1202 (delta 764)
Receiving objects: 100% (1519/1519), 1.30 MiB | 1.21 MiB/s, done.
Resolving deltas: 100% (1000/1000), completed with 182 local objects.
From git://github.com:example-user/example-repo
 * [new tag]         v1.0       -> v1.0
 * [new tag]         v1.1       -> v1.1

If you just want a single tag, use
git fetch <remote> tag <tag-name>.

By default, tags are not included when you push to
a remote repository. In order to explicitly update these you must
include the --tags option when using git push.

In a nutshell you use git tag to mark a
commit or point in your repo as important. This also allows
you to refer to that commit with a more memorable reference
than a SHA.

On to Sharing and Updating Projects »

Инструкция о том, как работать с ветками в Git. Расскажем, как закоммитить изменения и запушить в новую ветку, как удалить ветку или изменить ее — и это не все.

Введение

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

Основные понятия: о ветке Git и master

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

Имя основной ветки Git-проекта по умолчанию — master (однако зачастую бывает main, например, в GitHub), она появляется сразу при инициализации репозитория. Эта ветка ничем не отличается от остальных и также ее можно переименовать, но по договоренности master принято считать главной веткой в проекте.

Что делает git branch

Команда git branch — главный инструмент для работы с ветвлением. С ее помощью можно добавлять новые ветки, перечислять и переименовывать существующие и удалять их.

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

Чтобы в Git добавить ветку мы используем:

$ git branch <name of new branch>

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

$ git checkout <name of branch>

Для того чтобы определить, где сейчас находится разработчик, Git использует специальный указатель HEAD, ссылающийся на текущую локальную ветку. В результате checkout HEAD переместится на иную ветку.

Как с помощью git branch создать ветку и перейти в нее

Чаще всего при создании новой ветки git пользователю необходимо сразу же переключиться на нее. В таком случае стоит использовать:

$ git checkout branch <name of new branch> 

Это будет равносильно:

$ git branch <name of new branch>
$ git checkout <name of new branch>

И также мы получим тот же результат при использовании git checkout с ключом -b:

$ git checkout -b <name of branch>

Если пользователю нужно получить список определенного множества веток, то тогда можно воспользоваться ключами. Одними из самых распространенных будут:

  • -r — при использовании этого ключа мы получим список удаленных веток,
  • -a — используя этот параметр, в выводе будут удаленные и локальные ветки.

О команде git checkout

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

Проверка, что указанная нами ветка существует в проекте
Этот этап необходим, так как в ином случае программа не сможет переключиться на ветвь, которая не определена. Для большего понимания нужно вспомнить, что такое ветка в git. Учитываем, что фактически задание ветки — это запись коммита, на который она ссылается. Внутри Git наличие конкретной ветки проверяется наличием одноименного файла в конкретной директории.

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

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

После завершения всех перечисленных выше действий можно считать, что мы полностью переключились. Также с помощью checkout можно извлечь отдельный файл (или папку) из другой ветки и получить его, предварительно перейдя в ту ветку, куда вы собираетесь перенести файл. Для этого выполняем:

$ git checkout <name of new branch> -- <path to folder>

Основы ветвления и слияния

Ветвление позволяет разделять рабочий процесс, оптимизировать тестирование и написание нового кода. Однако после того, как разработчик убедился, что написанный им кусок кода готов и его можно отправить к остальной части итоговой версии, удобно переместить его в основную ветку. Такой подход дает возможность получить к концу разработки проекта целый продукт в одном месте.
Для этого в Git предусмотрено слияние — перенос изменений с одной ветки на другую. Однако сливаемая ветка (под этим определением мы подразумеваем ветку, у которой берем изменения для «вливания» их в другую ветвь) никак не меняется и остается в прежнем состоянии. Такие преобразования мы получаем, применив git merge:

$ git merge <name of merged branch>

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

Также стоит упомянуть о существовании ключей, предназначенных специально для работы с конфликтами:

  • —abort — прерывает слияние и возвращает все к началу
  • —continue — продолжает слияние после разрешения конфликта

Решить конфликт можно двумя способами:

  • Вручную разрешить файловый конфликт. Для этого нужно самим изменить файлы, с которыми возникли проблемы. Мы получим файлы такими, какими и представляли их при попытке слияния.
  • Выбрать более подходящий файл, а от второго отказаться.

Управление ветками с помощью git branch

Эта команда может немного больше, чем просто в git создавать ветки из текущей. Если запустить ее без параметров:

$ git branch

При выполнении этой строки мы получим список существующих веток, где символом * будет отмечена ветка, где вы сейчас находитесь. Это может выглядеть так:

 first_branch
* master
  second_branch

С помощью параметра -v можно получить последний сохраненный коммит в каждой ветке.

$ git branch -v
  first_branch 8fa301b Fix math
* master 225cc2d Merge branch 'first_branch'
  second_branch c56ee12 Refactor code style

Так же существуют опции —merged и —no-merged, с помощью которых можно отфильтровать полученную последовательность веток. То есть мы получим список ответвлений, которые уже были слиты, или, наоборот, ветки, которые еще не прошли через слияние с другими. Выведем ветки, которые уже были слиты с текущей:

$ git branch --merged
  first_branch
* master

Как закоммитить изменения в новую ветку

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

$ git add
$ git commit -m '<information about commit>'

После выполнения последовательности этих команд мы закоммитили изменения в нужной версии программы.

Как запушить в новую ветку

Если мы хотим запушить нашу ветку, то для этого нужно написать:

$ git push origin <name of branch>

Теперь ветка запушена. Если до этого мы уже пушили ее, то произойдет отправка новых коммитов.
В отличии от команды git checkout, при выполнении пуша нет проверки на существование указанной ветки. Это будет значить, что при написании несуществующей ветки git создаст ее автоматически.

Как переименовать ветку

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

$ git branch -m <new name of branch>

Однако здесь нужно быть аккуратными, чтобы не перегрузить проект ненужными ветками. Если запушить переименованную ветку, то на сервере появится ветка с новым именем, но и ветка со старым названием тоже останется. Чтобы избежать такой проблемы, необходимо удалить ветку локально и на сервере.

Как удалить ветку

Удаление веток не такой простой процесс, как может показаться. Можно случайно удалить несохраненные изменения в исходном коде, что приведет к нежелательным последствиям. Поэтому здесь нужно действовать осторожно. С операцией удаления над ветками справляется уже привычная команда git branch с параметром -d:

$ git branch -d <name of branch>

Для корректного удаления нужно помнить несколько правил, чтобы не получить ошибки:

  • Нельзя удалить ветку, в которой вы находитесь. Git выкинет ошибку и не произведет удаление. Следовательно, нужно перейти на другую ветку.
  • Git не позволит удалить ветку, у которой есть несохраненные изменения. Так мы избегаем ситуации, когда часть написанного кода будет безвозвратно утеряна. Если же мы уверены, что изменения в этой версии не нужны и их можно смело удалять, то вместо флага -d используем -D:
$ git branch -D <name of branch>

Соблюдая все условия, нам удастся удалить указанную ветвь.

Работа с ветками на практике

В инструментах для разработки на языках часто есть встроенный функционал, позволяющий работать напрямую с Git. Например, в таких средах разработки как IntelliJ IDEA, PyCharm, PhpStorm, CLine, Rider очень удобно и понятно, как правильно оперировать с разными ветками. Для примера разберем работу в одной из таких сред.

Как работать с ветками в PhpStorm

интерфейс для работы с ветками

Справа в нижнем углу расположены вкладки для работы с Git, где и происходит вся настройка ветвления. На этой панели расположено название текущей ветки. При желании создать новую нужно нажать на этот пункт и выбрать New Branch. Для смены ветки — выбрать из списка искомую и кликнуть на Checkout. Для удаления и переименования предусмотрены кнопки Delete и Rename соответственно.

Работа в специальном приложении почти ничем не отличается от работы в консоли, поэтому все полученные знания можно применять независимо от выбранного способа.

Получение информации о состоянии веток

Как просмотреть состояния файлов ветки

Отметим, что при переходе на другую версию, незакоммиченные изменения перенесутся на ветку, куда мы перейдем. Поэтому перед переключением необходимо убедиться, что изменения в текущей ветки уже закоммичены. Для этого подходит git status:

$ git status

Выполнение этой операции позволит просмотреть файлы, расположенные в ветке, где мы находимся. Как раз с помощью нее можно отслеживать незакоммиченные изменения, чтобы случайно не перенести их в другое место. Пустой вывод этой команды показывает то, что в ветке не присутствуют измененные файлы и мы можем без опасений продолжать с ней работу. А иначе необходимо закоммитить все нужные исправления.

Как просмотреть истории коммитов ветки

Неоднократно в процессе разработки нужно посмотреть на журнал изменений: для отслеживания развития проекта или для определения коммита, к которому следует вернуться. В таких ситуациях выручает команда git log:

$ git log <keys> --<path>

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

  • -<number> (равноценно -n=<number>) — показывает последние n коммитов,
  • —pretty=<value> (доступные такие значения, как oneline, short, medium, full и другие) ****— форматированный вывод истории,
  • -p — выводятся изменения, содержащиеся в коммите,
  • —graph — представляет дерево взаимосвязей коммитов в виде ASCII-графа — такой метод использования позволяет получить графическое представление ветвей прямо в консоли,
  • —all — на выходе мы получаем историю всех коммитов для всех существующих веток,
  • —decorate — показывает, на что ссылаются указатели.

Если нам нужно посмотреть историю для конкретной ветви, то поможет выполнение:

$ git log <keys> <name of parent's branch>..<name of branch>

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

Как просмотреть различия между коммитами

Достаточно часто в ходе разработки какого-либо продукта у разработчика может возникнуть потребность посмотреть разницу между двумя коммитами, прежде чем заливать что-то. Для этого существует git diff:

$ git diff <keys> <path to file> <path to file>

Для этой операции также предусмотрены несколько ключей:

  • —diff-filter=<mark> — с помощью этого параметра, изменяя значения меток, можно задать, обновления между какими файлами мы хотим увидеть. Рассмотрим некоторые возможные значения меток:
    • D — покажет удаленные файлы,
    • M — мы получим файлы, модифицированные после последнего коммита.
  • —word-diff=color — повышает читабельность полученной информации: слова подсвечиваются зеленым цветом, если они были добавлены, и красным — если были удалены.

Заключение

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

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

Git — самая популярная в мире распределённая система контроля версий. Линус Торвальдс, разработчик ядра ОС Linux, создал этот инструмент ещё в 2005 году, а сегодня Git активно поддерживается как проект с открытым исходным кодом. Огромное количество открытых и коммерческих проектов используют Git для контроля версий.

В данной статье перечисляются самые основные команды, которые следует знать разработчику, чтобы освоить управление репозиториями GitHub на высоком уровне. Ознакомиться с ними будет полезно как новичкам, так и опытным разработчикам.

30 основных команд, которые сделают из вас мастера Git

  1. Как задать имя пользователя и адрес электронной почты
  2. Кэширование учётных данных
  3. Инициализация репозитория
  4. Добавление отдельных файлов или всех файлов в область подготовленных файлов
  5. Проверка статуса репозитория
  6. Внесение изменений однострочным сообщением или через редактор
  7. Просмотр истории коммитов с изменениями
  8. Просмотр заданного коммита
  9. Просмотр изменений до коммита
  10. Удаление отслеживаемых файлов из текущего рабочего дерева
  11. Переименование файлов
  12. Отмена подготовленных и неподготовленных изменений
  13. Изменение последнего коммита
  14. Откат последнего коммита
  15. Откат заданного коммита
  16. Создание новой ветки и переход в неё
  17. Просмотр списка веток
  18. Удаление ветки
  19. Слияние двух веток
  20. Отображение журнала фиксации в виде графика для текущей или всех веток
  21. Прекращение слияния при конфликте
  22. Добавление удалённого репозитория
  23. Просмотр удалённых URL-адресов
  24. Получение дополнительных сведений об удалённом репозитории
  25. Отправка изменений в удалённый репозиторий
  26. Получение изменений из удалённого репозитория
  27. Слияние удалённого репозитория с локальным
  28. Отправка новой ветки в удалённый репозиторий
  29. Удаление удалённой ветки
  30. Использование перебазирования

1. Как задать имя пользователя и адрес электронной почты

Имя пользователя нужно, чтобы привязывать коммиты к вашему имени. Это не то же самое, что имя пользователя учётной записи GitHub, с помощью которого выполняется вход в профиль на GitHub. Задать или изменить имя пользователя можно с помощью команды git config. Новое имя будет автоматически отображаться в последующих коммитах, отправленных на GitHub через командную строку. Если хотите скрыть своё реальное имя, можно использовать в качестве имени пользователя Git произвольный набор символов.

git config --global user.name "Tara Routray"

Кроме того, командой git config можно изменять адрес электронной почты, привязанный к вашим коммитам Git. Новый адрес электронной почты будет автоматически отображаться во всех дальнейших коммитах, поданных на GitHub через командную строку.

git config --global user.email "dev@tararoutray.com"

2. Кэширование учётных данных

Кэшировать учётные данные можно с помощью параметра config с флагом --global. Так вы избавитесь от необходимости вручную вводить имя пользователя и пароль при создании нового коммита.

git config --global credential.helper cache

3. Инициализация репозитория

Создать пустой репозиторий Git или вновь инициализировать существующий можно параметром init. При инициализации он создаст скрытую папку. В ней содержатся все объекты и ссылки, которые Git использует и создаёт в истории работы над проектом.

git init

4. Добавление отдельных файлов или всех файлов в область подготовленных файлов

Добавить отдельный файл в область подготовленных файлов можно параметром add с указанием имени файла. Просто замените somefile.js на актуальное имя.

git add somefile.js

Кроме того, можно добавить все файлы и папки в эту область, предоставив wildcard . вместо имени файла:

git add .

5. Проверка статуса репозитория

Просмотреть статус нужного репозитория можно по ключевому слову status: его действие распространяется на подготовленные, неподготовленные и неотслеживаемые файлы.

git status

6. Внесение изменений однострочным сообщением или через редактор

При создании коммита в репозитории можно добавить однострочное сообщение с помощью параметра commit с флагом -m. Само сообщение вводится непосредственно после флага, в кавычках.

git commit -m "Your short summary about the commit"

Также можно открыть текстовый редактор в терминале для написания полного сообщения коммита. Оно может состоять из нескольких строк текста, в котором подробно характеризуются изменения, внесённые в репозиторий.

git commit

7. Просмотр истории коммитов с изменениями

Просматривать изменения, внесённые в репозиторий, можно с помощью параметра log. Он отображает список последних коммитов в порядке выполнения. Кроме того, добавив флаг -p, вы можете подробно изучить изменения, внесённые в каждый файл.

git log -p

8. Просмотр заданного коммита

Просмотреть полный список изменений, внесённых конкретным коммитом, можно с помощью параметра show, указав идентификатор или хеш коммита. Значение хеша уникально для каждого коммита, созданного в вашем репозитории.

git show 1af17e73721dbe0c40011b82ed4bb1a7dbe3ce29

Также можно использовать сокращённый хеш.

git show 1af17e

9. Просмотр изменений до коммита

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

git diff

Для просмотра подготовленных изменений необходимо добавить флаг --staged.

git diff --staged

Также можно указать имя файла как параметр и просмотреть изменения, внесённые только в этот файл.

git diff somefile.js

10. Удаление отслеживаемых файлов из текущего рабочего дерева

Удалять файлы из текущего рабочего дерева можно с помощью параметра rm. При этом файлы удаляются и из индекса.

git rm dirname/somefile.js

Можно также использовать маски файлов (например *.js) для удаления всех файлов, соответствующих критерию.

git rm dirname/*.html

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

Переименовать файл или папку можно параметром mv. Для него указывается источник source и назначение destination. Источник — реально существующий файл или папка, а назначение — существующая папка.

git mv dir1/somefile.js dir2

При выполнении команды файл или папка, указанные как источник, будут перемещены в папку назначения. Индекс будет обновлён соответственно, но изменения нужно записать.

12. Отмена подготовленных и неподготовленных изменений

Восстановить файлы рабочего дерева, не подготовленные к коммиту, можно параметром checkout. Для проведения операции требуется указать путь к файлу. Если путь не указан, параметр git checkout изменит указатель HEAD, чтобы задать указанную ветку как текущую.

git checkout somefile.js

Восстановить подготовленный файл рабочего дерева можно параметром reset. Потребуется указать путь к файлу, чтобы убрать его из области подготовленных файлов. При этом не будет производиться откат никаких изменений или модификаций — однако файл перейдёт в категорию не подготовленных к коммиту.

git reset HEAD somefile.js

Если нужно выполнить это действие для всех подготовленных файлов, путь к ним указывать не надо.

git reset HEAD

13. Изменение последнего коммита

Внести изменения в последний коммит можно параметром commit с флагом --amend. Например, вы записали изменения, внесённые в ряд файлов, и поняли, что допустили ошибку в сообщении коммита. В этом случае можете воспользоваться указанной командой, чтобы отредактировать сообщение предыдущего коммита, не изменяя его снимок.

git commit --amend -m "Updated message for the previous commit"

Также можно вносить изменения в файлы, отправленные ранее. Например, вы изменили несколько файлов в ряде папок и хотите их записать как единый снимок, но забыли добавить в коммит одну из папок. Чтобы исправить такую ошибку, достаточно подготовить для фиксации остальные файлы и папки и создать коммит с флагами --amend и --no-edit.

git add dir1
git commit

# Here you forgot to add dir2 to commit, you can execute the
following command to amend the other files and folders.

git add dir2
git commit --amend --no-edit

Флаг --no-edit позволит внести в коммит поправку без изменения сообщения коммита. В этом случае итоговый коммит заменит неполный, а выглядеть это будет так, как будто мы отправили изменения ко всем файлам в нужных папках как единый снимок.

Внимание! Не изменяйте публичные коммиты.

С помощью amend прекрасно исправляются локальные коммиты, а исправления можно передать в общий репозиторий. Однако изменять коммиты, уже доступные другим пользователям, не следует. Помните, что изменённые коммиты являются совершенно новыми, а предыдущий коммит уже не будет доступен в текущей ветке. Последствия будут такими же, как при отмене изменений публичного снимка.

14. Откат последнего коммита

Откатить последний коммит можно с помощью параметра revert. Создастся новый коммит, содержащий обратные преобразования относительно предыдущего, и добавится к истории текущей ветки.

git revert HEAD

▍ Разница между revert и reset

Команда git revert отменяет изменения, записанные только одним коммитом. Она не откатывает проект к более раннему состоянию, удаляя все последующие коммиты, как это делает команда git reset.

У команды revert есть два крупных преимущества по сравнению с reset. Во-первых, она не меняет историю проекта и производит операцию, безопасную для коммитов. Во-вторых, её объектом выступает конкретный коммит, созданный в любой момент истории, а git reset всегда берёт за точку отсчёта текущий коммит. К примеру, если нужно отменить старый коммит с помощью git reset, придётся удалить все коммиты, поданные после целевого, а затем выполнить их повторно. Следовательно, команда git revert — гораздо более удобный и безопасный способ отмены изменений.

15. Откат заданного коммита

Откатить проект до заданного коммита можно с помощью параметра revert и идентификатора коммита. Создастся новый коммит — копия коммита с предоставленным идентификатором — и добавится к истории текущей ветки.

git revert 1af17e

16. Создание новой ветки и переход в неё

Создать новую ветку можно с помощью параметра branch, указав имя ветки.

git branch new_branch_name

Но Git не переключится на неё автоматически. Для автоматического перехода нужно добавить флаг -b и параметр checkout.

git checkout -b new_branch_name

17. Просмотр списка веток

Можно просматривать полный список веток, используя параметр branch. Команда отобразит все ветки, отметит текущую звёздочкой (*) и выделит её цветом.

git branch

Также можно вывести список удалённых веток с помощью флага -a.

git branch -a

18. Удаление ветки

Удалить ветку можно параметром branch с добавлением флага -d и указанием имени ветки. Если вы завершили работу над веткой и объединили её с основной, можно её удалить без потери истории. Однако, если выполнить команду удаления до слияния — в результате появится сообщение об ошибке. Этот защитный механизм предотвращает потерю доступа к файлам.

git branch -d existing_branch_name

Для принудительного удаления ветки используется флаг -D с заглавной буквой. В этом случае ветка будет удалена независимо от текущего статуса, без предупреждений.

git branch -D existing_branch_name

Вышеуказанные команды удаляют только локальную копию ветки. В удалённом репозитории она может сохраниться. Если хотите стереть удалённую ветку, выполните следующую команду:

git push origin --delete existing_branch_name

19. Слияние двух веток

Объединить две ветки можно параметром merge с указанием имени ветки. Команда объединит указанную ветку с основной.

git merge existing_branch_name

Если надо выполнить коммит слияния, выполните команду git merge с флагом --no-ff.

git merge --no-ff existing_branch_name

Указанная команда объединит заданную ветку с основной и произведёт коммит слияния. Это необходимо для фиксации всех слияний в вашем репозитории.

20. Отображение журнала фиксации в виде графика для текущей или всех веток

Просмотреть историю коммитов в виде графика для текущей ветки можно с помощью параметра log и флагов --graph --oneline --decorate. Опция --graph выведет график в формате ASCII, отражающий структуру ветвления истории коммитов. В связке с флагами --oneline и --decorate, этот флаг упрощает понимание того, к какой ветке относится каждый коммит.

git log --graph --oneline --decorate

Для просмотра истории коммитов по всем веткам используется флаг --all.

git log --all --graph --oneline --decorate

21. Прекращение слияния при конфликте

Прервать слияние в случае конфликта можно параметром merge с флагом --abort. Он позволяет остановить процесс слияния и вернуть состояние, с которого этот процесс был начат.

git merge --abort

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

git reset

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

Добавить удалённый репозиторий можно параметром remote add, указав shortname и url требуемого репозитория.

git remote add awesomeapp https://github.com/someurl..

23. Просмотр удалённых URL-адресов

Просматривать удалённые URL-адреса можно параметром remote с флагом -v. Этот параметр отображает удалённые подключения к другим репозиториям.

git remote -v

Такая команда открывает доступ к интерфейсу управления удалёнными записями, которые хранятся в файле .git/config репозитория.

24. Получение дополнительных сведений об удалённом репозитории

Получить подробные сведения об удалённом репозитории можно с помощью параметра remote show с указанием имени репозитория — например, origin.

git remote show origin

Эта команда отображает список веток, связанных с удалённым репозиторием, а также рабочих станций, подключённых для получения и отправки файлов.

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

Отправлять изменения в удалённый репозиторий можно параметром push с указанием имени репозитория и ветки.

git push origin main

Эта команда передаёт локальные изменения в центральный репозиторий, где с ними могут ознакомиться другие участники проекта.

26. Получение изменений из удалённого репозитория

Для загрузки изменений из удалённого репозитория используется параметр pull. Он скачивает копию текущей ветки с указанного удалённого репозитория и объединяет её с локальной копией.

git pull

Также можно просмотреть подробные сведения о загруженных файлах с помощью флага --verbose.

git pull --verbose

27. Слияние удалённого репозитория с локальным

Слияние удалённого репозитория с локальным выполняется параметром merge с указанием имени удалённого репозитория.

git merge origin

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

Передать новую ветку в удалённый репозиторий можно параметром push с флагом -u, указав имя репозитория и имя ветки.

git push -u origin new_branch

29. Удаление удалённой ветки

Чтобы избавиться от удалённой ветки, используйте параметр push с флагом --delete, указав имя удалённого репозитория и имя ветки.

git push --delete origin existing_branch

30. Использование перебазирования

Для доступа к этой функции используйте параметр rebase с указанием имени ветки. Перебазирование — это процесс объединения или перемещения последовательности коммитов на новый родительский снимок.

git rebase branch_name

Эта команда изменит основу ветки с одного коммита на другой, как если бы вы начали ветку с другого коммита. В Git это достигается за счёт создания новых коммитов и применения их к указанному базовому коммиту. Необходимо понимать, что, хотя ветка и выглядит такой же, она состоит из совершенно новых коммитов.

▍ Спасибо за внимание!

Вы узнали 30 основных команд интерфейса командной строки Git. Теперь, при условии регулярной практики, у вас есть всё необходимое, чтобы достичь мастерства в управлении репозиториями GitHub.

Понравилась статья? Поделить с друзьями:

Не пропустите также:

  • Как составить пресс релиз организации
  • Как найти хороший велосипед
  • Как правильно составить тренировку в тренажерном зале женщине
  • Как собаке найти кабеля
  • Как составить медицинскую книжку

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии