gittutorial(7) Manual Page
This tutorial explains how to import a new project into Git, make changes to it, and share changes with other developers.
If you are instead primarily interested in using Git to fetch a project, for example, to test the latest version, you may prefer to start with the first two chapters of The Git User’s Manual.
First, note that you can get documentation for a command such as git log —graph with:
With the latter, you can use the manual viewer of your choice; see git-help(1) for more information.
It is a good idea to introduce yourself to Git with your name and public email address before doing any operation. The easiest way to do so is:
Importing a new project
Assume you have a tarball project.tar.gz with your initial work. You can place it under Git revision control as follows.
You’ve now initialized the working directory—you may notice a new directory created, named «.git».
Next, tell Git to take a snapshot of the contents of all files under the current directory (note the .), with git add:
This snapshot is now stored in a temporary staging area which Git calls the «index». You can permanently store the contents of the index in the repository with git commit:
This will prompt you for a commit message. You’ve now stored the first version of your project in Git.
Making changes
Modify some files, then add their updated contents to the index:
You are now ready to commit. You can see what is about to be committed using git diff with the —cached option:
(Without —cached, git diff will show you any changes that you’ve made but not yet added to the index.) You can also get a brief summary of the situation with git status:
If you need to make any further adjustments, do so now, and then add any newly modified content to the index. Finally, commit your changes with:
This will again prompt you for a message describing the change, and then record a new version of the project.
Alternatively, instead of running git add beforehand, you can use
which will automatically notice any modified (but not new) files, add them to the index, and commit, all in one step.
A note on commit messages: Though not required, it’s a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout Git. For example, git-format-patch(1) turns a commit into email, and it uses the title on the Subject line and the rest of the commit in the body.
Git tracks content not files
Many revision control systems provide an add command that tells the system to start tracking changes to a new file. Git’s add command does something simpler and more powerful: git add is used both for new and newly modified files, and in both cases it takes a snapshot of the given files and stages that content in the index, ready for inclusion in the next commit.
Viewing project history
At any point you can view the history of your changes using
If you also want to see complete diffs at each step, use
Often the overview of the change is useful to get a feel of each step
Managing branches
A single Git repository can maintain multiple branches of development. To create a new branch named «experimental», use
you’ll get a list of all existing branches:
The «experimental» branch is the one you just created, and the «master» branch is a default branch that was created for you automatically. The asterisk marks the branch you are currently on; type
to switch to the experimental branch. Now edit a file, commit the change, and switch back to the master branch:
Check that the change you made is no longer visible, since it was made on the experimental branch and you’re back on the master branch.
You can make a different change on the master branch:
at this point the two branches have diverged, with different changes made in each. To merge the changes made in experimental into master, run
If the changes don’t conflict, you’re done. If there are conflicts, markers will be left in the problematic files showing the conflict;
will show this. Once you’ve edited the files to resolve the conflicts,
will commit the result of the merge. Finally,
will show a nice graphical representation of the resulting history.
At this point you could delete the experimental branch with
This command ensures that the changes in the experimental branch are already in the current branch.
If you develop on a branch crazy-idea, then regret it, you can always delete the branch with
Branches are cheap and easy, so this is a good way to try something out.
Using Git for collaboration
Suppose that Alice has started a new project with a Git repository in /home/alice/project, and that Bob, who has a home directory on the same machine, wants to contribute.
Bob begins with:
This creates a new directory «myrepo» containing a clone of Alice’s repository. The clone is on an equal footing with the original project, possessing its own copy of the original project’s history.
Bob then makes some changes and commits them:
When he’s ready, he tells Alice to pull changes from the repository at /home/bob/myrepo. She does this with:
This merges the changes from Bob’s «master» branch into Alice’s current branch. If Alice has made her own changes in the meantime, then she may need to manually fix any conflicts.
The «pull» command thus performs two operations: it fetches changes from a remote branch, then merges them into the current branch.
Note that in general, Alice would want her local changes committed before initiating this «pull». If Bob’s work conflicts with what Alice did since their histories forked, Alice will use her working tree and the index to resolve conflicts, and existing local changes will interfere with the conflict resolution process (Git will still perform the fetch but will refuse to merge — Alice will have to get rid of her local changes in some way and pull again when this happens).
Alice can peek at what Bob did without merging first, using the «fetch» command; this allows Alice to inspect what Bob did, using a special symbol «FETCH_HEAD», in order to determine if he has anything worth pulling, like this:
This operation is safe even if Alice has uncommitted local changes. The range notation «HEAD..FETCH_HEAD» means «show everything that is reachable from the FETCH_HEAD but exclude anything that is reachable from HEAD». Alice already knows everything that leads to her current state (HEAD), and reviews what Bob has in his state (FETCH_HEAD) that she has not seen with this command.
If Alice wants to visualize what Bob did since their histories forked she can issue the following command:
This uses the same two-dot range notation we saw earlier with git log.
Alice may want to view what both of them did since they forked. She can use three-dot form instead of the two-dot form:
This means «show everything that is reachable from either one, but exclude anything that is reachable from both of them».
Please note that these range notation can be used with both gitk and «git log».
After inspecting what Bob did, if there is nothing urgent, Alice may decide to continue working without pulling from Bob. If Bob’s history does have something Alice would immediately need, Alice may choose to stash her work-in-progress first, do a «pull», and then finally unstash her work-in-progress on top of the resulting history.
When you are working in a small closely knit group, it is not unusual to interact with the same repository over and over again. By defining remote repository shorthand, you can make it easier:
With this, Alice can perform the first part of the «pull» operation alone using the git fetch command without merging them with her own branch, using:
Unlike the longhand form, when Alice fetches from Bob using a remote repository shorthand set up with git remote, what was fetched is stored in a remote-tracking branch, in this case bob/master . So after this:
shows a list of all the changes that Bob made since he branched from Alice’s master branch.
After examining those changes, Alice could merge the changes into her master branch:
This merge can also be done by pulling from her own remote-tracking branch, like this:
Note that git pull always merges into the current branch, regardless of what else is given on the command line.
Later, Bob can update his repo with Alice’s latest changes using
Note that he doesn’t need to give the path to Alice’s repository; when Bob cloned Alice’s repository, Git stored the location of her repository in the repository configuration, and that location is used for pulls:
(The complete configuration created by git clone is visible using git config -l , and the git-config(1) man page explains the meaning of each option.)
Git also keeps a pristine copy of Alice’s master branch under the name «origin/master»:
If Bob later decides to work from a different host, he can still perform clones and pulls using the ssh protocol:
Alternatively, Git has a native protocol, or can use http; see git-pull(1) for details.
Git can also be used in a CVS-like mode, with a central repository that various users push changes to; see git-push(1) and gitcvs-migration(7).
Exploring history
Git history is represented as a series of interrelated commits. We have already seen that the git log command can list those commits. Note that first line of each git log entry also gives a name for the commit:
We can give this name to git show to see the details about this commit.
But there are other ways to refer to commits. You can use any initial part of the name that is long enough to uniquely identify the commit:
Every commit usually has one «parent» commit which points to the previous state of the project:
Note that merge commits may have more than one parent:
You can also give commits names of your own; after running
you can refer to 1b2e1d63ff by the name «v2.5». If you intend to share this name with other people (for example, to identify a release version), you should create a «tag» object, and perhaps sign it; see git-tag(1) for details.
Any Git command that needs to know a commit can take any of these names. For example:
Be careful with that last command: in addition to losing any changes in the working directory, it will also remove all later commits from this branch. If this branch is the only branch containing those commits, they will be lost. Also, don’t use git reset on a publicly-visible branch that other developers pull from, as it will force needless merges on other developers to clean up the history. If you need to undo changes that you have pushed, use git revert instead.
The git grep command can search for strings in any version of your project, so
searches for all occurrences of «hello» in v2.5.
If you leave out the commit name, git grep will search any of the files it manages in your current directory. So
is a quick way to search just the files that are tracked by Git.
Many Git commands also take sets of commits, which can be specified in a number of ways. Here are some examples with git log:
You can also give git log a «range» of commits where the first is not necessarily an ancestor of the second; for example, if the tips of the branches «stable» and «master» diverged from a common commit some time ago, then
will list commits made in the master branch but not in the stable branch, while
will show the list of commits made on the stable branch but not the master branch.
The git log command has a weakness: it must present commits in a list. When the history has lines of development that diverged and then merged back together, the order in which git log presents those commits is meaningless.
Most projects with multiple contributors (such as the Linux kernel, or Git itself) have frequent merges, and gitk does a better job of visualizing their history. For example,
allows you to browse any commits from the last 2 weeks of commits that modified files under the «drivers» directory. (Note: you can adjust gitk’s fonts by holding down the control key while pressing «-» or «+».)
Finally, most commands that take filenames will optionally allow you to precede any filename by a commit, to specify a particular version of the file:
You can also use git show to see any such file:
Next Steps
This tutorial should be enough to perform basic distributed revision control for your projects. However, to fully understand the depth and power of Git you need to understand two simple ideas on which it is based:
The object database is the rather elegant system used to store the history of your project—files, directories, and commits.
The index file is a cache of the state of a directory tree, used to create commits, check out working directories, and hold the various trees involved in a merge.
Part two of this tutorial explains the object database, the index file, and a few other odds and ends that you’ll need to make the most of Git. You can find it at gittutorial-2(7).
If you don’t want to continue with that right away, a few other digressions that may be interesting at this point are:
git-format-patch(1), git-am(1): These convert series of git commits into emailed patches, and vice versa, useful for projects such as the Linux kernel which rely heavily on emailed patches.
git-bisect(1): When there is a regression in your project, one way to track down the bug is by searching through the history to find the exact commit that’s to blame. Git bisect can help you perform a binary search for that commit. It is smart enough to perform a close-to-optimal search even in the case of complex non-linear history with lots of merged branches.
2.2 Основы Git — Запись изменений в репозиторий
Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта. Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.
Запомните, каждый файл в вашем рабочем каталоге может находиться в одном из двух состояний: под версионным контролем (отслеживаемые) и нет (неотслеживаемые). Отслеживаемые файлы — это те файлы, которые были в последнем снимке состояния проекта; они могут быть неизменёнными, изменёнными или подготовленными к коммиту. Если кратко, то отслеживаемые файлы — это те файлы, о которых знает Git.
Неотслеживаемые файлы — это всё остальное, любые файлы в вашем рабочем каталоге, которые не входили в ваш последний снимок состояния и не подготовлены к коммиту. Когда вы впервые клонируете репозиторий, все файлы будут отслеживаемыми и неизменёнными, потому что Git только что их извлек и вы ничего пока не редактировали.
Как только вы отредактируете файлы, Git будет рассматривать их как изменённые, так как вы изменили их с момента последнего коммита. Вы индексируете эти изменения, затем фиксируете все проиндексированные изменения, а затем цикл повторяется.

Определение состояния файлов
Основной инструмент, используемый для определения, какие файлы в каком состоянии находятся — это команда git status . Если вы выполните эту команду сразу после клонирования, вы увидите что-то вроде этого:
Это означает, что у вас чистый рабочий каталог, другими словами — в нем нет отслеживаемых измененных файлов. Git также не обнаружил неотслеживаемых файлов, в противном случае они бы были перечислены здесь. Наконец, команда сообщает вам на какой ветке вы находитесь и сообщает вам, что она не расходится с веткой на сервере. Пока что это всегда ветка master , ветка по умолчанию; в этой главе это не важно. В главе Ветвление в Git будут рассмотрены ветки и ссылки более детально.
Предположим, вы добавили в свой проект новый файл, простой файл README . Если этого файла раньше не было, и вы выполните git status , вы увидите свой неотслеживаемый файл вот так:
Понять, что новый файл README неотслеживаемый можно по тому, что он находится в секции «Untracked files» в выводе команды status . Статус Untracked означает, что Git видит файл, которого не было в предыдущем снимке состояния (коммите); Git не станет добавлять его в ваши коммиты, пока вы его явно об этом не попросите. Это предохранит вас от случайного добавления в репозиторий сгенерированных бинарных файлов или каких-либо других, которые вы и не думали добавлять. Мы хотели добавить README, так давайте сделаем это.
Отслеживание новых файлов
Для того чтобы начать отслеживать (добавить под версионный контроль) новый файл, используется команда git add . Чтобы начать отслеживание файла README , вы можете выполнить следующее:
Если вы снова выполните команду status , то увидите, что файл README теперь отслеживаемый и добавлен в индекс:
Вы можете видеть, что файл проиндексирован, так как он находится в секции «Changes to be committed». Если вы выполните коммит в этот момент, то версия файла, существовавшая на момент выполнения вами команды git add , будет добавлена в историю снимков состояния. Как вы помните, когда вы ранее выполнили git init , затем вы выполнили git add (файлы) — это было сделано для того, чтобы добавить файлы в вашем каталоге под версионный контроль. Команда git add принимает параметром путь к файлу или каталогу, если это каталог, команда рекурсивно добавляет все файлы из указанного каталога в индекс.
Индексация изменённых файлов
Давайте модифицируем файл, уже находящийся под версионным контролем. Если вы измените отслеживаемый файл CONTRIBUTING.md и после этого снова выполните команду git status , то результат будет примерно следующим:
Файл CONTRIBUTING.md находится в секции «Changes not staged for commit» — это означает, что отслеживаемый файл был изменён в рабочем каталоге, но пока не проиндексирован. Чтобы проиндексировать его, необходимо выполнить команду git add . Это многофункциональная команда, она используется для добавления под версионный контроль новых файлов, для индексации изменений, а также для других целей, например для указания файлов с исправленным конфликтом слияния. Вам может быть понятнее, если вы будете думать об этом как «добавить этот контент в следующий коммит», а не как «добавить этот файл в проект». Выполним git add , чтобы проиндексировать CONTRIBUTING.md , а затем снова выполним git status :
Теперь оба файла проиндексированы и войдут в следующий коммит. В этот момент вы, предположим, вспомнили одно небольшое изменение, которое вы хотите сделать в CONTRIBUTING.md до коммита. Вы открываете файл, вносите и сохраняете необходимые изменения и вроде бы готовы к коммиту. Но давайте-ка ещё раз выполним git status :
Что за чёрт? Теперь CONTRIBUTING.md отображается как проиндексированный и непроиндексированный одновременно. Как такое возможно? Такая ситуация наглядно демонстрирует, что Git индексирует файл в точности в том состоянии, в котором он находился, когда вы выполнили команду git add . Если вы выполните коммит сейчас, то файл CONTRIBUTING.md попадёт в коммит в том состоянии, в котором он находился, когда вы последний раз выполняли команду git add , а не в том, в котором он находится в вашем рабочем каталоге в момент выполнения git commit . Если вы изменили файл после выполнения git add , вам придётся снова выполнить git add , чтобы проиндексировать последнюю версию файла:
Сокращенный вывод статуса
Вывод команды git status довольно всеобъемлющий и многословный. Git также имеет флаг вывода сокращенного статуса, так что вы можете увидеть изменения в более компактном виде. Если вы выполните git status -s или git status —short вы получите гораздо более упрощенный вывод:
Новые неотслеживаемые файлы помечены ?? слева от них, файлы добавленные в отслеживаемые помечены A , отредактированные файлы помечены M и так далее. В выводе содержится два столбца — в левом указывается статус файла, а в правом модифицирован ли он после этого. К примеру в нашем выводе, файл README модифицирован в рабочем каталоге, но не проиндексирован, а файл lib/simplegit.rb модифицирован и проиндексирован. Файл Rakefile модифицирован, проиндексирован и ещё раз модифицирован, таким образом на данный момент у него есть те изменения, которые попадут в коммит, и те, которые не попадут.
Игнорирование файлов
Зачастую, у вас имеется группа файлов, которые вы не только не хотите автоматически добавлять в репозиторий, но и видеть в списках неотслеживаемых. К таким файлам обычно относятся автоматически генерируемые файлы (различные логи, результаты сборки программ и т. п.). В таком случае, вы можете создать файл .gitignore . с перечислением шаблонов соответствующих таким файлам. Вот пример файла .gitignore :
Первая строка предписывает Git игнорировать любые файлы заканчивающиеся на «.o» или «.a» — объектные и архивные файлы, которые могут появиться во время сборки кода. Вторая строка предписывает игнорировать все файлы заканчивающиеся на тильду (
), которая используется во многих текстовых редакторах, например Emacs, для обозначения временных файлов. Вы можете также включить каталоги log, tmp или pid; автоматически создаваемую документацию; и т. д. и т. п. Хорошая практика заключается в настройке файла .gitignore до того, как начать серьёзно работать, это защитит вас от случайного добавления в репозиторий файлов, которых вы там видеть не хотите.
К шаблонам в файле .gitignore применяются следующие правила:
Пустые строки, а также строки, начинающиеся с # , игнорируются.
Стандартные шаблоны являются глобальными и применяются рекурсивно для всего дерева каталогов.
Чтобы избежать рекурсии используйте символ слеш (/) в начале шаблона.
Чтобы исключить каталог добавьте слеш (/) в конец шаблона.
Можно инвертировать шаблон, использовав восклицательный знак (!) в качестве первого символа.
Glob-шаблоны представляют собой упрощённые регулярные выражения, используемые командными интерпретаторами. Символ ( * ) соответствует 0 или более символам; последовательность [abc] — любому символу из указанных в скобках (в данном примере a, b или c); знак вопроса ( ? ) соответствует одному символу; и квадратные скобки, в которые заключены символы, разделённые дефисом ( [0-9] ), соответствуют любому символу из интервала (в данном случае от 0 до 9). Вы также можете использовать две звёздочки, чтобы указать на вложенные каталоги: a/**/z соответствует a/z , a/b/z , a/b/c/z , и так далее.
Вот ещё один пример файла .gitignore :
GitHub поддерживает довольно полный список примеров .gitignore файлов для множества проектов и языков https://github.com/github/gitignore это может стать отправной точкой для .gitignore в вашем проекте.
В простейшем случае репозиторий будет иметь один файл .gitignore в корневом каталоге, правила из которого будут рекурсивно применяться ко всем подкаталогам. Так же возможно использовать .gitignore файлы в подкаталогах. Правила из этих файлов будут применяться только к каталогам, в которых они находятся. Например, репозиторий исходного кода ядра Linux содержит 206 файлов .gitignore .
Детальное рассмотрение использования нескольких .gitignore файлов выходит за пределы этой книги; детали доступны в справке man gitignore .
Просмотр индексированных и неиндексированных изменений
Если результат работы команды git status недостаточно информативен для вас — вам хочется знать, что конкретно поменялось, а не только какие файлы были изменены — вы можете использовать команду git diff . Позже мы рассмотрим команду git diff подробнее; вы, скорее всего, будете использовать эту команду для получения ответов на два вопроса: что вы изменили, но ещё не проиндексировали, и что вы проиндексировали и собираетесь включить в коммит. Если git status отвечает на эти вопросы в самом общем виде, перечисляя имена файлов, git diff показывает вам непосредственно добавленные и удалённые строки — патч как он есть.
Допустим, вы снова изменили и проиндексировали файл README , а затем изменили файл CONTRIBUTING.md без индексирования. Если вы выполните команду git status , вы опять увидите что-то вроде:
Чтобы увидеть, что же вы изменили, но пока не проиндексировали, наберите git diff без аргументов:
Эта команда сравнивает содержимое вашего рабочего каталога с содержимым индекса. Результат показывает ещё не проиндексированные изменения.
Если вы хотите посмотреть, что вы проиндексировали и что войдёт в следующий коммит, вы можете выполнить git diff —staged . Эта команда сравнивает ваши проиндексированные изменения с последним коммитом:
Важно отметить, что git diff сама по себе не показывает все изменения сделанные с последнего коммита — только те, что ещё не проиндексированы. Такое поведение может сбивать с толку, так как если вы проиндексируете все свои изменения, то git diff ничего не вернёт.
Другой пример: вы проиндексировали файл CONTRIBUTING.md и затем изменили его, вы можете использовать git diff для просмотра как проиндексированных изменений в этом файле, так и тех, что пока не проиндексированы. Если наше окружение выглядит вот так:
Используйте git diff для просмотра непроиндексированных изменений
а так же git diff —cached для просмотра проиндексированных изменений ( —staged и —cached синонимы):
Мы будем продолжать использовать команду git diff различными способами на протяжении всей книги. Существует еще один способ просматривать эти изменения, если вы предпочитаете графический просмотр или внешнюю программу просмотра различий, вместо консоли. Выполнив команду git difftool вместо git diff , вы сможете просмотреть изменения в файле с помощью таких программ как emerge, vimdiff и других (включая коммерческие продукты). Выполните git difftool —tool-help чтобы увидеть какие из них уже установлены в вашей системе.
Коммит изменений
Теперь, когда ваш индекс находится в таком состоянии, как вам и хотелось, вы можете зафиксировать свои изменения. Запомните, всё, что до сих пор не проиндексировано — любые файлы, созданные или изменённые вами, и для которых вы не выполнили git add после редактирования — не войдут в этот коммит. Они останутся изменёнными файлами на вашем диске. В нашем случае, когда вы в последний раз выполняли git status , вы видели что всё проиндексировано, и вот, вы готовы к коммиту. Простейший способ зафиксировать изменения — это набрать git commit :
Эта команда откроет выбранный вами текстовый редактор.
Редактор устанавливается переменной окружения EDITOR — обычно это vim или emacs, хотя вы можете установить любой другой с помощью команды git config —global core.editor , как было показано в главе Введение).
В редакторе будет отображён следующий текст (это пример окна Vim):
Вы можете видеть, что комментарий по умолчанию для коммита содержит закомментированный результат работы команды git status и ещё одну пустую строку сверху. Вы можете удалить эти комментарии и набрать своё сообщение или же оставить их для напоминания о том, что вы фиксируете.
Для ещё более подробного напоминания, что же именно вы поменяли, можете передать аргумент -v в команду git commit . Это приведёт к тому, что в комментарий будет также помещена дельта/diff изменений, таким образом вы сможете точно увидеть все изменения которые вы совершили.
Когда вы выходите из редактора, Git создаёт для вас коммит с этим сообщением, удаляя комментарии и вывод команды diff .
Есть и другой способ — вы можете набрать свой комментарий к коммиту в командной строке вместе с командой commit указав его после параметра -m , как в следующем примере:
Итак, вы создали свой первый коммит! Вы можете видеть, что коммит вывел вам немного информации о себе: на какую ветку вы выполнили коммит ( master ), какая контрольная сумма SHA-1 у этого коммита ( 463dc4f ), сколько файлов было изменено, а также статистику по добавленным/удалённым строкам в этом коммите.
Запомните, что коммит сохраняет снимок состояния вашего индекса. Всё, что вы не проиндексировали, так и висит в рабочем каталоге как изменённое; вы можете сделать ещё один коммит, чтобы добавить эти изменения в репозиторий. Каждый раз, когда вы делаете коммит, вы сохраняете снимок состояния вашего проекта, который позже вы можете восстановить или с которым можно сравнить текущее состояние.
Игнорирование индексации
Несмотря на то, что индекс может быть удивительно полезным для создания коммитов именно такими, как вам и хотелось, он временами несколько сложнее, чем вам нужно в процессе работы. Если у вас есть желание пропустить этап индексирования, Git предоставляет простой способ. Добавление параметра -a в команду git commit заставляет Git автоматически индексировать каждый уже отслеживаемый на момент коммита файл, позволяя вам обойтись без git add :
Обратите внимание, что в данном случае перед коммитом вам не нужно выполнять git add для файла CONTRIBUTING.md , потому что флаг -a включает все файлы. Это удобно, но будьте осторожны: флаг -a может включить в коммит нежелательные изменения.
Удаление файлов
Для того чтобы удалить файл из Git, вам необходимо удалить его из отслеживаемых файлов (точнее, удалить его из вашего индекса) а затем выполнить коммит. Это позволяет сделать команда git rm , которая также удаляет файл из вашего рабочего каталога, так что в следующий раз вы не увидите его как «неотслеживаемый».
Если вы просто удалите файл из своего рабочего каталога, он будет показан в секции «Changes not staged for commit» (измененные, но не проиндексированные) вывода команды git status :
Затем, если вы выполните команду git rm , удаление файла попадёт в индекс:
После следующего коммита файл исчезнет и больше не будет отслеживаться. Если вы изменили файл и уже проиндексировали его, вы должны использовать принудительное удаление с помощью параметра -f . Это сделано для повышения безопасности, чтобы предотвратить ошибочное удаление данных, которые ещё не были записаны в снимок состояния и которые нельзя восстановить из Git.
Другая полезная штука, которую вы можете захотеть сделать — это удалить файл из индекса, оставив его при этом в рабочем каталоге. Другими словами, вы можете захотеть оставить файл на жёстком диске, но перестать отслеживать изменения в нём. Это особенно полезно, если вы забыли добавить что-то в файл .gitignore и по ошибке проиндексировали, например, большой файл с логами, или кучу промежуточных файлов компиляции. Чтобы сделать это, используйте опцию —cached :
В команду git rm можно передавать файлы, каталоги или шаблоны. Это означает, что вы можете сделать что-то вроде:
Обратите внимание на обратный слеш ( \ ) перед * . Он необходим из-за того, что Git использует свой собственный обработчик имён файлов вдобавок к обработчику вашего командного интерпретатора. Эта команда удаляет все файлы, имеющие расширение .log и находящиеся в каталоге log/ . Или же вы можете сделать вот так:
Эта команда удаляет все файлы, имена которых заканчиваются на
Перемещение файлов
В отличие от многих других систем контроля версий, Git не отслеживает перемещение файлов явно. Когда вы переименовываете файл в Git, в нём не сохраняется никаких метаданных, говорящих о том, что файл был переименован. Однако, Git довольно умён в плане обнаружения перемещений постфактум — мы рассмотрим обнаружение перемещения файлов чуть позже.
Таким образом, наличие в Git команды mv выглядит несколько странным. Если вам хочется переименовать файл в Git, вы можете сделать что-то вроде:
и это отлично сработает. На самом деле, если вы выполните что-то вроде этого и посмотрите на статус, вы увидите, что Git считает, что произошло переименование файла:
Однако, это эквивалентно выполнению следующих команд:
Git неявно определяет, что произошло переименование, поэтому неважно, переименуете вы файл так или используя команду mv . Единственное отличие состоит лишь в том, что mv — одна команда вместо трёх — это функция для удобства. Важнее другое — вы можете использовать любой удобный способ для переименования файла, а затем воспользоваться командами add или rm перед коммитом.
Git. Коротко о главном

Привет, Хабр! Меня зовут Егор, я занимаюсь разработкой мобильных приложений на Flutter. Это моя первая работа в сфере IT, и как подобает начинающим, я столкнулся с проблемой изучения систем контроля версий. В данной публикации я хочу поделиться приобретенными знаниями и подробно рассмотреть одну из таких систем, а именно Git. Итак, начнем.
“Whoah, I’ve just read this quick tuto about git and oh my god it is cool. I feel now super comfortable using it, and I’m not afraid at all to break something.” — said no one ever.
Не так страшен чёрт, как его малюют. Хотя, как мне кажется, это не касается Git. Так или иначе многие сталкиваются с необходимостью обучиться грамотной работе с этим инструментом. Несмотря на обилие информации и туториалов, это задача является не самой тривиальной. Исходя из своего опыта, могу сделать вывод: необходимо изучить самые разные ресурсы, прежде чем наступит понимание.
Полагаю, все дело в том, что изучение Git — комплексная тема, и охватить ее в одной статье, чтобы быстренько освоить азы и тут же применить знания на практике, несколько сложно.
Тем не менее, я бы хотел дополнить просторы интернета очередной статьей о Git. Постараюсь изложить все таким образом, как если бы у меня была возможность объяснить все самому себе из прошлого. Как следует из названия, я расскажу о Git очень коротко; а точнее о возможностях, которые он нам предоставляет.
Перед тем, как говорить про какую-либо конкретную систему контроля версий, необходимо понимать, что это такое и какими они бывают.
Система контроля версий — это программное обеспечение, помогающее разработчикам управлять состоянием исходного кода на протяжение всей разработки. Другими словами, это система, которая записывает ваши изменения в файл и позже позволяет откатиться к более ранней версии проекта.
Системы контроля версий можно разделить на две группы:
1. Централизованные системы контроля версий;
2. Распределенные системы контроля версий.
Централизованная система контроля версий — это система, при которой репозиторий проекта хранится на сервере и вносить изменения вы можете непосредственно только в этот репозиторий при помощи специальных клиентских приложений. Среди таких систем можно выделить: ClearCase, TFVC, SVN.
Распределенная система контроля версий — это система, при которой копия репозитория может храниться на машине у каждого разработчика, что значительно снижает риск потерять результат работы над проектом. Примером таких систем могут быть: Git, Mercurial, Bazaar.
Git является распределенной системой контроля версий, разработанной Линусом Торвальдсом для управления разработкой ядра Linux. На данный момент Git завоевал огромную популярность в IT сообществе и, как следствие, его часто можно встретить в стеке технологий различных компаний.
Далее я расскажу про структуру Git репозитория и как его завести. Познакомлю вас с основными, наиболее популярными командами в Git. Также вы узнаете о том, как инспектировать историю своего проекта и как откатить его до определенной точки. И, в заключение, я слегка затрону тему ветвления.
Установка Git
Прежде чем мы продолжим, вам необходимо установить Git.
Ниже я представлю краткую инструкцию к установке, но вы также можете пройти по этой ссылке на официальный источник и разобраться в этом самостоятельно.
Windows. Перейдите по ссылке и скачайте Git соответствующий архитектуре вашего процессора (32 или 64-bit) и установите его.
Linux. Перейдите по ссылке для более подробной инструкции.
Структура директории .git/
Как правило, ваша работа с Git будет начинаться с того, что вам потребуется проинициализировать Git директорию в своем проекте. Это делается с помощью команды:
Ее необходимо ввести в корне вашего проекта. Это создаст в текущем каталоге новый подкаталог .git со следующим содержанием:

Структура директории .git
В данной директории будет содержаться вся конфигурация Git и история проекта. При желании можно править эти файлы вручную, внося необходимые изменения в историю проекта.
В данном файле содержатся настройки Git репозитория. Например, здесь можно хранить email и имя пользователя.
Данный файл предназначен для GitWeb и содержит в себе информацию о проекте (название проекта и его описание). GitWeb — это веб интерфейс, написанный для просмотра Git репозитория используя веб-браузер. Если вы не пользуетесь GitWeb, то это не столь важно.
В этом каталоге Git предоставляет набор скриптов, которые могут автоматически запускаться во время выполнения git команд. В некоторых случаях это значительно упрощает разработку. Например, вы можете написать скрипт, который будет редактировать сообщение коммита согласно вашим требованиям.
4. info — exclude
Каталог info содержит файл exclude, в котором можно указывать любые файлы, и Git не станет добавлять их в свою историю. Это почти то же самое что и .gitingnore (возможно вы сталкивались с ним. Его можно найти в корневом каталоге вашего проекта), за тем исключением, что exclude не сохраняется в истории проекта, и вы не сможете им поделиться с другими.
Каталог refs хранит в себе копию ссылок на объекты коммитов в локальных и удаленных ветках.
Каталог logs хранит в себе историю проекта для всех веток в вашем проекте.
Каталог objects хранит в себе BLOB объекты, каждый из которых проиндексирован уникальным SHA.
Промежуточная область с метаданными, такими как временные метки, имена файлов, а также SHA файлов, которые уже упакованы Git. В эту область попадают файлы, над которыми вы работали, при выполнение команды git add .
Файл содержит ссылку на текущую ветку, в которой вы работаете
Каждый раз во время слияния в этот файл попадает SHA ветки, с которой проводилось слияние
Файл хранит в себе ссылки в виде SHA на ветки, которые участвовали в git fetch
Файл хранит в себе ссылки в виде SHA на ветки, которые участвовали в git merge
Файл содержит в себе последнее введенное вами сообщение коммита
Самые распространенные команды в Git.

При работе с системами контроля версий разработчики сталкиваются с определенной, повторяющейся последовательностью действий. Оно и понятно, ведь, по сути, если не брать в расчет возможности Git для управления состоянием проекта и прочие плюшки, то как правило ваша работа ограничена рядом действий:
1. Внести изменения в проект;
2. Добавить изменения в индекс(staging area) — git add (таким образом вы сообщаете Git какие именно изменения должны быть занесены в историю.)
2. Закоммитить изменения — git commit (сохранить изменения в историю проекта)
3. Запушить — git push (отправить результаты работы на удаленный сервер, чтобы другие разработчики тоже имели к ним доступ)
Итак, разберемся в этом подробнее. Проинициализировав Git репозиторий, вы начинаете вносить какие-то изменения в проект. Предположим, что вы создали файл `hello_world.txt` и работаете над его редактированием.
Введем git status и увидим следующее:
Команда git status отображает состояние директории и индекса(staging area). Это позволяет определить, какие файлы в проекте отслеживаются Git, а также какие изменения будут включены в следующий коммит.
Так как вы создали новый файл, Git определяет его как неотслеживаемый, и тут же подсказывает, что делать дальше:
git add hello_world.txt
Файл добавлен в индекс. Теперь можно закоммитить внесенные изменения и оставить небольшое описание. Делается это командой:
git commit -m ‘first commit
Готово! Мы сделали наш первый коммит! Далее добавим в наш файл строку “Hello, World!”, и снова проверим git status:
Теперь Git сообщает, что у нас есть измененный файл hello_world.txt . И теперь нам сново нужно добавить его в индекс и затем закоммитить.
Что ж, мы научились записывать и хранить изменения на своей машине, теперь нам нужно отправить версию нашей истории на удаленный сервер. В данном примере я воспользуюсь репозиторием на GitHub.
Для начала вам нужно создать удаленный репозиторий. Как это реализовать в случае с GitHub подробно описано тут.
Далее необходимо добавить удаленный репозиторий в Git:
git remote add <remote_name> <remote_repo_url>
Эта команда сопоставит удаленное хранилище с ссылкой на локальный репозиторий. С этого момента можно обращаться к удаленному репозиторию через эту ссылку. Например:
git remote add origin https://github.com/user/hello_world.git
В данном случае “origin” является коротким именем для удаленного репозитория, на которое он будет ссылаться. Вы можете выбрать совершенно любое имя — это не важно. “origin” это просто стандартное соглашение.
Осталось дело за малым — отправить результат нашей работы в репозиторий. Делается это следующим образом:
git push origin
Готово! Теперь история изменений вашего проекта будет храниться в удаленном репозитории.
Работа с историей

Итак, как записывать, сохранять и отправлять изменения в удаленное хранилище мы разобрались.
Настало время поговорить о том, как управлять историей проекта. А именно как просматривать изменения и как откатить проект до определенной точки.
Для инспектирования истории в Git предусмотрен определенный ряд команд, рассмотрим несколько из них:
Данная команда предназначена для отображения всей вашей истории. Она может быть весьма удобна, если вам понадобилось узнать, какие изменения вы вносили ранее. Или если вам нужно откатиться до определенного места в истории, либо если есть нужда её отредактировать.
Если ввести git log без каких либо параметров, выглядит это примерно так:
git log имеет огромное множество дополнительных параметров, которые будут влиять на вывод в консоль. Вам предоставляется выбор на любой вкус.
Хотите просмотреть последние три коммита? Пожалуйста:
Есть необходимость вывести все в одну линию? Запросто:
git log —oneline
Так можно продолжать до бесконечности, поэтому я оставлю ссылочку, перейдя по которой, вы сможете с ними подробней ознакомиться.
Команда git show используется для отображения полной информации о любом объекте в Git, будь то коммит или ветка. По умолчанию git show отображает информацию коммита, на который в данный момент времени указывает HEAD.
Для удобства работы git show оснащен рядом дополнительных параметров, некоторые из них мы рассмотрим ниже.
Итак, если ввести git show , мы получим следующий результат:
Здесь представлена полная информация о последнем коммите, а также какие именно изменения он в себя включает.
Мы также можем вывести диапазон из указанных коммитов. Диапазон указывается полуоткрытым интервалом, содержащим id коммитов, не включая первый элемент. Выглядит это следующим образом:
git show 349de9d..957e113
Для более лаконичного вывода, можно воспользоваться командой:
git show —oneline
Таким образом, мы сократим id коммита, а также исключим авторство и дату коммита.
Подробнее с командой `git show` и с её параметрами можно ознакомиться перейдя по ссылке.
Эта команда выводит упорядоченный список коммитов, на которые указывал HEAD. Грубо говоря, она отображает историю всех ваших перемещений по проекту.
Основное преимущество этой команды заключается в том, что если вы вдруг случайно удалили часть истории или откатились назад, вы сможете проинспектировать момент утраты нужной вам информации и откатиться обратно.
Это возможно за счет того, что git reflog хранит свою информацию на вашей машине отдельно от коммитов, поэтому при удалении чего-либо в истории, в сможете это найти в git reflog .
Вывод этой команды выглядит следующим образом:

Теперь давайте рассмотрим очень полезную команду `git reset`. Она позволяет откатить проект до определенной точки.
Эту команду можно использовать с тремя параметрами:
git reset —soft <commit>
git reset —mixed <commit>
git reset —hard <commit>
Рассмотрим их по порядку. Для этого сначала давайте вспомним, что такое index. Как я упоминал ранее, index — это временный файл, который фиксирует структуру Git проекта в определенный момент времени. Это важная деталь сейчас, поскольку команда git reset в зависимости от параметра прокидывает нас в истории проекта с соответствующими состояниями индекса.
1. В случае с —soft , содержимое вашего индекса, а также рабочей директории, остается неизменным. Это значит, что если мы откатимся назад на пару коммитов, мы изменим ссылку указателя HEAD на указанный коммит и все изменения, которые были до этого внесены, окажутся в индексе.
2. При использовании параметра —mixed , мы опять-таки изменим ссылку указателя HEAD, но все предыдущие изменения в индекс не попадут, а будут отслеживаться как не занесенные в индекс. Это дает возможность внести в индекс только те изменения, которые нам необходимы, что довольно удобно!
3. Если использовать команду git reset с параметром —hard , мы снова изменим ссылку указателя HEAD, но все предыдущие изменения не попадут ни в индекс, ни в зону отслеживаемых файлов. Это значит, что мы полностью сотрем все изменения, которые вносили ранее. Это также удобно, если вы знаете, что вам больше не пригодится ваша предыдущая работа над проектом.
Давайте вернемся к нашему репозиторию и рассмотрим следующий пример:
git log —oneline
Итак, в ходе нашей работы, мы сделали четыре коммита. Предположим, что мы хотим откатить проект до второго коммита. Давайте посмотрим, как это будет происходить, используя разные параметры:
git reset —soft 349de9d
Далее, проверим индекс:
И снова git log —oneline :
Как и ожидалось, указатель HEAD переместился на второй коммит, а состояние индекса осталось неизменным.
Теперь повторим наши действия, но уже с параметром —mixed :
git reset —mixed 349de9d
Проверим git status:
А также git log —oneline :
В данном случае, указатель снова переместился на второй коммит, но предыдущие изменения попали в зону отслеживаемых файлов. Это значит, что теперь мы можем решить — оставить эти изменения, добавив их в индекс, либо избавиться от них.
И в заключении повторим ту же последовательность действий с параметром —hard .
git reset —hard 349de9d
Снова проверяем git status :
И git log —oneline :
Здесь указатель HEAD переместился на второй коммит, а все предыдущие изменения были стерты, что видно по пустому индексу и зоне отслеживаемых файлов.
И если посмотреть сейчас содержимое файла, то мы увидим единственную строку “Hello, world!”, которую мы с вами добавляли в файл во втором коммите.
Ветвление в Git
Почти каждая система контроля версий имеет поддержку ветвления. Ветвление означает, что у вас есть возможность работать над разными версиями проекта. То есть, если раньше история вашей разработки являла собой прямую последовательность коммитов, то теперь она может расходиться в определенных точках.
Это очень полезная функция по многим причинам, например для взаимодействия нескольких разработчиков. Представьте, вы с коллегой корпите над одним проектом. Каждый из вас работает над разными фичами, и для того чтобы не мешать друг другу, вы можете работать в разных ветках, а по окончанию работы слить эти ветки в одну.
Давайте попробуем с этим поработать на нашем примере. У нас имеется следующая последовательность коммитов.
Git по умолчанию во время инициализации создает ветку master и уже ведет свою работу в ней. Мы можем в этом убедиться введя команду:
Предположим, что нам по какой-либо причине понадобилось создать новую ветку и вести работу в ней. Для этого сначала необходимо её создать.
Делается это при помощи команды git branch <branch_name> . Давайте создадим ветку “dev”:
Теперь введя команду git branch мы увидим следующее:
Звёздочкой Git указывает на текущую ветку, в которой мы работаем.
Для того чтобы переключиться на другую ветку используют команду git checkout <branch_name> . Давайте переключимся на ветку “dev”.
git checkout dev
Теперь внесем любые изменения в файл hello_world.txt и сделаем коммит, после чего посмотрим, как выглядят наши ветки после редактирования.
Взглянем на git log —oneline :
Как и следовало ожидать, в нашей истории появился еще один — пятый коммит.
Теперь перейдем на ветку master
git checkout master
И просмотрим git log —oneline , и убедимся в том что все осталось без изменений.
Помимо разделения истории в Git мы также можем соединять воедино два потока разработки. Это значит, что нашу проделанную работу в новой ветке мы можем слить обратно в master. Такой процесс слияния можно выполнить при помощи команды git merge <branch_name> . То есть, если мы хотим слить изменения из ветки “dev” в ветку “master”, нам необходимо перейти на ветку “master” и в ней выполнить:
Теперь если мы проверим git log —oneline , то убедимся в том, что новый коммит из ветки “dev” переместился в ветку “master”.
Теперь от ненужной ветки можно избавиться и удалить её с помощью команды git branch -d <branch_name> .
В данных примерах я не учитывал того факта, что при слиянии веток иногда возможно возникновение конфликтов, которые приходится разрешать вручную. Как правило это происходит при слиянии двух веток, в которых одновременно велась какая-то работа. Или же когда в новой ветке вы задели изменения старой. Я не буду рассматривать такие примеры, т.к. разрешение конфликтов — тема не маленькая, и многие вещи в ней можно разобрать самостоятельно в ходе практики.
Примеры ведения истории проекта
Моя статья подходит к концу, но перед завершением хочу отметить, что во многих командах существуют определенные соглашения по поводу ведения истории в Git.
Например вас могут попросить соблюдать несколько правил, при написании сообщения коммита. Или перед работой вас могут ознакомить с определенной стратегией ветвления в проектах компании. Вас также могут ограничить в количестве отправляемых коммитов в удаленный репозиторий.
В качестве примера, я расскажу какие соглашения действуют в компании, в которой я работаю.
1. Сообщение коммита:
Ниже представлен шаблон наших сообщений коммита:

Мы указываем дату совершения коммита и версию приложения для удобства поиска работы в истории.
Модификаторы формата коммита предоставляют информацию о том какой фронт работы был выполнен в этом коммите.
Мы используем следующие модификаторы:
Dev: — указывает на то, что в коммите велась разработка нового функционала.
Refactoring: — данный модификатор сообщает о рефакторинге проведенном в коде.
Fix: — в данном коммите фиксили баги.
Release: — данный коммит отправлен в ветку «release» и хранит состояние релизной версии приложения.
Также в конце сообщения мы оставляем короткое описание — над чем мы работали в этом коммите.
2. Стратегия ветвления:
В действительности можно насчитать достаточно много стратегий ветвления. Все они могут незначительно различаться, но выполнять совершенно разные задачи.
В нашем случае, мы выделяем две основные ветки master и «release». Master используется для подготовки к выкладке новых версий приложения. Код попавший в «master» проходит автоматические тесты, после которых выполняется сборка проекта, которую необходимо вручную протестировать перед дальнейшими действиями. Далее если замечаний к работе нет, мы сливаем ветку «master» в ветку «release». Там снова запускаются автоматические тесты, и собираются сборки к выкладке в маркеты.
Для ведения разработки мы создаем feature векти. Это означает, что каждая ветка отвечает за разработку какой-нибудь функциональности. Например, если мы хотим внедрить в приложение хранение данных в облаке, то программист создаст ветку «feature-cloud» и будет вести работу в ней.
Заключение
Мы рассмотрели самые основные приемы работы с Git. Моей задачей было сформировать в вас некоторое понимание — что есть система контроля версий и познакомить с одной из них. Мы разобрали структуру Git проекта, и теперь у вас есть представление о том, как он работает. Мы познакомились с самыми важными командами в Git, рассмотрели некоторые команды для инспектирования истории проекта и даже овладели несколькими приемами для перемещения HEAD указателя. Мы немного затронули тему ветвления, попробовали создать свою новую ветку и слить её с базовой.
Надеюсь, вам было интересно. Хочу снова заметить, что Git — тема комплексная, и, собирая информацию по крупицам, вы в итоге сможете работать уверенно с этим инструментом. Главное здесь — практика и желание во всем разобраться.
В качестве тренировки и закрепления имеющихся навыков, оставлю ссылку на удобный тренажер для Git.
А также на книги, которыми я пользовался и интернет ресурсы:
1. “Version control with Git” — Jon Loeliger;
2. “Pro Git” — Scott Chacon, Ben Straub.
Также было бы интересно узнать какие практики по Git есть у вас в компаниях и какие интересные ресурсы вы можете подсказать.
Основы Git. Как работает Git?
Git — распределённая система контроля версий, позволяющая сохранять изменения, внесённые в файлы, которые хранятся в репозитории. Сами изменения сохраняются в виде снимков, называемых коммитами. Они могут размещаться на разных серверах, поэтому вы всегда восстановите код в случае сбоя, а также без проблем откатитесь до любого предыдущего состояния. Кроме того, значительно облегчается взаимодействие с другими разработчиками: несколько человек могут работать над одним репозиторием одновременно, сохраняя свои изменения.
Git имеет множество плюсов, поэтому считается незаменимым инструментом для всех, кто работает в сфере разработки ПО. В этой статье мы рассмотрим, когда используется Git, изучим наиболее полезные Git-команды. Если Git вам уже знаком, вы сможете освежить свои знания.
Как работать с Git?
В Git имеется много команд, поэтому разобьём их по теме и причине использования. Но начнём с того, что рассмотрим работу Git на локальной машине, ведь большая часть операций происходит именно там. После этого перейдём к многопользовательскому формату.
Вообще, с Git можно работать и через графический интерфейс (например, GitHub Desktop), и через командную строку. Командную строку изучить необходимо хотя бы потому, что она предоставляет больше возможностей, чем некоторые инструменты с интерфейсом.
Обычно, команды Git имеют следующий вид:
В качестве аргумента может быть путь к файлу. Также у команд бывают опции, обозначаемые —<опция> либо -<однобуквенная опция> . Они обеспечивают более детальную настройку действия команды. В нашем материале команды будут представлены в общем виде, а значит всё, что будет в <> , вы можете менять на собственные значения.
Кстати, если возникают затруднения с использованием той либо иной команды, рекомендуется открыть руководство посредством git help <команда> . Если просто нужно напоминание, применяйте git <команда> -h либо git <команда> —help (в Git -h и —help имеют одинаковое значение).
Установка Git
Если вы пользуетесь Windows, качайте Git отсюда. Что касается macOS, то здесь Git поставляется как часть инструмента командной строки XCode. Наличие Git можно проверить, открыв терминал и набрав git —version . Для Linux используйте команду sudo apt install git-all либо sudo dnf install git-all .
Настраиваем конфигурационный файл
Сразу после установки Git нужно настроить имя пользователя и email, ведь они используются для идентификации. Данные настройки будут сохранены в конфигурационном файле.
Вы можете отредактировать файл .gitconfig напрямую с помощью редактора или, используя команду git config —global —edit . Чтобы отредактировать отдельные поля, подойдёт git config —global <поле> <значение> — здесь нас интересуют поля user.email и user.name.
Кроме того, есть возможность настройки текстового редактора для написания сообщений коммитов — это поле core.editor. По умолчанию применяется системный редактор. Поле commit.template служит для указания шаблона, который будет задействоваться при каждом коммите.
Есть и много других полей, но самое полезное — alias (привязывает команду к псевдониму). К примеру, git config —global alias.st «status -s» позволит использовать git st вместо git status –s.
А git config —list выведет все поля с их значениями из конфигурационного файла.
Создание Git-репозитория
Чтобы инициализировать новый репозиторий .git используют команду git init . Если хотите скопировать уже существующий репозиторий — git clone <адрес репозитория> .
История коммитов в Git

Git хранит имеющиеся данные в виде набора «снимков», называемых коммитами. Коммиты хранят состояние файловой системы в конкретный момент времени, а также имеют указатель на предыдущие коммиты. Каждый коммит содержит уникальный контрольный идентификатор, который используется Git, чтобы ссылаться на этот коммит. Для отслеживания истории Git хранит указатель HEAD, указывающий на 1-й коммит.
Ссылаться можно как через контрольную сумму коммита, так и через его позицию относительно HEAD. К примеру, HEAD
4 будет ссылаться на коммит, находящийся 4-мя коммитами ранее HEAD.
Система файлов в Git

Git может отслеживать файлы в 3-х основных разделах: — рабочая директория (речь идёт о файловой системе вашего ПК); — область подготовленных файлов (это staging area, где хранится содержание следующего коммита); — HEAD (последний в репозитории коммит).
Как просматривать изменения в файловых системах?
Для этого используют команду git status . Она отображает все файлы, которые различаются между 3-мя отделами. Файлы имеют четыре состояния: 1) untracked (неотслеживаемый). Находится в рабочей директории, но его нет ни в HEAD, ни в области подготовленных файлов. Можно сказать, что Git о нём не знает; 2) modified (изменён). В рабочей директории находится его более новая версия по сравнению с той, которая хранится в HEAD либо в области подготовленных файлов (при этом изменения не находятся в следующем коммите); 3) staged (подготовлен). В области подготовленных файлов и в рабочей директории есть более новая версия, если сравнивать с хранящейся в HEAD, но файл уже готов к коммиту; 4) без изменений. Во всех разделах содержится одна версия файла, то есть в последнем коммите находится актуальная версия.
Чтобы посмотреть не изменённые файлы, а непосредственно изменения, можно использовать: — git diff — для сравнения рабочей директории с областью подготовленных файлов; — git diff —staged — для сравнения области подготовленных файлов с HEAD.
В случае применения аргумента <файл/папка> diff покажет изменения лишь для указанных вами папок или файлов, к примеру:
Игнорирование файлов
Иногда нам не надо, чтобы Git отслеживал все файлы в репозитории, ведь в их число могут входить: — файлы с конфиденциальной информацией; — огромные бинарные файлы; — специфичные файлы; — файлы сборок, генерируемые после каждой компиляции.
Для игнорирования предусмотрен файл .gitignore, где отмечаются файлы для игнорирования.
Коммиты
Основой истории версий являются коммиты. Для работы с ними используют git commit — эта команда откроет текстовый редактор для ввода сообщения коммита. Кроме того, она принимает следующие аргументы: • -m — позволяет написать сообщение, не открывая редактор, то есть вместе с командой; • -a — служит для переноса всех отслеживаемых файлов в область подготовленных файлов и включения их в коммит (даёт возможность перед коммитом пропустить git add); • —amend — заменяет последний коммит новым изменённым коммитом. Это бывает полезно, когда вы неправильно наберёте сообщение последнего коммита либо забудете включить в него нужные файлы.
Ряд советов по коммитам: — коммитьте часто; — одно изменение — один коммит, но не коммитьте слишком незначительные изменения (в большом репозитории они могут засорить историю); — комментируя сообщение о коммите, логически дополняйте фразу this commit will ___ и не используйте более 50 символов.
Удалённые серверы
Мы можем хранить, отслеживать и обновлять историю коммитов не только на локальной машине, но и на удалённых репозиториях. По сути, можно говорить об облачных бэкапах нашей истории коммитов.
Для вывода списка удалённых репозиториев нужна команда git remote –v . С её помощью мы не только загружаем копию репозитория, но и отслеживаем удалённый сервер, находящийся по указанному адресу (ему присваивается имя origin).
Другие часто употребляемые команды: • git remote add <имя> <url> — добавляется удалённый репозиторий с заданным именем; • git remote remove <имя> — удаляется удалённый репозиторий с заданным именем; • git remote rename <старое имя> <новое имя> — переименовывается удалённый репозиторий; • git remote set-url <имя> <url> — репозиторию с именем присваивается новый адрес; • git remote show <имя> — показывается информация о репозитории.
Следующий список нужен для работы с удалёнными ветками: • git fetch <имя> <ветка> — для получения данных из ветки заданного репозитория; • git pull <имя> <ветка> — сливает данные из ветки; • git push <имя> <ветка> — для отправления изменения в ветку заданного репозитория. Когда локальная ветка отслеживает удалённую, достаточно использовать git push или git pull .

В результате несколько человек могут запрашивать с сервера изменения, выполнять изменения в локальных копиях, а потом отправлять их на удалённый сервер. Всё это позволяет легко взаимодействовать между собой в пределах одного репозитория.
Ветвление в Git
Ключевая особенность Git — ветвление, позволяющее работать над разными версиями проекта. Таким образом, вместо одного перечня с упорядоченными коммитами история может расходиться в некоторых точках, поэтому становится похожей на дерево. И каждая ветвь содержит в Git легковесный указатель HEAD, указывающий на последний коммит в данной ветке. В результате можно легко создать много веток. Делая это, называйте ветки согласно разрабатываемой функциональности. Ветку по умолчанию называют master.
Что ж, у нас есть HEAD для каждой ветки и общий указатель HEAD. Переключение между ветками предполагает лишь перемещение HEAD в HEAD соответствующей ветки.

Стандартные команды при ветвлении в Git: • git branch <имя ветки> — для создания новой ветки с HEAD, указывающим на HEAD. Если аргумент <имя ветки> передан не будет, команда выведет список всех имеющихся локальных веток; • git branch -d <имя ветки> — для удаления ветки; • git checkout <имя ветки> — для переключения на эту ветку. Если хотим создать новую ветку перед переключением, можем передать опцию –b.
И локальный, и удалённый репозиторий могут иметь много веток, поэтому при отслеживании на деле отслеживается удалённая ветка, то есть git clone привязывает ветвь master к ветви origin/master удалённого репозитория.
Парочка команд для привязывания к удалённой ветке: • git branch -u <имя удалённого репозитория>/<удалённая ветка> —текущая ветка привязывается к указанной удалённой ветке; • git checkout —track <имя удалённого репозитория>/<удалённая ветка> — аналогично; • git checkout -b <ветка> <имя удалённого репозитория>/<удалённая ветка> — создаётся новая локальная ветвь и начинает отслеживать удалённую; • git checkout <удалённая ветка> — создаётся локальная ветвь с таким же именем, как и у удалённой, плюс начинает её отслеживать; • git branch —vv — служит, чтобы показать локальные и отслеживаемые удалённые ветки.
Совмещение веток
Обсудив возможности по переключению, можно поговорить, как ветки совмещать после разработки. Ветку, в которую мы желаем слить изменения, назовём основной, а ветвь, из которой будем сливать, — тематической. Существуют 2 способа внести изменения — перемещение и слияние.
Слияние
Включает в себя создание нового коммита, основанного на общем коммите-предке 2-х ветвей, указывает на оба HEAD. Для осуществления слияния нужно перейти на основную ветки и использовать команду git merge <тематическая ветка> .

Когда обе ветки меняют одну и ту же часть файла, возникает конфликт слияния. В этой ситуации Git не понимает, какую версию файла нужно сохранить. Разрешать конфликт следует вручную. Для просмотра конфликтующих файлов, используйте git status .
Маркеры разрешения конфликта:
В этом блоке надо заменить всё на версию, которую хотите оставить, после чего подготовить файл. Разрешив все конфликты, можно завершать слияние, используя git commit .
Перемещение
Осуществляется вместо совмещения 2-ух веток коммитом слияния. Перемещение заново воспроизводит коммиты тематической ветви в виде набора новых коммитов базовой ветви, что обеспечивает более чистую историю коммитов.

Чтобы выполнить перемещение, используют команду git rebase <основная ветка> <тематическая ветка> . Она воспроизводит изменения тематической ветви на основной. При этом HEAD тематической ветви указывает на последний воспроизведённый коммит.
Совет: перемещайте изменения лишь на вашей приватной локальной ветке. Не стоит перемещать коммиты, от которых ещё кто-то зависит.
Если хотите откатить коммит: — git revert <коммит> — создаёт новый коммит, который отменяет изменения, но сохраняет историю; — git reset <коммит> — перемещает указатель HEAD, и создаёт более чистую историю, как будто коммита никогда не было. Но это также значит, что вы не сможете вернуться обратно к изменениям, если решите, что отмена была лишней. В общем, чище — не значит лучше!