git-commit(1) Manual Page
Create a new commit containing the current contents of the index and the given log message describing the changes. The new commit is a direct child of HEAD, usually the tip of the current branch, and the branch is updated to point to it (unless no branch is associated with the working tree, in which case HEAD is «detached» as described in git-checkout(1)).
The content to be committed can be specified in several ways:
by using git-add(1) to incrementally «add» changes to the index before using the commit command (Note: even modified files must be «added»);
by using git-rm(1) to remove files from the working tree and the index, again before using the commit command;
by listing files as arguments to the commit command (without —interactive or —patch switch), in which case the commit will ignore changes staged in the index, and instead record the current content of the listed files (which must already be known to Git);
by using the -a switch with the commit command to automatically «add» changes from all known files (i.e. all files that are already listed in the index) and to automatically «rm» files in the index that have been removed from the working tree, and then perform the actual commit;
by using the —interactive or —patch switches with the commit command to decide one by one which files or hunks should be part of the commit in addition to contents in the index, before finalizing the operation. See the “Interactive Mode” section of git-add(1) to learn how to operate these modes.
The —dry-run option can be used to obtain a summary of what is included by any of the above for the next commit by giving the same set of parameters (options and paths).
If you make a commit and then find a mistake immediately after that, you can recover from it with git reset.
OPTIONS
Tell the command to automatically stage files that have been modified and deleted, but new files you have not told Git about are not affected.
Use the interactive patch selection interface to choose which changes to commit. See git-add(1) for details.
-C <commit> —reuse-message=<commit>
Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit.
-c <commit> —reedit-message=<commit>
Like -C, but with -c the editor is invoked, so that the user can further edit the commit message.
Create a new commit which «fixes up» <commit> when applied with git rebase —autosquash . Plain —fixup=<commit> creates a «fixup!» commit which changes the content of <commit> but leaves its log message untouched. —fixup=amend:<commit> is similar but creates an «amend!» commit which also replaces the log message of <commit> with the log message of the «amend!» commit. —fixup=reword:<commit> creates an «amend!» commit which replaces the log message of <commit> with its own log message but makes no changes to the content of <commit> .
The commit created by plain —fixup=<commit> has a subject composed of «fixup!» followed by the subject line from <commit>, and is recognized specially by git rebase —autosquash . The -m option may be used to supplement the log message of the created commit, but the additional commentary will be thrown away once the «fixup!» commit is squashed into <commit> by git rebase —autosquash .
The commit created by —fixup=amend:<commit> is similar but its subject is instead prefixed with «amend!». The log message of <commit> is copied into the log message of the «amend!» commit and opened in an editor so it can be refined. When git rebase —autosquash squashes the «amend!» commit into <commit> , the log message of <commit> is replaced by the refined log message from the «amend!» commit. It is an error for the «amend!» commit’s log message to be empty unless —allow-empty-message is specified.
—fixup=reword:<commit> is shorthand for —fixup=amend:<commit> —only . It creates an «amend!» commit with only a log message (ignoring any changes staged in the index). When squashed by git rebase —autosquash , it replaces the log message of <commit> without making any other changes.
Neither «fixup!» nor «amend!» commits change authorship of <commit> when applied by git rebase —autosquash . See git-rebase(1) for details.
Construct a commit message for use with rebase —autosquash . The commit message subject line is taken from the specified commit with a prefix of «squash! «. Can be used with additional commit message options ( -m / -c / -C / -F ). See git-rebase(1) for details.
When used with -C/-c/—amend options, or when committing after a conflicting cherry-pick, declare that the authorship of the resulting commit now belongs to the committer. This also renews the author timestamp.
When doing a dry-run, give the output in the short-format. See git-status(1) for details. Implies —dry-run .
Show the branch and tracking info even in short-format.
When doing a dry-run, give the output in a porcelain-ready format. See git-status(1) for details. Implies —dry-run .
When doing a dry-run, give the output in the long-format. Implies —dry-run .
When showing short or porcelain status output, print the filename verbatim and terminate the entries with NUL, instead of LF. If no format is given, implies the —porcelain output format. Without the -z option, filenames with «unusual» characters are quoted as explained for the configuration variable core.quotePath (see git-config(1)).
Take the commit message from the given file. Use — to read the message from the standard input.
Override the commit author. Specify an explicit author using the standard A U Thor <author@example.com> format. Otherwise <author> is assumed to be a pattern and is used to search for an existing commit by that author (i.e. rev-list —all -i —author=<author>); the commit author is then copied from the first such commit found.
Override the author date used in the commit.
Use the given <msg> as the commit message. If multiple -m options are given, their values are concatenated as separate paragraphs.
The -m option is mutually exclusive with -c , -C , and -F .
When editing the commit message, start the editor with the contents in the given file. The commit.template configuration variable is often used to give this option implicitly to the command. This mechanism can be used by projects that want to guide participants with some hints on what to write in the message in what order. If the user exits the editor without editing the message, the commit is aborted. This has no effect when a message is given by other means, e.g. with the -m or -F options.
-s —signoff —no-signoff
Add a Signed-off-by trailer by the committer at the end of the commit log message. The meaning of a signoff depends on the project to which you’re committing. For example, it may certify that the committer has the rights to submit the work under the project’s license or agrees to some contributor representation, such as a Developer Certificate of Origin. (See http://developercertificate.org for the one used by the Linux kernel and Git projects.) Consult the documentation or leadership of the project to which you’re contributing to understand how the signoffs are used in that project.
The —no-signoff option can be used to countermand an earlier —signoff option on the command line.
Specify a (<token>, <value>) pair that should be applied as a trailer. (e.g. git commit —trailer «Signed-off-by:C O Mitter \ <committer@example.com>» —trailer «Helped-by:C O Mitter \ <committer@example.com>» will add the «Signed-off-by» trailer and the «Helped-by» trailer to the commit message.) The trailer.* configuration variables (git-interpret-trailers(1)) can be used to define if a duplicated trailer is omitted, where in the run of trailers each trailer would appear, and other details.
By default, the pre-commit and commit-msg hooks are run. When any of —no-verify or -n is given, these are bypassed. See also githooks(5).
Usually recording a commit that has the exact same tree as its sole parent commit is a mistake, and the command prevents you from making such a commit. This option bypasses the safety, and is primarily for use by foreign SCM interface scripts.
Like —allow-empty this command is primarily for use by foreign SCM interface scripts. It allows you to create a commit with an empty commit message without using plumbing commands like git-commit-tree(1).
This option determines how the supplied commit message should be cleaned up before committing. The <mode> can be strip , whitespace , verbatim , scissors or default .
Strip leading and trailing empty lines, trailing whitespace, commentary and collapse consecutive empty lines.
Same as strip except #commentary is not removed.
Do not change the message at all.
Same as whitespace except that everything from (and including) the line found below is truncated, if the message is to be edited. » # » can be customized with core.commentChar.
Same as strip if the message is to be edited. Otherwise whitespace .
The default can be changed by the commit.cleanup configuration variable (see git-config(1)).
The message taken from file with -F , command line with -m , and from commit object with -C are usually used as the commit log message unmodified. This option lets you further edit the message taken from these sources.
Use the selected commit message without launching an editor. For example, git commit —amend —no-edit amends a commit without changing its commit message.
Replace the tip of the current branch by creating a new commit. The recorded tree is prepared as usual (including the effect of the -i and -o options and explicit pathspec), and the message from the original commit is used as the starting point, instead of an empty message, when no other message is specified from the command line via options such as -m , -F , -c , etc. The new commit has the same parents and author as the current one (the —reset-author option can countermand this).
It is a rough equivalent for:
but can be used to amend a merge commit.
You should understand the implications of rewriting history if you amend a commit that has already been published. (See the «RECOVERING FROM UPSTREAM REBASE» section in git-rebase(1).)
Bypass the post-rewrite hook.
Before making a commit out of staged contents so far, stage the contents of paths given on the command line as well. This is usually not what you want unless you are concluding a conflicted merge.
Make a commit by taking the updated working tree contents of the paths specified on the command line, disregarding any contents that have been staged for other paths. This is the default mode of operation of git commit if any paths are given on the command line, in which case this option can be omitted. If this option is specified together with —amend , then no paths need to be specified, which can be used to amend the last commit without committing changes that have already been staged. If used together with —allow-empty paths are also not required, and an empty commit will be created.
Pathspec is passed in <file> instead of commandline args. If <file> is exactly — then standard input is used. Pathspec elements are separated by LF or CR/LF. Pathspec elements can be quoted as explained for the configuration variable core.quotePath (see git-config(1)). See also —pathspec-file-nul and global —literal-pathspecs .
Only meaningful with —pathspec-from-file . Pathspec elements are separated with NUL character and all other characters are taken literally (including newlines and quotes).
Show untracked files.
The mode parameter is optional (defaults to all), and is used to specify the handling of untracked files; when -u is not used, the default is normal, i.e. show untracked files and directories.
The possible options are:
no — Show no untracked files
normal — Shows untracked files and directories
all — Also shows individual files in untracked directories.
The default can be changed using the status.showUntrackedFiles configuration variable documented in git-config(1).
Show unified diff between the HEAD commit and what would be committed at the bottom of the commit message template to help the user describe the commit by reminding what changes the commit has. Note that this diff output doesn’t have its lines prefixed with #. This diff will not be a part of the commit message. See the commit.verbose configuration variable in git-config(1).
If specified twice, show in addition the unified diff between what would be committed and the worktree files, i.e. the unstaged changes to tracked files.
Suppress commit summary message.
Do not create a commit, but show a list of paths that are to be committed, paths with local changes that will be left uncommitted and paths that are untracked.
Include the output of git-status(1) in the commit message template when using an editor to prepare the commit message. Defaults to on, but can be used to override configuration variable commit.status.
Do not include the output of git-status(1) in the commit message template when using an editor to prepare the default commit message.
GPG-sign commits. The keyid argument is optional and defaults to the committer identity; if specified, it must be stuck to the option without a space. —no-gpg-sign is useful to countermand both commit.gpgSign configuration variable, and earlier —gpg-sign .
Do not interpret any more arguments as options.
When pathspec is given on the command line, commit the contents of the files that match the pathspec without recording the changes already added to the index. The contents of these files are also staged for the next commit on top of what have been staged before.
For more details, see the pathspec entry in gitglossary(7).
EXAMPLES
When recording your own work, the contents of modified files in your working tree are temporarily stored to a staging area called the «index» with git add. A file can be reverted back, only in the index but not in the working tree, to that of the last commit with git restore —staged <file> , which effectively reverts git add and prevents the changes to this file from participating in the next commit. After building the state to be committed incrementally with these commands, git commit (without any pathname parameter) is used to record what has been staged so far. This is the most basic form of the command. An example:
Instead of staging files after each individual change, you can tell git commit to notice the changes to the files whose contents are tracked in your working tree and do corresponding git add and git rm for you. That is, this example does the same as the earlier example if there is no other change in your working tree:
The command git commit -a first looks at your working tree, notices that you have modified hello.c and removed goodbye.c, and performs necessary git add and git rm for you.
After staging changes to many files, you can alter the order the changes are recorded in, by giving pathnames to git commit . When pathnames are given, the command makes a commit that only records the changes made to the named paths:
This makes a commit that records the modification to Makefile . The changes staged for hello.c and hello.h are not included in the resulting commit. However, their changes are not lost — they are still staged and merely held back. After the above sequence, if you do:
this second commit would record the changes to hello.c and hello.h as expected.
After a merge (initiated by git merge or git pull) stops because of conflicts, cleanly merged paths are already staged to be committed for you, and paths that conflicted are left in unmerged state. You would have to first check which paths are conflicting with git status and after fixing them manually in your working tree, you would stage the result as usual with git add:
After resolving conflicts and staging the result, git ls-files -u would stop mentioning the conflicted path. When you are done, run git commit to finally record the merge:
As with the case to record your own changes, you can use -a option to save typing. One difference is that during a merge resolution, you cannot use git commit with pathnames to alter the order the changes are committed, because the merge should be recorded as a single commit. In fact, the command refuses to run when given pathnames (but see -i option).
COMMIT INFORMATION
Author and committer information is taken from the following environment variables, if set:
(nb «<«, «>» and «\n»s are stripped)
The author and committer names are by convention some form of a personal name (that is, the name by which other humans refer to you), although Git does not enforce or require any particular form. Arbitrary Unicode may be used, subject to the constraints listed above. This name has no effect on authentication; for that, see the credential.username variable in git-config(1).
In case (some of) these environment variables are not set, the information is taken from the configuration items user.name and user.email , or, if not present, the environment variable EMAIL, or, if that is not set, system user name and the hostname used for outgoing mail (taken from /etc/mailname and falling back to the fully qualified hostname when that file does not exist).
The author.name and committer.name and their corresponding email options override user.name and user.email if set and are overridden themselves by the environment variables.
The typical usage is to set just the user.name and user.email variables; the other options are provided for more complex use cases.
DATE FORMATS
The GIT_AUTHOR_DATE and GIT_COMMITTER_DATE environment variables support the following date formats:
It is <unix-timestamp> <time-zone-offset> , where <unix-timestamp> is the number of seconds since the UNIX epoch. <time-zone-offset> is a positive or negative offset from UTC. For example CET (which is 1 hour ahead of UTC) is +0100 .
The standard email format as described by RFC 2822, for example Thu, 07 Apr 2005 22:13:13 +0200 .
Time and date specified by the ISO 8601 standard, for example 2005-04-07T22:13:13 . The parser accepts a space instead of the T character as well. Fractional parts of a second will be ignored, for example 2005-04-07T22:13:13.019 will be treated as 2005-04-07T22:13:13 .
In addition to recognizing all date formats above, the —date option will also try to make sense of other, more human-centric date formats, such as relative dates like «yesterday» or «last Friday at noon».
DISCUSSION
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 is to some extent character encoding agnostic.
The contents of the blob objects are uninterpreted sequences of bytes. There is no encoding translation at the core level.
Path names are encoded in UTF-8 normalization form C. This applies to tree objects, the index file, ref names, as well as path names in command line arguments, environment variables and config files ( .git/config (see git-config(1)), gitignore(5), gitattributes(5) and gitmodules(5)).
Note that Git at the core level treats path names simply as sequences of non-NUL bytes, there are no path name encoding conversions (except on Mac and Windows). Therefore, using non-ASCII path names will mostly work even on platforms and file systems that use legacy extended ASCII encodings. However, repositories created on such systems will not work properly on UTF-8-based systems (e.g. Linux, Mac, Windows) and vice versa. Additionally, many Git-based tools simply assume path names to be UTF-8 and will fail to display other encodings correctly.
Commit log messages are typically encoded in UTF-8, but other extended ASCII encodings are also supported. This includes ISO-8859-x, CP125x and many others, but not UTF-16/32, EBCDIC and CJK multi-byte encodings (GBK, Shift-JIS, Big5, EUC-x, CP9xx etc.).
Although we encourage that the commit log messages are encoded in UTF-8, both the core and Git Porcelain are designed not to force UTF-8 on projects. If all participants of a particular project find it more convenient to use legacy encodings, Git does not forbid it. However, there are a few things to keep in mind.
git commit and git commit-tree issues a warning if the commit log message given to it does not look like a valid UTF-8 string, unless you explicitly say your project uses a legacy encoding. The way to say this is to have i18n.commitEncoding in .git/config file, like this:
Commit objects created with the above setting record the value of i18n.commitEncoding in its encoding header. This is to help other people who look at them later. Lack of this header implies that the commit log message is encoded in UTF-8.
git log, git show, git blame and friends look at the encoding header of a commit object, and try to re-code the log message into UTF-8 unless otherwise specified. You can specify the desired output encoding with i18n.logOutputEncoding in .git/config file, like this:
If you do not have this configuration variable, the value of i18n.commitEncoding is used instead.
Note that we deliberately chose not to re-code the commit log message when a commit is made to force UTF-8 at the commit object level, because re-coding to UTF-8 is not necessarily a reversible operation.
ENVIRONMENT AND CONFIGURATION VARIABLES
The editor used to edit the commit log message will be chosen from the GIT_EDITOR environment variable, the core.editor configuration variable, the VISUAL environment variable, or the EDITOR environment variable (in that order). See git-var(1) for details.
Everything above this line in this section isn’t included from the git-config(1) documentation. The content that follows is the same as what’s found there:
This setting overrides the default of the —cleanup option in git commit . See git-commit(1) for details. Changing the default can be useful when you always want to keep lines that begin with comment character # in your log message, in which case you would do git config commit.cleanup whitespace (note that you will have to remove the help lines that begin with # in the commit log template yourself, if you do this).
A boolean to specify whether all commits should be GPG signed. Use of this option when doing operations such as rebase can result in a large number of commits being signed. It may be convenient to use an agent to avoid typing your GPG passphrase several times.
A boolean to enable/disable inclusion of status information in the commit message template when using an editor to prepare the commit message. Defaults to true.
Specify the pathname of a file to use as the template for new commit messages.
A boolean or int to specify the level of verbose with git commit . See git-commit(1).
HOOKS
This command can run commit-msg , prepare-commit-msg , pre-commit , post-commit and post-rewrite hooks. See githooks(5) for more information.
2.2 Основы Git — Запись изменений в репозиторий
Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта. Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.
Запомните, каждый файл в вашем рабочем каталоге может находиться в одном из двух состояний: под версионным контролем (отслеживаемые) и нет (неотслеживаемые). Отслеживаемые файлы — это те файлы, которые были в последнем снимке состояния проекта; они могут быть неизменёнными, изменёнными или подготовленными к коммиту. Если кратко, то отслеживаемые файлы — это те файлы, о которых знает Git.
Неотслеживаемые файлы — это всё остальное, любые файлы в вашем рабочем каталоге, которые не входили в ваш последний снимок состояния и не подготовлены к коммиту. Когда вы впервые клонируете репозиторий, все файлы будут отслеживаемыми и неизменёнными, потому что Git только что их извлек и вы ничего пока не редактировали.
Как только вы отредактируете файлы, Git будет рассматривать их как изменённые, так как вы изменили их с момента последнего коммита. Вы индексируете эти изменения, затем фиксируете все проиндексированные изменения, а затем цикл повторяется.
Определение состояния файлов
Основной инструмент, используемый для определения, какие файлы в каком состоянии находятся — это команда git status . Если вы выполните эту команду сразу после клонирования, вы увидите что-то вроде этого:
Это означает, что у вас чистый рабочий каталог, другими словами — в нём нет отслеживаемых изменённых файлов. Git также не обнаружил неотслеживаемых файлов, в противном случае они бы были перечислены здесь. Наконец, команда сообщает вам на какой ветке вы находитесь и сообщает вам, что она не расходится с веткой на сервере. Пока что это всегда ветка master , ветка по умолчанию; в этой главе это не важно. В главе Ветвление в Git будут рассмотрены ветки и ссылки более детально.
В 2020 году GitHub изменил имя ветки по умолчанию с master на main , другие же git-хостинг платформы последовали этому примеру. Поэтому, вы можете обнаружить, что ветка по умолчанию для новых репозиториев — main , а не master . Более того, имя ветки по умолчанию можно изменить (как вы видели в Настройка ветки по умолчанию), поэтому вам может встретиться и другое имя. При этом Git продолжает использовать имя master , поэтому далее в книге мы используем именно его.
Предположим, вы добавили в свой проект новый файл, простой файл 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 перед коммитом.
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
git commit creates a commit, which is like a snapshot of your repository. These commits are snapshots of your entire repository at specific times. You should make new commits often, based around logical units of change. Over time, commits should tell a story of the history of your repository and how it came to be the way that it currently is. Commits include lots of metadata in addition to the contents and message, like the author, timestamp, and more.
How Git Commit Works
Commits are the building blocks of «save points» within Git’s version control.
Commits shape history
By using commits, you’re able to craft history intentionally and safely. You can make commits to different branches, and specify exactly what changes you want to include. Commits are created on the branch that you’re currently checked out to (wherever HEAD is pointing) so it’s always a good idea to run git status before making a commit, to check that you’re checked-out to the branch that you intend to be. Before you commit, you will need to stage any new changes that you’d like to include in the commit using git add [file] .
Commits are lightweight SHA hashes, objects within Git. As long as you’re working with text files, you won’t need to worry about how many files you have, how big they are, or how many commits you make. Git can handle it!
Committing in two phases
Commits have two phases to help you craft commits properly. Commits should be logical, atomic units of change that represent a specific idea. But, not all humans work that way. You may get carried away and end up solving two or three problems before you remember to commit! That’s OK — Git can handle that. Once you’re ready to craft your commits, you’ll use git add <FILENAME> to specify the files that you’d like to «stage» for commit. Without adding any files, the command git commit won’t work. Git only looks to the staging area to find out what to commit. Staging, or adding, files, is possible through the command line, and also possible with most Git interfaces like GitHub Desktop by selecting the lines or files that you’d like to stage.
You can also use a handy command, git add -p , to walk through the changes and separate them out, even if they’re in the same file.
How to Use Git Commit
Common usages and options for Git Commit
- git commit : This starts the commit process, but since it doesn’t include a -m flag for the message, your default text editor will be opened for you to create the commit message. If you haven’t configured anything, there’s a good chance this will be VI or Vim. (To get out, press esc, then :w , and then Enter. :wink:)
- git commit -m «descriptive commit message» : This starts the commit process, and allows you to include the commit message at the same time.
- git commit -am «descriptive commit message» : In addition to including the commit message, this option allows you to skip the staging phase. The addition of -a will automatically stage any files that are already being tracked by Git (changes to files that you’ve committed before).
- git commit —amend : Replaces the most recent commit with a new commit. (More on this later!)
To see all of the possible options you have with git commit , check out Git’s documentation.
How to Undo Commits in Git
Sometimes, you may need to change history. You may need to undo a commit. If you find yourself in this situation, there are a few very important things to remember:
- If you are «undoing» a commit that exists on the remote, you could create big problems for your collaborators
- Undoing a commit on work that you only have locally is much safer
What can go wrong while changing history?
Changing history for collaborators can be problematic in a few ways. Imagine — You and another collaborator have the same repository, with the same history. But, they make a change that deletes the most recent commit. They continue new commits from the commit directly before that. Meanwhile, you keep working with the commit that the collaborator tried to delete. When they push, they’ll have to ‘force push’, which should show to them that they’re changing history. What do you think will happen when you try to push?
In dramatic cases, Git may decide that the histories are too different and the projects are no longer related. This is uncommon, but a big problem.
The most common result is that your git push would return the «deleted» commit to shared history. (First, you would git pull if you were working on the same branch, and then merge, but the results would be the same.) This means that whatever was so important to delete is now back in the repository. A password, token, or large binary file may return without ever alerting you.
git revert is the safest way to change history with Git. Instead of deleting existing commits, git revert looks at the changes introduced in a specific commit, then applies the inverse of those changes in a new commit. It functions as an «undo commit» command, without sacrificing the integrity of your repository’s history. git revert is always the recommended way to change history when it’s possible.
Sometimes, a commit includes sensitive information and needs to actually be deleted. git reset is a very powerful command that may cause you to lose work. By resetting, you move the HEAD pointer and the branch pointer to another point in time — maybe making it seem like the commits in between never happened! Before using git reset :
- Make sure to talk with your team about any shared commits
- Research the three types of reset to see which is right for you (—soft, —mixed, —hard)
- Commit any work that you don’t want to be lost intentionally — work that is committed can be gotten back, but uncommitted work cannot
If you’re changing history and undoing commits, you should know about git reflog . If you get into trouble, the reflog could get you out of trouble. The reflog is a log of every commit that HEAD has pointed to. So, for example, if you use git reset and unintentionally lose commits, you can find and access them with git reflog .
Updating Commits With Git Commit Amend
While git commit —amend does change history, it only changes the most recent commit on your current branch. This can be an extremely useful command for commits that:
- Haven’t been pushed to the remote yet
- Have a spelling error in the commit message
- Don’t contain the changes that you’d like to contain
Examples of Git Commit
Once you’ve staged the files that you want to include in your commit, you’re ready. Whether you commit in a tool like GitHub Desktop, or through your command line, the commit message is important. Commit messages should be short and descriptive of your change. If you are looking through your repository’s history, you’ll be guided by the commit messages, so they should tell a story. Commits in the command line can include the message with the following format:
- git commit -m «git commit message example»
Commit messages should be present tense and directive, like the following examples:
- git commit -m «create file structure for Git guides»
- git commit -m «translate Git cheat sheet into German»
- git commit -m «update broken URL to Git resources»
If you’d like to include more context in your commit messages, you can also include an extended commit message.
- git add [file] : Snapshots the file in preparation for versioning, adding it to the staging area.
- git status : Always a good idea, this command shows you what branch you’re on, what files are in the working or staging directory, and any other important information.
- git push : Uploads all local branch commits to the remote.
- git log : Browse and inspect the evolution of project files.
Get started with git and GitHub
Review code, manage projects, and build software alongside 40 million developers.
Subscribe to The GitHub Insider
Discover tips, technical guides, and best practices in our monthly newsletter for developers.
Гайд по Git : Часть 1 : Как сделать коммит в Git
Отвечаю на вопросы: как сделать коммит, создать новую ветку, вмержить одну ветку в другую.
Git — это консольная утилита, для отслеживания и ведения истории изменения файлов в проекте. Чаще всего его используют для кода, но можно и для других файлов.
Я пользовался git еще в универе, было удобно писать диплом и не плодить 100 копий файлов с названиями: “диплом (новый)”, “диплом (новее нового)”, “диплом (новые правки)”.
Мои статьи основаны на отличном интерактивном курсе LearnGitBranching. Но у него есть существенный недостаток, они не используют настоящий Git в процессе обучения. Из-за этого ряд важных нюансов упускается.
В моей статье будет обучение на настоящем Git. Просто повторяйте команды за мной, чтобы попрактиковаться.
Что такое VCS?
Системы контроля версий (СКВ, VCS, Version Control Systems) позволяют откатить проект до старой версии, сравнивать, анализировать или сливать свои изменения в репозиторий.
Репозиторием называют хранилище вашего кода. Git работает локально и все ваши репозитории хранятся в определенных папках на жестком диске. Также есть хостинги репозиториев, такие как GitHub и GitLab, которые позволяют хранить проект в интернете.
VCS позволяют нескольким разработчикам работать над одним проектом и сохранять внесённые изменения независимо друг от друга. При этом каждый участник команды видит над чем работают коллеги.
Теперь, когда мы в общих чертах понимаем зачем нам Git, создадим свой первый репозиторий. Но сначала нужно установить git.
Установка git
Основой интерфейс для работы с Git-ом является консоль. Это не удобно использовать в работе, но некоторые проблемы решаются только через консоль.
Для установки на Windows нажимаем на кнопку ниже, скачиваем и устанавливаем.
Для Mac OS открываем терминал и пишем, если установлен Brew:
Если Brew не установлен, то вводим эту команду.
После этого появится окно, где предложит установить Command Line Tools (CLT). Соглашаемся и ждем установки. Вместе с CLT установиться и git
Для Linux открываем терминал и вводим следующую команду.
Настройка
Вы установили себе Git. Давайте теперь его настроим, чтобы когда вы создавали снимок проекта, указывался автор.
Открываем терминал (Linux и MacOS) или консоль (Windows) и вводим следующие команды.
Инициализация репозитория
Теперь вы готовы к работе с Git локально на компьютере. Для начала создадим папку, которая будет нашим обучающим проектом.
Чтобы создать локальный репозиторий, необходимо выполнить команду:
Посмотрим, какие файлы находятся сейчас в папке git-project :
Появилась новая папка .git , которая содержит множество файлов и других папок. Предназначение этих файлов и папок мы разберем в другой статье.
Коммиты
Коммит это одно из базовых понятий в Git. Если объяснять простым языком, то коммит это огромная копия вашего проекта в момент времени, когда этот коммит был сделан.
Но на самом деле git пытается быть лёгким и быстрым, так что он не просто слепо копирует весь проект каждый раз, а ужимает коммит в набор изменений или «дельту» между текущей версией и предыдущей. Это позволяет занимать меньше места.
Также Git хранит всю историю о том, когда какой коммит был сделан и кем. Это очень важно, можно посмотреть из-за кого упало приложение и навалять ему
Файлы в репозитории могут находиться в 3 различных “областях”.
- HEAD
- Индекс
- Рабочий каталог
Наш проект сейчас пуст. Давайте создадим наш первый файл:
На данном этапе только область “Рабочий каталог” содержит данные.
Рабочий Каталог это ваша папка с файлами, в данном случае это git-project . Две другие области сохраняют свое содержимое внутри папки .git в понятном и удобном для git формате, но не понятном для человека.
Считайте Рабочий Каталог песочницей, где вы можете опробовать изменения перед тем, как сделаете коммит. На данном этапе вы можете в любой момент стереть все изменения и вернуться к последнему коммиту. Они не будут сохранены в истории git.
Чтобы сохранить изменения – сделать коммит. Необходимо сначала добавить содержимое Рабочего Каталога в так называемый Индекс – это черновик коммита. Только файлы из Индекс попадут в коммит.
Без добавления файла в Индекс у нас не получится создать коммит, проверьте это сами с помощью комманды:
Для добавления файлов в Индекс используется следующая команда:
Когда у вас много файлов, вы можете добавить их все разом git add —all .
Теперь сделаем наш первый коммит, выполнив команду git commit . Тем самым мы сохраним содержимое области Индекс как неизменяемый снимок в области HEAD . Обязательно нужно описать суть внесенных вами изменений, для этого используется флаг -m :
Все, коммит готов. И файл попал в область HEAD . HEAD будет родителем следующего созданного коммита. Как правило, самое простое считать HEAD снимком вашего последнего коммита. Возможно пока не совсем понятно что такое HEAD , но о нем мы еще поговорим.
Если сейчас выполнить git status , то мы не увидим никаких изменений, так как все три области одинаковые.
Теперь мы хотим внести изменения в файл и сделать новый коммит. Мы пройдём через ту же процедуру: сначала отредактируем файл в нашем рабочем каталоге. Давайте называть эту версию файла v2 и обозначать зеленым цветом. Допишем в файл цифры 67890.
Теперь посмотрим, какие изменения произошли в git:
Нам подсказывают, что изменения не попадут в коммит, пока мы не сделаем git add . Выполним эту комманду чуть позже, пока добавим новый файл:
Еще раз проверяем статус репозитория:
Новый файл появился в списке не отслеживаемых, то есть в Рабочем Каталоге . Давайте добавим в отслеживание этот файл, а так же измененный ранее.
Теперь у нас есть изменения, которые будут включены в коммит. Значит пора сделать второй коммит:
Я уже упоминал, что у коммитов есть родитель, который указывает на предыдущий коммит. Из таких цепочек складывается “ветка”. О ветках мы поговорим в следующей статье. Пока достаточно знать, что по умолчанию у нас уже есть ветка main . Эта цепочка также является нашей историей проекта, вы можете вернуться к предыдущим коммитам в любой момент.
Для удобства восприятия, визуализируем наши коммиты. Кружочки это коммиты, а стрелочки между ними указывают на родителей.
Просмотр истории коммитов
Не все коммиты будете делать вы, какие-то будут делать ваши коллеги по команде, поэтому вам может понадобиться изучить историю коммитов. Одним из основных и наиболее мощных инструментов для этого является команда git log .
Помимо автора и даты, у каждого комита есть идентификатор, который называется hash. Пример: 2934ee19f4d4ca37ff9bea9dc8208ef5362d789e. Необязательно использовать такую длинную запись, git поймет и по первым 5 символам, какой hash вам нужен.
Команда git log имеет очень большое количество опций для поиска коммитов по разным критериям.
Одним из самых полезных аргументов является -p или —patch , который показывает разницу, внесенную в каждый коммит. Можно ограничить количество записей в выводе команды, используя параметр -2 :
Навигация
Прежде чем перейти к более продвинутым фичам Git, важно понять различные способы перемещения по коммитам вашего проекта.
Detaching HEAD
Давайте разберемся, как нам откатиться к более старой версии нашего репозитория.
У git есть указатели на коммиты, своеобразный ярлыки, которые перемещаются от коммита к коммиту. Одним из таких ярлыков-указателей является HEAD .
HEAD — это символическое имя текущего выбранного коммита. По сути это, тот коммит, над которым мы в данным момент работаем.
Указатели могут ссылаться на другие указатели, обычно HEAD указывает на имя ветки. Но это можно изменить, например указать hash нужного коммита, чтобы откатиться к нему.
Создадим еще один файл и сделаем третий коммит:
Мы видим, что HEAD сейчас указывает на main , main это тоже указатель, обозначающий ветку. То есть HEAD указывает на main , который в свою очередь указывает на коммит dac5bb87a . Отделение (detaching) HEAD означает лишь присвоение его не ветке, а конкретному коммиту.
Представим, что нам надо посмотреть, как выглядел наш репозиторий после второго коммита. Для этого используем команду checkout и хэш второго коммита. Кстати, можно не указывать его целиком, достаточно первых 5 символов.
Таким образом мы переключились на состояние второго коммита, в котором у нас еще не было файла three-file.txt , проверим это:
Вызвав git log видим, что HEAD теперь указывает на второй коммит:
При этом мы не потеряли третий коммит и все изменения в нем, можем убедиться в этом с помощью следующей команды:
Вернем указатель HEAD на main :
Относительные ссылки
Передвигаться по коммитам при помощи указания хешей неудобно. Поэтому Git поддерживает относительные ссылки. С относительными ссылками можно начать с какого-либо удобного места и двигаться от него.
Относительные ссылки — мощный инструмент, но мы разберем два простых способа использования:
- Перемещение на один коммит назад ^
- Перемещение на n коммитов назад
Для начала рассмотрим оператор каретки ^ . Когда мы добавляем его к имени указателя, Git воспринимает это как команду найти родителя выбранного коммита. Так что main^ означает “первый родитель ветки main”. main^^ означает прародитель (родитель родителя) main .
Давайте переключимся на коммит выше main :
Да, мы снова попали на второй коммит, то есть HEAD сейчас вновь указывает на второй коммит.
Может показаться, нужно еще раз вызвать команду git checkout main^ , чтобы попасть на первый коммит. Но это не так, указатель main остался на третьем коммите, мы сдвинули HEAD . Поэтому git checkout main^ запросит снова родителя третьего коммита.
Чтобы попасть на первый коммит, можно использовать указатель HEAD . Попробуем перейти к первому коммиту:
Вернемся на третий коммит:
Оператор
Предположим, нужно переместиться на много шагов назад. Было бы неудобно печатать ^ несколько раз, так что Git поддерживает также оператор тильда
Опционально к тильде можно добавить количество родительских коммитов, через которые нужно пройти. Посмотрим, как это работает.
Мы переместились на первый коммит. Вернемся:
Заключение
Это была первая статья по обучению git. Мы установили git и научились работать с некоторыми командами для создания коммитов и навигации по ним.
Этого уже достаточно, чтобы работать с Git локально и не потерять изменения, об остальных командах читайте в остальных статьях.