On branch main nothing to commit working tree clean как исправить

Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта. Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.

Запись изменений в репозиторий

Итак, у вас имеется настоящий Git-репозиторий и рабочая копия файлов для некоторого проекта.
Вам нужно делать некоторые изменения и фиксировать «снимки» состояния (snapshots) этих изменений в вашем репозитории каждый раз, когда проект достигает состояния, которое вам хотелось бы сохранить.

Запомните, каждый файл в вашем рабочем каталоге может находиться в одном из двух состояний: под версионным контролем (отслеживаемые) и нет (неотслеживаемые).
Отслеживаемые файлы — это те файлы, которые были в последнем снимке состояния проекта; они могут быть неизменёнными, изменёнными или подготовленными к коммиту.
Если кратко, то отслеживаемые файлы — это те файлы, о которых знает Git.

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

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

Жизненный цикл состояний файлов

Рисунок 8. Жизненный цикл состояний файлов

Определение состояния файлов

Основной инструмент, используемый для определения, какие файлы в каком состоянии находятся — это команда git status.
Если вы выполните эту команду сразу после клонирования, вы увидите что-то вроде этого:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

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

Предположим, вы добавили в свой проект новый файл, простой файл README.
Если этого файла раньше не было, и вы выполните git status, вы увидите свой неотслеживаемый файл вот так:

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README

nothing added to commit but untracked files present (use "git add" to track)

Понять, что новый файл README неотслеживаемый можно по тому, что он находится в секции «Untracked files» в выводе команды status.
Статус Untracked означает, что Git видит файл, которого не было в предыдущем снимке состояния (коммите); Git не станет добавлять его в ваши коммиты, пока вы его явно об этом не попросите.
Это предохранит вас от случайного добавления в репозиторий сгенерированных бинарных файлов или каких-либо других, которые вы и не думали добавлять.
Мы хотели добавить README, так давайте сделаем это.

Отслеживание новых файлов

Для того чтобы начать отслеживать (добавить под версионный контроль) новый файл, используется команда git add.
Чтобы начать отслеживание файла README, вы можете выполнить следующее:

Если вы снова выполните команду status, то увидите, что файл README теперь отслеживаемый и добавлен в индекс:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

    new file:   README

Вы можете видеть, что файл проиндексирован, так как он находится в секции «Changes to be committed».
Если вы выполните коммит в этот момент, то версия файла, существовавшая на момент выполнения вами команды git add, будет добавлена в историю снимков состояния.
Как вы помните, когда вы ранее выполнили git init, затем вы выполнили git add (файлы) — это было сделано для того, чтобы добавить файлы в вашем каталоге под версионный контроль.
Команда git add принимает параметром путь к файлу или каталогу, если это каталог, команда рекурсивно добавляет все файлы из указанного каталога в индекс.

Индексация изменённых файлов

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

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Файл CONTRIBUTING.md находится в секции «Changes not staged for commit» — это означает, что отслеживаемый файл был изменён в рабочем каталоге, но пока не проиндексирован.
Чтобы проиндексировать его, необходимо выполнить команду git add.
Это многофункциональная команда, она используется для добавления под версионный контроль новых файлов, для индексации изменений, а также для других целей, например для указания файлов с исправленным конфликтом слияния.
Вам может быть понятнее, если вы будете думать об этом как «добавить этот контент в следующий коммит», а не как «добавить этот файл в проект».
Выполним git add, чтобы проиндексировать CONTRIBUTING.md, а затем снова выполним git status:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Теперь оба файла проиндексированы и войдут в следующий коммит.
В этот момент вы, предположим, вспомнили одно небольшое изменение, которое вы хотите сделать в CONTRIBUTING.md до коммита.
Вы открываете файл, вносите и сохраняете необходимые изменения и вроде бы готовы к коммиту.
Но давайте-ка ещё раз выполним git status:

$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Что за чёрт?
Теперь CONTRIBUTING.md отображается как проиндексированный и непроиндексированный одновременно.
Как такое возможно?
Такая ситуация наглядно демонстрирует, что Git индексирует файл в точности в том состоянии, в котором он находился, когда вы выполнили команду git add.
Если вы выполните коммит сейчас, то файл CONTRIBUTING.md попадёт в коммит в том состоянии, в котором он находился, когда вы последний раз выполняли команду git add , а не в том, в котором он находится в вашем рабочем каталоге в момент выполнения git commit.
Если вы изменили файл после выполнения git add, вам придётся снова выполнить git add, чтобы проиндексировать последнюю версию файла:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Сокращенный вывод статуса

Вывод команды git status довольно всеобъемлющий и многословный.
Git также имеет флаг вывода сокращенного статуса, так что вы можете увидеть изменения в более компактном виде.
Если вы выполните git status -s или git status --short вы получите гораздо более упрощенный вывод:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

Новые неотслеживаемые файлы помечены ?? слева от них, файлы добавленные в отслеживаемые помечены A, отредактированные файлы помечены M и так далее.
В выводе содержится два столбца — в левом указывается статус файла, а в правом модифицирован ли он после этого.
К примеру в нашем выводе, файл README модифицирован в рабочем каталоге, но не проиндексирован, а файл lib/simplegit.rb модифицирован и проиндексирован.
Файл Rakefile модифицирован, проиндексирован и ещё раз модифицирован, таким образом на данный момент у него есть те изменения, которые попадут в коммит, и те, которые не попадут.

Игнорирование файлов

Зачастую, у вас имеется группа файлов, которые вы не только не хотите автоматически добавлять в репозиторий, но и видеть в списках неотслеживаемых.
К таким файлам обычно относятся автоматически генерируемые файлы (различные логи, результаты сборки программ и т. п.).
В таком случае, вы можете создать файл .gitignore. с перечислением шаблонов соответствующих таким файлам.
Вот пример файла .gitignore:

$ cat .gitignore
*.[oa]
*~

Первая строка предписывает 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:

# Исключить все файлы с расширением .a
*.a

# Но отслеживать файл lib.a даже если он подпадает под исключение выше
!lib.a

# Исключить файл TODO в корневом каталоге, но не файл в subdir/TODO
/TODO

# Игнорировать все файлы в каталоге build/
build/

# Игнорировать файл doc/notes.txt, но не файл doc/server/arch.txt
doc/*.txt

# Игнорировать все .txt файлы в каталоге doc/
doc/**/*.txt

Подсказка

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 status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Чтобы увидеть, что же вы изменили, но пока не проиндексировали, наберите git diff без аргументов:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if you patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

Эта команда сравнивает содержимое вашего рабочего каталога с содержимым индекса.
Результат показывает ещё не проиндексированные изменения.

Если вы хотите посмотреть, что вы проиндексировали и что войдёт в следующий коммит, вы можете выполнить git diff --staged.
Эта команда сравнивает ваши проиндексированные изменения с последним коммитом:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

Важно отметить, что git diff сама по себе не показывает все изменения сделанные с последнего коммита — только те, что ещё не проиндексированы.
Такое поведение может сбивать с толку, так как если вы проиндексируете все свои изменения, то git diff ничего не вернёт.

Другой пример: вы проиндексировали файл CONTRIBUTING.md и затем изменили его, вы можете использовать git diff для просмотра как проиндексированных изменений в этом файле, так и тех, что пока не проиндексированы.
Если наше окружение выглядит вот так:

$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Используйте git diff для просмотра непроиндексированных изменений

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

а так же git diff --cached для просмотра проиндексированных изменений (--staged и --cached синонимы):

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if you patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

Примечание

Git Diff во внешних инструментах

Мы будем продолжать использовать команду 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):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

Вы можете видеть, что комментарий по умолчанию для коммита содержит закомментированный результат работы команды git status и ещё одну пустую строку сверху.
Вы можете удалить эти комментарии и набрать своё сообщение или же оставить их для напоминания о том, что вы фиксируете.

Примечание

Для ещё более подробного напоминания, что же именно вы поменяли, можете передать аргумент -v в команду git commit.
Это приведёт к тому, что в комментарий будет также помещена дельта/diff изменений, таким образом вы сможете точно увидеть все изменения которые вы совершили.

Когда вы выходите из редактора, Git создаёт для вас коммит с этим сообщением, удаляя комментарии и вывод команды diff.

Есть и другой способ — вы можете набрать свой комментарий к коммиту в командной строке вместе с командой commit указав его после параметра -m, как в следующем примере:

$ git commit -m "Story 182: fix benchmarks for speed"
[master 463dc4f] Story 182: fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

Итак, вы создали свой первый коммит!
Вы можете видеть, что коммит вывел вам немного информации о себе: на какую ветку вы выполнили коммит (master), какая контрольная сумма SHA-1 у этого коммита (463dc4f), сколько файлов было изменено, а также статистику по добавленным/удалённым строкам в этом коммите.

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

Игнорирование индексации

Несмотря на то, что индекс может быть удивительно полезным для создания коммитов именно такими, как вам и хотелось, он временами несколько сложнее, чем вам нужно в процессе работы.
Если у вас есть желание пропустить этап индексирования, Git предоставляет простой способ.
Добавление параметра -a в команду git commit заставляет Git автоматически индексировать каждый уже отслеживаемый на момент коммита файл, позволяя вам обойтись без git add:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'Add new benchmarks'
[master 83e38c7] Add new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

Обратите внимание, что в данном случае перед коммитом вам не нужно выполнять git add для файла CONTRIBUTING.md, потому что флаг -a включает все файлы.
Это удобно, но будьте осторожны: флаг -a может включить в коммит нежелательные изменения.

Удаление файлов

Для того чтобы удалить файл из Git, вам необходимо удалить его из отслеживаемых файлов (точнее, удалить его из вашего индекса) а затем выполнить коммит.
Это позволяет сделать команда git rm, которая также удаляет файл из вашего рабочего каталога, так что в следующий раз вы не увидите его как «неотслеживаемый».

Если вы просто удалите файл из своего рабочего каталога, он будет показан в секции «Changes not staged for commit» (измененные, но не проиндексированные) вывода команды git status:

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    PROJECTS.md

no changes added to commit (use "git add" and/or "git commit -a")

Затем, если вы выполните команду git rm, удаление файла попадёт в индекс:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    PROJECTS.md

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

Другая полезная штука, которую вы можете захотеть сделать — это удалить файл из индекса, оставив его при этом в рабочем каталоге.
Другими словами, вы можете захотеть оставить файл на жёстком диске, но перестать отслеживать изменения в нём.
Это особенно полезно, если вы забыли добавить что-то в файл .gitignore и по ошибке проиндексировали, например, большой файл с логами, или кучу промежуточных файлов компиляции.
Чтобы сделать это, используйте опцию --cached:

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

Обратите внимание на обратный слеш () перед *.
Он необходим из-за того, что Git использует свой собственный обработчик имён файлов вдобавок к обработчику вашего командного интерпретатора.
Эта команда удаляет все файлы, имеющие расширение .log и находящиеся в каталоге log/.
Или же вы можете сделать вот так:

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

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

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

Таким образом, наличие в Git команды mv выглядит несколько странным.
Если вам хочется переименовать файл в Git, вы можете сделать что-то вроде:

$ git mv file_from file_to

и это отлично сработает.
На самом деле, если вы выполните что-то вроде этого и посмотрите на статус, вы увидите, что Git считает, что произошло переименование файла:

$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Однако, это эквивалентно выполнению следующих команд:

$ mv README.md README
$ git rm README.md
$ git add README

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

Загружаю бота на Heroku пишу

git init 
git add . 
git commit -m "My project"

и вот тут вылазит ошибка:

On branch master nothing to commit, working tree clean

В гугле забанили, помогите расшифровать сообщение.


  • Вопрос задан

    18 июл. 2022

  • 2985 просмотров

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

Пригласить эксперта

Вы забыли произвести сохранение после внесенных изменений ctrl/s, дальнейшие команды вводите только после этого.


  • Показать ещё
    Загружается…

10 февр. 2023, в 00:54

2000 руб./в час

10 февр. 2023, в 00:15

1000 руб./в час

09 февр. 2023, в 22:06

500 руб./за проект

Минуточку внимания

When you have added all of the changes in a repository to a commit, the Git command line will classify your working directory as “clean”. You’ll see this description if you run git status to check the status of your repository.

In this guide, we’re going to discuss what the “nothing to commit, working directory clean” message means. We’ll also discuss why you see this message even when you have made changes to your local repository that have not been pushed to a remote repository.

Get offers and scholarships from top coding schools illustration

Find Your Bootcamp Match

  • Career Karma matches you with top tech bootcamps
  • Access exclusive scholarships and prep courses

Select your interest

First name

Last name

Email

Phone number

By continuing you agree to our Terms of Service and Privacy Policy, and you consent to receive offers and opportunities from Career Karma by telephone, text message, and email.

nothing to commit, working directory clean

Git is a distributed version control system. This means you can maintain multiple separate copies of a repository.

Because multiple copies of a repository can exist, different developers can work on their own version of a repository locally. Then, when they have finished making a change, they can push their changes to the main version of the repository.

The “nothing to commit, working directory clean” message tells us all of the changes we have made to a Git repository are committed. This means the current state of our project folder is exactly the same as that of the last commit.

When you add, remove, or delete a file, this message will change. You’ll see a list of the files you have changed and a description of whether you have created, modified, or deleted that file.

Let’s run the git status command on a repository to which we have made no changes:

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

The git status command tells us we are viewing the “master” branch. The command also tells us we have not made any changes to our repository since the last commit.

If you have set up your project with a remote, you should see a message telling you whether all of the changes you have made to your repository have been pushed to the remote. This is the “Your branch is up to date” message above.

nothing to commit, working directory clean Error

The “nothing to commit, working directory clean” message may appear in error. This happens if you have not set a branch on your repository upstream.

Let’s create a local copy of our demo Git repository, ck-git. To start, we’re going to initialize a new repository, add that repository as a remote, and pull the contents of the repo:

git init
git remote add origin https://github.com/career-karma-tutorials/ck-git
git pull origin master

These commands retrieve the code from the career-karma-tutorials/ck-git repository on GitHub. Next, let’s modify a file and add it to a commit:

echo "This project is a work in progress." >> README.md
git add README.md
git commit -m "docs: Add work in progress notice"

We have just added a line of text to the README.md file. Then, we added the README.md file into the staging area and all the files in the staging area to a commit.

Let’s run git status to make sure our changes have been made:

On branch master

nothing to commit, working tree clean

This command tells us that our working tree is clean even though we’ve made changes to our remote repository. There is no message to tell us that our local repository is different to our remote repository.

This is because we have not told Git to compare our local repository to our remote repository. This occurred because we did not clone our repository. We initialized a new repository and pulled the contents from an existing repository to our local machine.

We can fix this error by setting an upstream remote branch:

git branch -u origin/master

This tells Git to compare the contents of your current branch to the “master” branch on the “origin” remote. Now, let’s run the git status command again:

On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

The Git command line informs us that our local repository contains one more commit than our remote repository. To make this message go away, we must push our changes using the git push command:

Now that we’ve pushed our changes, our local and remote repositories will be the same:

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

We’ve fixed the issue!

Conclusion

The Git “nothing to commit, working directory clean” message tells us that we have not made any changes to our repository since the last commit.

If this message appears and the contents of your remote repository are different to your local repository, check to make sure you have correctly set up an upstream branch.

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

  • Создание репозитория git
  • Создание первого коммита

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

Для того чтобы создать репозиторий, для начала, создайте папку, в которой он будет располагаться. В нашем случае это будет каталог с названием repo.

> mkdir repo

Теперь перейдем в этот каталог.

>cd repo

Создадим в нем пустой git репозиторий.

> git init

Создание первого коммита

Если мы посмотрим на список коммитов, которые были отправлены в репозиторий, то увидим, что он пустой – это правильно, т.к. мы пока только создали репозиторий и ничего ещё туда не отправляли.

> git log
fatal: your current branch 'master' does not have any commits yet

Для просмотра состояния рабочего каталога воспользуемся командой git status.

> git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)

Создадим в нашем каталоге пустой файл.

> touch README.md

Теперь, если мы выполним команду git status, то увидим, что в нашем каталоге появился один неотслеживаемый файл: README.md.

> git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        README.md

nothing added to commit but untracked files present (use "git add" to track)

Добавим, созданный файл в stage. Stage (или cache) – это хранилище для файлов с изменениями, информация о которых попадет в единый коммит. Stage является элементом архитектуры трех деревьев, на базе которой построен git, более подробно смотрите здесь. Для добавления файла README.md в stage необходимо воспользоваться командой git add.

> git add README.md

Если изменение было произведено в нескольких файлах, и мы хотим их все отправить в stage, то вместо имени файла поставьте точку.

Выполним git status для того, чтобы посмотреть на то, что сейчас происходит в нашем каталоге.

> git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   README.md

Как видно, в stage был добавлен один файл с именем README.md и теперь представленный набор изменений готов к отправке в репозиторий – т.е. к коммиту. Сделаем это.

> git commit -m "[create repository]"
[master (root-commit) 500067c] [create repository]
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md

Проверим статус каталога.

> git status
On branch master
nothing to commit, working tree clean

Как видно с момента последнего коммита никаких изменений в рабочем каталоге не производилось.

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

> git log
commit 500067cc0b80643d38e2a24e9e0699031ada6be3
Author: Writer <writer@someserver.com>
Date:   Mon Feb 12 22:51:14 2018 +0500

    [create repository]

Из приведенной информации видно, что был отправлен один коммит, который имеет ID: 500067cc0b80643d38e2a24e9e0699031ada6be3, более подробно об идентификаторах будет рассказано в следующих уроках. Автор данного коммита Writer, он (коммит) был создан Mon Feb 12 22:51:14 2018 +0500, с сообщением:  [create repository]. Это довольно подробная информация, когда коммитов станет много, такой формат вывода будет не очень удобным, сокращенный вариант выглядит так.

> git log --oneline
500067c [create repository]

Подведем небольшое резюме вышесказанному.

Создание пустого репозитория.

> git init

Добавление файлов в stage.

> git add filename

Создание коммита.

> git commit -m “message”

Просмотр статуса каталога.

> git status

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

> git log

Просмотр коммитов в репозитории с сокращенным выводом информации.

> git log --oneline

Отличный курс по git  делают ребята из GeekBrains, найдите в разделе “Курсы” курс Git. Быстрый старт”, он бесплатный!

<<< Часть 4. Архитектура Git   Часть 6. Просмотр информации по коммитам >>>

At this point, you should have a bona fide Git repository on your local machine, and a checkout or working copy of all of its files in front of you.
Typically, you’ll want to start making changes and committing snapshots of those changes into your repository each time the project reaches a state you want to record.

Remember that each file in your working directory can be in one of two states: tracked or untracked.
Tracked files are files that were in the last snapshot, as well as any newly staged files; they can be unmodified, modified, or staged.
In short, tracked files are files that Git knows about.

Untracked files are everything else — any files in your working directory that were not in your last snapshot and are not in your staging area.
When you first clone a repository, all of your files will be tracked and unmodified because Git just checked them out and you haven’t edited anything.

As you edit files, Git sees them as modified, because you’ve changed them since your last commit.
As you work, you selectively stage these modified files and then commit all those staged changes, and the cycle repeats.

The lifecycle of the status of your files

Figure 8. The lifecycle of the status of your files

Checking the Status of Your Files

The main tool you use to determine which files are in which state is the git status command.
If you run this command directly after a clone, you should see something like this:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working tree clean

This means you have a clean working directory; in other words, none of your tracked files are modified.
Git also doesn’t see any untracked files, or they would be listed here.
Finally, the command tells you which branch you’re on and informs you that it has not diverged from the same branch on the server.
For now, that branch is always master, which is the default; you won’t worry about it here.
Git Branching will go over branches and references in detail.

Note

GitHub changed the default branch name from master to main in mid-2020, and other Git hosts followed suit.
So you may find that the default branch name in some newly created repositories is main and not master.
In addition, the default branch name can be changed (as you have seen in Your default branch name), so you may see a different name for the default branch.

However, Git itself still uses master as the default, so we will use it throughout the book.

Let’s say you add a new file to your project, a simple README file.
If the file didn’t exist before, and you run git status, you see your untracked file like so:

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README

nothing added to commit but untracked files present (use "git add" to track)

You can see that your new README file is untracked, because it’s under the “Untracked files” heading in your status output.
Untracked basically means that Git sees a file you didn’t have in the previous snapshot (commit), and which hasn’t yet been staged; Git won’t start including it in your commit snapshots until you explicitly tell it to do so.
It does this so you don’t accidentally begin including generated binary files or other files that you did not mean to include.
You do want to start including README, so let’s start tracking the file.

Tracking New Files

In order to begin tracking a new file, you use the command git add.
To begin tracking the README file, you can run this:

If you run your status command again, you can see that your README file is now tracked and staged to be committed:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)

    new file:   README

You can tell that it’s staged because it’s under the “Changes to be committed” heading.
If you commit at this point, the version of the file at the time you ran git add is what will be in the subsequent historical snapshot.
You may recall that when you ran git init earlier, you then ran git add <files> — that was to begin tracking files in your directory.
The git add command takes a path name for either a file or a directory; if it’s a directory, the command adds all the files in that directory recursively.

Staging Modified Files

Let’s change a file that was already tracked.
If you change a previously tracked file called CONTRIBUTING.md and then run your git status command again, you get something that looks like this:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

The CONTRIBUTING.md file appears under a section named “Changes not staged for commit” — which means that a file that is tracked has been modified in the working directory but not yet staged.
To stage it, you run the git add command.
git add is a multipurpose command — you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved.
It may be helpful to think of it more as “add precisely this content to the next commit” rather than “add this file to the project”.
Let’s run git add now to stage the CONTRIBUTING.md file, and then run git status again:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Both files are staged and will go into your next commit.
At this point, suppose you remember one little change that you want to make in CONTRIBUTING.md before you commit it.
You open it again and make that change, and you’re ready to commit.
However, let’s run git status one more time:

$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

What the heck?
Now CONTRIBUTING.md is listed as both staged and unstaged.
How is that possible?
It turns out that Git stages a file exactly as it is when you run the git add command.
If you commit now, the version of CONTRIBUTING.md as it was when you last ran the git add command is how it will go into the commit, not the version of the file as it looks in your working directory when you run git commit.
If you modify a file after you run git add, you have to run git add again to stage the latest version of the file:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Short Status

While the git status output is pretty comprehensive, it’s also quite wordy.
Git also has a short status flag so you can see your changes in a more compact way.
If you run git status -s or git status --short you get a far more simplified output from the command:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

New files that aren’t tracked have a ?? next to them, new files that have been added to the staging area have an A, modified files have an M and so on.
There are two columns to the output — the left-hand column indicates the status of the staging area and the right-hand column indicates the status of the working tree.
So for example in that output, the README file is modified in the working directory but not yet staged, while the lib/simplegit.rb file is modified and staged.
The Rakefile was modified, staged and then modified again, so there are changes to it that are both staged and unstaged.

Ignoring Files

Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked.
These are generally automatically generated files such as log files or files produced by your build system.
In such cases, you can create a file listing patterns to match them named .gitignore.
Here is an example .gitignore file:

$ cat .gitignore
*.[oa]
*~

The first line tells Git to ignore any files ending in “.o” or “.a” — object and archive files that may be the product of building your code.
The second line tells Git to ignore all files whose names end with a tilde (~), which is used by many text editors such as Emacs to mark temporary files.
You may also include a log, tmp, or pid directory; automatically generated documentation; and so on.
Setting up a .gitignore file for your new repository before you get going is generally a good idea so you don’t accidentally commit files that you really don’t want in your Git repository.

The rules for the patterns you can put in the .gitignore file are as follows:

  • Blank lines or lines starting with # are ignored.

  • Standard glob patterns work, and will be applied recursively throughout the entire working tree.

  • You can start patterns with a forward slash (/) to avoid recursivity.

  • You can end patterns with a forward slash (/) to specify a directory.

  • You can negate a pattern by starting it with an exclamation point (!).

Glob patterns are like simplified regular expressions that shells use.
An asterisk (*) matches zero or more characters; [abc] matches any character inside the brackets (in this case a, b, or c); a question mark (?) matches a single character; and brackets enclosing characters separated by a hyphen ([0-9]) matches any character between them (in this case 0 through 9).
You can also use two asterisks to match nested directories; a/**/z would match a/z, a/b/z, a/b/c/z, and so on.

Here is another example .gitignore file:

# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

Tip

GitHub maintains a fairly comprehensive list of good .gitignore file examples for dozens of projects and languages at https://github.com/github/gitignore if you want a starting point for your project.

Note

In the simple case, a repository might have a single .gitignore file in its root directory, which applies recursively to the entire repository.
However, it is also possible to have additional .gitignore files in subdirectories.
The rules in these nested .gitignore files apply only to the files under the directory where they are located.
The Linux kernel source repository has 206 .gitignore files.

It is beyond the scope of this book to get into the details of multiple .gitignore files; see man gitignore for the details.

Viewing Your Staged and Unstaged Changes

If the git status command is too vague for you — you want to know exactly what you changed, not just which files were changed — you can use the git diff command.
We’ll cover git diff in more detail later, but you’ll probably use it most often to answer these two questions: What have you changed but not yet staged?
And what have you staged that you are about to commit?
Although git status answers those questions very generally by listing the file names, git diff shows you the exact lines added and removed — the patch, as it were.

Let’s say you edit and stage the README file again and then edit the CONTRIBUTING.md file without staging it.
If you run your git status command, you once again see something like this:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

To see what you’ve changed but not yet staged, type git diff with no other arguments:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

That command compares what is in your working directory with what is in your staging area.
The result tells you the changes you’ve made that you haven’t yet staged.

If you want to see what you’ve staged that will go into your next commit, you can use git diff --staged.
This command compares your staged changes to your last commit:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

It’s important to note that git diff by itself doesn’t show all changes made since your last commit — only changes that are still unstaged.
If you’ve staged all of your changes, git diff will give you no output.

For another example, if you stage the CONTRIBUTING.md file and then edit it, you can use git diff to see the changes in the file that are staged and the changes that are unstaged.
If our environment looks like this:

$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Now you can use git diff to see what is still unstaged:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

and git diff --cached to see what you’ve staged so far (--staged and --cached are synonyms):

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

Note

Git Diff in an External Tool

We will continue to use the git diff command in various ways throughout the rest of the book.
There is another way to look at these diffs if you prefer a graphical or external diff viewing program instead.
If you run git difftool instead of git diff, you can view any of these diffs in software like emerge, vimdiff and many more (including commercial products).
Run git difftool --tool-help to see what is available on your system.

Committing Your Changes

Now that your staging area is set up the way you want it, you can commit your changes.
Remember that anything that is still unstaged — any files you have created or modified that you haven’t run git add on since you edited them — won’t go into this commit.
They will stay as modified files on your disk.
In this case, let’s say that the last time you ran git status, you saw that everything was staged, so you’re ready to commit your changes.
The simplest way to commit is to type git commit:

Doing so launches your editor of choice.

Note

This is set by your shell’s EDITOR environment variable — usually vim or emacs, although you can configure it with whatever you want using the git config --global core.editor command as you saw in Getting Started.

The editor displays the following text (this example is a Vim screen):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

You can see that the default commit message contains the latest output of the git status command commented out and one empty line on top.
You can remove these comments and type your commit message, or you can leave them there to help you remember what you’re committing.

Note

For an even more explicit reminder of what you’ve modified, you can pass the -v option to git commit.
Doing so also puts the diff of your change in the editor so you can see exactly what changes you’re committing.

When you exit the editor, Git creates your commit with that commit message (with the comments and diff stripped out).

Alternatively, you can type your commit message inline with the commit command by specifying it after a -m flag, like this:

$ git commit -m "Story 182: fix benchmarks for speed"
[master 463dc4f] Story 182: fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

Now you’ve created your first commit!
You can see that the commit has given you some output about itself: which branch you committed to (master), what SHA-1 checksum the commit has (463dc4f), how many files were changed, and statistics about lines added and removed in the commit.

Remember that the commit records the snapshot you set up in your staging area.
Anything you didn’t stage is still sitting there modified; you can do another commit to add it to your history.
Every time you perform a commit, you’re recording a snapshot of your project that you can revert to or compare to later.

Skipping the Staging Area

Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow.
If you want to skip the staging area, Git provides a simple shortcut.
Adding the -a option to the git commit command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the git add part:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'Add new benchmarks'
[master 83e38c7] Add new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

Notice how you don’t have to run git add on the CONTRIBUTING.md file in this case before you commit.
That’s because the -a flag includes all changed files.
This is convenient, but be careful; sometimes this flag will cause you to include unwanted changes.

Removing Files

To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit.
The git rm command does that, and also removes the file from your working directory so you don’t see it as an untracked file the next time around.

If you simply remove the file from your working directory, it shows up under the “Changes not staged for commit” (that is, unstaged) area of your git status output:

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    PROJECTS.md

no changes added to commit (use "git add" and/or "git commit -a")

Then, if you run git rm, it stages the file’s removal:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    PROJECTS.md

The next time you commit, the file will be gone and no longer tracked.
If you modified the file or had already added it to the staging area, you must force the removal with the -f option.
This is a safety feature to prevent accidental removal of data that hasn’t yet been recorded in a snapshot and that can’t be recovered from Git.

Another useful thing you may want to do is to keep the file in your working tree but remove it from your staging area.
In other words, you may want to keep the file on your hard drive but not have Git track it anymore.
This is particularly useful if you forgot to add something to your .gitignore file and accidentally staged it, like a large log file or a bunch of .a compiled files.
To do this, use the --cached option:

You can pass files, directories, and file-glob patterns to the git rm command.
That means you can do things such as:

Note the backslash () in front of the *.
This is necessary because Git does its own filename expansion in addition to your shell’s filename expansion.
This command removes all files that have the .log extension in the log/ directory.
Or, you can do something like this:

This command removes all files whose names end with a ~.

Moving Files

Unlike many other VCSs, Git doesn’t explicitly track file movement.
If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file.
However, Git is pretty smart about figuring that out after the fact — we’ll deal with detecting file movement a bit later.

Thus it’s a bit confusing that Git has a mv command.
If you want to rename a file in Git, you can run something like:

$ git mv file_from file_to

and it works fine.
In fact, if you run something like this and look at the status, you’ll see that Git considers it a renamed file:

$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

However, this is equivalent to running something like this:

$ mv README.md README
$ git rm README.md
$ git add README

Git figures out that it’s a rename implicitly, so it doesn’t matter if you rename a file that way or with the mv command.
The only real difference is that git mv is one command instead of three — it’s a convenience function.
More importantly, you can use any tool you like to rename a file, and address the add/rm later, before you commit.

Цель

Узнайте, как отменить изменения на локальной машине и в репозитории Bitbucket Cloud во время совместной работы с коллегами.

Краткое описание основной задачи

В этом обучающем руководстве рассматриваются команды git revert, git reset, git log и git status

Время Аудитория Обязательные условия

40 минут

В этом обучающем руководстве предполагается, что вы знакомы со следующими командами Git:

git clone, git commit, git pull и git push

У вас установлен Git
У вас есть аккаунт Bitbucket

Ошибиться может каждый. Не все изменения, отправляемые с помощью команды push, идеальны, поэтому в этом учебном руководстве рассматриваются наиболее распространенные команды Git для безопасной отмены изменений.

В этом обучающем руководстве предполагается, что вы знакомы со следующими командами Git:

  • git clone
  • git commit
  • git pull
  • git push

Если вы не знакомы с этими командами, мы поможем изучить Git с помощью Bitbucket Cloud. Далее вернитесь на эту страницу и узнайте, как отменять изменения. Эти команды Git подходят для сред Windows и Unix. При навигации по файловой системе в этом руководстве будут использоваться утилиты командной строки Unix.

Отмена изменений на локальной машине

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

Команда Определение

git revert

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

git reset

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

  • --soft: только сброс указателя HEAD до выбранного коммита. Действие команды аналогично git checkout <номер коммита>, но в этом режиме указатель HEAD не открепляется.
  • --mixed: сброс указателя HEAD до выбранного коммита в истории и отмена изменений в индексе.
  • --hard: сброс указателя HEAD до выбранного коммита в истории, отмена изменений в индексе и отмена изменений в рабочем каталоге. В рамках данного обучения мы не будем демонстрировать работу команды reset в режиме hard.

Подробное описание принципа работы команды git reset приведено в разделе сайта git-scm.com Git Tools — Reset Demystified (Инструменты Git — Раскрытие тайн reset).

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

Форк репозитория

Начнем с создания уникального репозитория, содержащего весь код оригинального репозитория. Этот процесс называется разветвлением (созданием форка) репозитория. Создание форка — это расширенный процесс Git, который используется, когда общий репозиторий размещается на стороннем сервисе хостинга, таком как Bitbucket.

  1. Щелкните по следующему URL или введите его в адресную строку: https://bitbucket.org/atlassian/tutorial-documentation-tests/commits/all
  2. Щелкните на левой боковой панели значок +, а затем выберите Fork this repository (Сделать форк этого репозитория), изучите содержимое диалогового окна и щелкните Fork repository (Сделать форк репозитория).
  3. Перед вами появится обзор нового репозитория.
  4. Щелкните значок «+» и выберите Clone this repository (Клонировать этот репозиторий).
  5. Клонируйте репозиторий на свой компьютер.
  6. Перейдите в каталог, в котором находится клонированный репозиторий.

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

Поиск изменений в локальной системе

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

git status

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

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.
nothing to commit, working tree clean

Согласно выводу команды git status, все данные соответствуют данным в удаленной главной ветке main, а изменений, ожидающих коммита, нет. В следующем примере мы внесем небольшие изменения в репозиторий и рассмотрим его в состоянии отложенных изменений. То есть мы рассмотрим репозиторий, находящийся в локальной системе, в котором файлы изменены, но не подготовлены (или не проиндексированы) для добавления в историю проекта.

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

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.

 Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git checkout -- <file>..." to discard changes in working directory)

  Modified: myquote2.html

 no changes added to commit (use "git add" and/or "git commit -a")
--

Согласно выводу, в репозитории есть отложенные изменения для файла myquote2.html. Хорошие новости! Если отменяемое изменение не было добавлено в раздел проиндексированных файлов (как в примере выше), вы можете просто отредактировать файл и продолжить работу. Git начинает отслеживать изменения только после того, как они добавлены в раздел проиндексированных файлов и выполнен коммит в историю проекта.

Теперь давайте отменим изменения, внесенные в файл myquote2.html. Поскольку это упрощенный пример с минимумом изменений, мы можем отменить их двумя способами. Если выполнить команду git checkout myquote2.html, репозиторий восстановит файл myquote2.html до версии предыдущего коммита. Если же выполнить команду git reset --hard, весь репозиторий будет возвращен к состоянию последнего коммита.

git log

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

Этот же журнал истории коммитов можно найти в пользовательском интерфейсе Bitbucket, обратившись к представлению коммитов в репозитории. Представление коммитов для нашего демонстрационного репозитория можно найти по ссылке https://bitbucket.org/dans9190/tutorial-documentation-tests/commits/all. Это представление будет похоже на вывод утилиты командной строки git log. С его помощью можно найти и указать коммит для отмены.

В следующем примере история состоит из нескольких изменений, но каждое изменение по сути является коммитом. Это то, что нам нужно найти и отменить.

$ git status
On branch main
Your branch is up-to-date with 'origin/main'.

nothing to commit, working tree clean

$ git log

commit 1f08a70e28d84d5034a8076db9103f22ec2e982c
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Wed Feb 7 17:06:50 2018 +0000

    Initial Bitbucket Pipelines configuration

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700

    repeated quote to show how a change moves through the process

commit 4801b87c2147dce83f1bf31acfcffa6cb1d7e0a5
Merge: 1a6a403 3b29606
Author: Dan Stevens [Atlassian] <dstevens@atlassian.com>
Date:   Fri Jul 29 18:45:34 2016 +0000

    Merged in changes (pull request #6)

    Changes

Рассмотрим один из перечисленных коммитов внимательнее.

commit 52f823ca251a132225dd1cc18ad768de8d336e84
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Fri Sep 30 15:50:58 2016 -0700

     repeated quote to show how a change moves through the process

Вы можете заметить, что каждый комментарий к коммиту состоит из четырех элементов.

Элемент Описание

Хеш коммита

Буквенно-цифровая строка (генерируемая функцией SHA-1), по которой можно идентифицировать то или иное изменение

Автор

Лицо, сделавшее коммит изменения

Дата

Дата внесения изменения в проект с помощью коммита

Комментарий к коммиту

Текстовая строка с описанием изменения.

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

Поиск местонахождения конкретного коммита

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

  1. В окне терминала перейдите на самый верхний уровень локального репозитория с помощью команды cd (change directory — сменить каталог).
$ cd ~/repos/tutorial-documentation-tests/

Введите команду git log --oneline. Параметр --oneline отобразит каждый коммит в отдельной строке, поэтому в окне терминала поместится больше записей из истории.

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

Вы увидите нечто подобное:

$ git log --oneline
1f08a70 (HEAD -> main, origin/main, origin/HEAD) Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
...
  1. Нажмите клавишу q, чтобы вернуться к командной строке.
  2. Найдите коммит с хешем c5826da и комментарием more changes в списке, образованном после выполнения команды git log. Кто-то не написал подробный комментарий к коммиту, поэтому необходимо выяснить, есть ли в нем необходимые нам изменения.
  3. Выделите и скопируйте хеш коммита c5826da из вывода команды git log в окне терминала.
  4. Введите команду git show, а затем вставьте скопированный хеш коммита или перепишите его и нажмите клавишу ввода. Вы увидите нечто подобное:
$git show c5826daeb6ee3fd89e63ce35fc9f3594fe243605
commit c5826daeb6ee3fd89e63ce35fc9f3594fe243605
Author: Daniel Stevens <dstevens@atlassian.com>
Date:   Tue Sep 8 13:50:23 2015 -0700

    more changes

diff --git a/README.md b/README.md
index bdaee88..6bb2629 100644
--- a/README.md
+++ b/README.md
@@ -11,12 +11,7 @@ This README would normally document whatever steps are necessary to get your app
 ### How do I get set up? ###

 * Summary of set up
-* Configuration
-* Dependencies
-* Database configuration
-* How to run tests
-* Deployment instructions
-* more stuff and things
:

Строка внизу продолжит заполняться до тех пор, пока не отобразится изменение целиком. Нажмите клавишу q, чтобы закрыть командную строку.

Фильтрация вывода команды git log для поиска определенного коммита

Отфильтровать и скорректировать вывод команды git log можно с помощью следующих параметров:

Фильтр Описание Пример команды Результаты выполнения
-

Ограничивает количество отображаемых коммитов

git log -10

10 последних коммитов в истории

--after

--before

Ограничивает отображаемые коммиты установленными временными рамками

Вы также можете использовать --after "гггг-мм-дд" --before "гггг-мм-дд"

git log --after 2017-07-04

Все коммиты после 4 июля 2017 года

--author="имя"

Выводит список всех коммитов, автор которых совпадает с указанным

git log --author="Alana"

Все коммиты, у которых в поле имени автора содержится строка «Alana»

--grep="строка комментария"

Возвращает все коммиты, комментарий к которым содержит указанную строку

git log --grep="HOT-"

Все коммиты, содержащие строку «HOT-» в комментарии к коммиту

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

Отмена изменения с помощью git reset

Сначала давайте просто отменим последний коммит в истории. Предположим, вы только что включили конвейеры непрерывной интеграции и непрерывной поставки (CI/CD) Bitbucket, но обнаружили, что скрипт работает не совсем так, как нужно.

  1. Введите в окне терминала команду git log --oneline.
  2. Скопируйте хеш второго коммита в журнале (52f823c), а затем нажмите клавишу q, чтобы закрыть журнал.
  3. Введите в окне терминала команду git reset --soft 52f823c. Если все нормально, команда должна запуститься в фоновом режиме. Вот и все, вы отменили ваше первое изменение. Теперь давайте посмотрим на результат этого действия.
  4. Введите в окне терминала команду git status. Вы увидите, что коммит был отменен, а изменения теперь остаются неподтвержденными. Это будет выглядеть примерно так:
$ git status
On branch main
Your branch is behind 'origin/main' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

 Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

     new file:   bitbucket-pipelines.yml

  1. Введите в окне терминала команду git log --oneline. Вы должны увидеть что-то увидите нечто подобное:
$ git log --oneline
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 (origin/changes) myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
...
  1. Вы увидите, что в качестве нового указателя HEAD для ветки указан требуемый коммит 52f823c.
  2. Нажмите клавишу q, чтобы закрыть журнал. Не закрывайте терминал, поскольку теперь, после изучения простого применения команды reset, мы рассмотрим чуть более сложный вариант.

Отмена нескольких изменений с помощью git reset

Допустим, вы обнаружили, что запрос pull № 6 (4801b87) необходимо доработать, и при этом вы хотите поддержать чистоту истории, поэтому на этот раз вы будете сбрасывать указатель HEAD до коммита 1a6a403 с помощью команды git reset.

  1. Введите команду git log --oneline.
  2. Скопируйте хеш коммита 1a6a403 (myquote edited online with Bitbucket), созданного прямо перед запросом pull № 6, в котором мы хотим отменить изменения.
  3. Введите в окне терминала команду git reset 1a6a403. Вывод должен выглядеть примерно так:
$ git reset 1a6a403
Unstaged changes after reset:
M README.md
M myquote2.html

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

  1. Введите в окне терминала команду git status. Вывод должен выглядеть примерно так:

$ git status
On branch main
Your branch is behind 'origin/main' by 6 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

 Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

     modified:   README.md
    modified:   myquote2.html

 Untracked files:
  (use "git add <file>..." to include in what will be committed)

     bitbucket-pipelines.yml

 no changes added to commit (use "git add" and/or "git commit -a")

Теперь Git вообще не отслеживает первое отмененное изменение (файл bitbucket-pipelines.yml). Это связано с тем, что команда git reset удалила изменение как из указателя HEAD ветки, так и из области отслеживания (или индекса) Git. Основной процесс выглядит несколько сложнее, чем описывается в этом руководстве, подробнее см. в руководстве по команде git reset.

  1. Введите в окне терминала команду git log --oneline.
1a6a403 myquote edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
879f965 adding to the quote file
8994332 Merged in HOT-235 (pull request #2)
b4a0b43 removed sarcastic remarks because they violate policy.
b5f5199 myquote2.html created online with Bitbucket
b851618 adding my first file
5b43509 writing and using tests

Согласно выводу команды log, история коммитов также была изменена и начинается с коммита 1a6a403. Для демонстрации следующего примера допустим, что мы хотим отменить сброс, который только что выполнили. В дальнейшем мы, возможно, захотим сохранить содержимое запроса pull № 6.

Отправка результатов отмены в Bitbucket

Команда git reset — один из способов отмены, которые предлагает Git. В целом сброс с помощью команды reset считается небезопасным. Он хорошо подходит для локального применения к изолированному коду, но становится опасным при работе над общим кодом с другими участниками команды.

Чтобы поделиться сброшенной веткой с удаленной командой, необходимо использовать принудительную отправку изменений. Принудительная отправка изменений выполняется с помощью команды git push -f. Она уничтожит всю историю ветки, созданную после этой точки отправки.

Ниже приведен пример небезопасного сценария.

  • Разработчик A работает в ветке над новой возможностью.
  • Разработчик B работает в той же ветке над другой возможностью.
  • Разработчик B решает сбросить ветку к более раннему состоянию, когда разработчики A и B еще не приступили к работе.
  • Разработчик B принудительно отправляет сброшенную ветку в удаленный репозиторий.
  • Разработчик A делает запрос pull для этой ветки, чтобы получить обновления. Во время выполнения запроса pull разработчик A получает принудительное обновление, которое сбрасывает его локальную ветку к тому моменту времени, когда он еще не начал работать над новой возможностью. Соответственно, он теряет все коммиты.

Отмена команды git reset

До сих пор мы передавали в git reset SHA-хеши коммитов Git. Теперь вывод команды git log не показывает сброшенные коммиты. Как их вернуть? Git никогда не удаляет коммиты окончательно, хотя все указатели на них открепляются. Кроме того, Git хранит отдельный журнал со всеми перемещениями ссылок — reflog, или журнал ссылок. Проверить журнал ссылок можно с помощью команды git reflog.

1a6a403 HEAD@{0}: reset: moving to 1a6a403
1f08a70 HEAD@{1}: reset: moving to origin/main
1f08a70 HEAD@{2}: clone: from git@bitbucket.org:dans9190/tutorial-documentation-tests.git

Вывод команды git reflog должен быть аналогичен показанному в примере выше. Вы можете просмотреть историю действий в репозитории. Самая верхняя строчка является ссылкой на команду reset, которую мы выполнили для сброса запроса pull № 6. Теперь сбросим выполнение команды reset, чтобы восстановить запрос pull № 6. Во втором столбце вывода команды reflog находится указатель на действие по изменению репозитория. Здесь HEAD@{0} — это ссылка на выполненную нами ранее команду reset. Мы не хотим снова выполнять эту команду сброса, поэтому восстановим репозиторий до HEAD@{1}.

$ git reset --hard HEAD@{1}
HEAD is now at 1f08a70 Initial Bitbucket Pipelines configuration

Теперь давайте рассмотрим историю коммитов репозитория с помощью команды git log --oneline:

$git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

Здесь видно, что история коммитов репозитория была восстановлена до предыдущей версии, с которой мы экспериментировали. Коммит 4801b87 восстановлен, хотя был утерян при первой операции сброса. Команда git reflog является мощным инструментом для отмены изменений в репозитории. Подробнее о ее использовании см. на странице git reflog.

git revert

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

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

$ git log --online
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
1f08a70 Initial Bitbucket Pipelines configuration
52f823c repeated quote to show how a change moves through the process
4801b87 Merged in changes (pull request #6)
1a6a403 myquote edited online with Bitbucket
3b29606 myquote2.html edited online with Bitbucket
8b236d9 myquote edited online with Bitbucket
235b9a7 testing prs
c5826da more changes
43a87f4 remivng
d5c4c62 a few small changes
23a7476 Merged in new-feature2 (pull request #3)
5cc4e1e add a commit message
cbbb5d6 trying a thing
438f956 adding section for permissions and cleaning up some formatting
23251c1 updated snipptes.xml organization into resources. other files misc changes
3f630f8 Adding file to track changes
e52470d README.md edited online with Bitbucket
e2fad94 README.md edited online with Bitbucket
592f84f Merge branch 'main' into new-feature2 Merge branch  especially if it merges an updated upstream into a topic branch.
7d0bab8 added a line
:

В этом примере будем работать с самым последним коммитом — 1f08a70. Предположим, что мы хотим отменить изменения, внесенные в этот коммит. Выполните следующую команду.

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

Вы только что узнали, как отменять изменения!

Вы закончили, поздравляем! Вы можете в любое время вернуться к этому учебному руководству или ознакомиться с разделом «Отмена изменений», чтобы изучить эту тему подробнее. Продолжайте в том же духе в Bitbucket!

Перевод первой части статьи «How to Use Git and Git Workflows – a Practical Guide».

Все говорят, что разработчику нужно знать Git — и это правда. Но будем откровенны: Git не так прост.

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

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

Я считаю, что как и многие другие вещи в программировании, Git лучше всего изучать на практике. Начните пользоваться инструментом — и постепенно освоите и основы, и продвинутый функционал.

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

Мы будем использовать простые команды и разбирать стоящие за ними концепции — но только в том объеме, который способствует лучшему пониманию.

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

Также отмечу, что я не буду использовать древовидные схемы (такие, как на иллюстрации снизу). Дело в том, что лично меня они всегда только сбивали с толку, и то, что я никогда не представлял себе Git именно таким образом, не помешало мне стать продуктивным разработчиком.

https://www.atlassian.com/git/tutorials/using-branches/git-checkout

В первой части статьи мы рассмотрим следующие темы:

  • Как установить Git и настроить аккаунт на GitHub
  • Как создать новый репозиторий на GitHub
  • Как клонировать Git-репозиторий
  • Ветки в Git
  • Как посмотреть состояние проекта в Git
  • Как сделать первый коммит

Я советую вам испытывать все описываемые команды самостоятельно, на вашей машине. Итак, начнем!

Как установить Git и настроить аккаунт на GitHub

Начнем с рутинных, но необходимых вещей.

Если вы уже установили Git на своей машине, завели аккаунт на GitHub (или GitLab, или Bitbucket) и настроили SSH-соединение, то этот раздел можно пропустить.

Если нет, для начала нужно установить Git.

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

Заведя аккаунт, нужно создать SSH-ключ. Это позволит вам отправлять ваш код с вашей локальной машины на GitHub (при помощи ключа GitHub будет проверять, что вы — это вы). Это не сложно: просто следуйте инструкции.

Как создать новый репозиторий на GitHub

Следующее, что нам нужно сделать, это создать репозиторий на GitHub.

Это просто. Нажмите кнопку «New» на вашей домашней странице:

Затем выберите имя для репозитория и укажите, будет он приватным или публичным. Опционально можно добавить файл README. Затем нажмите кнопку «Create repository».

Свой репозиторий я назвал practical-git-tutorial. В нем содержатся все шаги, описанные в этом руководстве, так что при желании можете пользоваться им как справочником.

Как клонировать Git-репозиторий

Чтобы начать работать, нам нужно «клонировать» репозиторий. Клонирование означает скачивание из источника всего кода проекта, а также метаданных. Источником в нашем случае является GitHub.

Чтобы клонировать репозиторий, используйте команду git clone <URL>.

В примере я использовал URL репозитория, который только что создал, а вам нужно подставить URL вашего.

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

$ git clone git@github.com:johnmosesman/practical-git-tutorial.git
Cloning into 'practical-git-tutorial'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (6/6), done.

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

Давайте перейдем в папку проекта (при помощи команды cd):

$ cd practical-git-tutorial/
/practical-git-tutorial (main)$

Мы перешли в папку проекта (это обычная папка, такая же, как все остальные). Ваш терминал может выводить рядом с именем папки слово (main).

Ветки в Git

Наличие (main) рядом с именем папки означает, что в настоящее время мы находимся в ветке под названием main. Что такое ветка (англ branch)? Считайте, что это копия проекта в определенный момент времени, которую можно изменять независимо от других веток.

Рассмотрим пример. Если бы мы писали книгу, у нас могли бы быть следующие ветки:

  • main branch (главная ветка)
  • table-of-contents branch (ветка содержания)
  • chapter-1 branch (ветка первой главы)
  • chapter-2 branch (ветка второй главы)
  • и так далее.

Ветка main — главная. Это место, где мы будем собирать все содержимое воедино, в законченную книгу.

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

Допустим, я работаю над Главой 1, а вы — над Главой 2. Мы можем создать две разные ветки, chapter-1 и chapter-2, каждая из которых будет отдельной копией текущего состояния книги.

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

Когда один из нас закончит работу над своей главой, он сможет добавить содержимое этой главы обратно в ветку main. Когда мы оба закончим работу, в ветке main будет и Глава 1, и Глава 2.

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

Примечание. Главная ветка может называться не main, а master: это зависит от проекта. Функциональной разницы нет.

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

Работая над проектами, мы довольно часто проверяем их состояние и смотрим, какие изменения были внесены.

Чтобы просмотреть статус нашего проекта, мы используем команду git status:

(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Давайте разберем вывод команды.

Первое, что нам сообщает git status, это то, что мы находимся в ветке main:

On branch main

Второе предложение немного интереснее:

Your branch is up to date with 'origin/main'.

Git сообщает, что наша ветка полностью соответствует некоему origin/main.

Это новая концепция. origin (или remote) — удаленный источник, т. е., находящийся не на вашей локальной машине.

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

Вернемся на момент к нашему примеру с книгой. Если бы я писал Главу 1 на своей машине, а вы — Главу 2 на вашей машине, мы могли бы добавить себе компьютеры друг друга в качестве удаленных источников, чтобы обмениваться внесенными изменениями. Ведь одно из главных достоинств Git — контролируемое сотрудничество с другими людьми.

На практике сообщество разработчиков в целом пришло к выводу, что лучше не обмениваться изменениями в стиле «все-со-всеми», а иметь единый источник истины для кода. Текущее состояние кодовой базы в этом источнике считается «правильным», а все остальные с ним сверяются. По соглашению это место называется origin (англ. начало, источник).

В нашем случае origin — репозиторий на GitHub.

На самом деле мы можем посмотреть, что у нас считается origin, запустив команду git remote -v (-v означает «verbose»: информация будет выводиться «многословно», подробно).

(main)$ git remote -v
origin  git@github.com:johnmosesman/practical-git-tutorial.git (fetch)
origin  git@github.com:johnmosesman/practical-git-tutorial.git (push)

Эта команда выводит список всех наших удаленных репозиториев. Мы видим, что у нас есть удаленный репозиторий с именем origin, а его Git URL указывает на наш репозиторий на Github.com. Это было настроено автоматически, когда мы запустили git clone.

Но вернемся к выводу команды git status:

Your branch is up to date with 'origin/main'.

Когда мы запросили статус проекта, Git ответил, что наша локальная ветка main полностью соответствует ветке main в нашем origin (GitHub).

Git «увидел», что в origin, который мы клонировали, в качестве главной ветки была ветка main. И команда git clone автоматически создала для нас локальную ветку main.

В общем, на нашей локальной машине не внесено никаких изменений, которых нет на GitHub, и наоборот. Наша локальная ветка main и ветка main в репозитории на GitHub идентичны.

Когда мы внесем какие-нибудь изменения, в выводе команды git status сообщение уже будет другим. Оно будет отражать разницу между нашим локальным репозиторием и репозиторием origin (GitHub).

Последнее сообщение git status касается состояния локального проекта:

nothing to commit, working tree clean

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

Подобьем итоги. Выполнив команду git status, мы узнали следующие вещи:

  • мы находимся в ветке main
  • наша локальная ветка main идентична ветке main в origin (GitHub)
  • мы еще не внесли никаких изменений в проект.

Как сделать первый коммит

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

Продолжая аналогию с написанием книги, давайте создадим новый файл chapter-1.txt и вставим в него какой-то текст.

(Вы можете выполнить в терминале команды, указанные ниже, или просто создать файл в любом текстовом редакторе).

(main)$ touch chapter-1.txt
(main)$ echo "Chapter 1 - The Beginning" >> chapter-1.txt
(main)$ cat chapter-1.txt
Chapter 1 - The Beginning

Мы создаем файл chapter-1.txt при помощи команды touch и вставляем в него текст «Chapter 1 — The Beginning» при помощи команды echo и оператора перенаправления. Чтобы проверить результат, выводим содержимое файла на экран при помощи команды cat.

У нас есть простой текстовый файл с маленьким текстом.

Давайте теперь запустим git status и посмотрим, что изменится в выводе.

(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        chapter-1.txt

nothing added to commit but untracked files present (use "git add" to track)

Да, кое-что определенно изменилось. Мы видим раздел, описывающий «Untracked files» («Неотслеживаемые файлы»), в котором есть наш файл chapter-1.txt.

Прежде чем Git начнет отслеживать изменения в файле, нам сначала нужно сказать ему делать это. И, как написано в конце сообщения, для этого можно использовать команду git add:

(main)$ git add chapter-1.txt

(Можно не указывать конкретное имя, а просто поставить точку. Таким образом будут «захвачены» все изменения в директории).

Давайте еще раз проверим статус проекта:

(main)$ git status
On branch main
Your branch is up to date with 'origin/main'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   chapter-1.txt

john:~/code/practical-git-tutorial (main)$

Сообщение снова изменилось. Теперь в нем говорится, что у нас есть некоторые изменения, готовые к «закреплению» — коммиту.

В Git коммит — это сохраненный кусочек работы. Но это сохранение отличается от сохранения файла в текстовом редакторе.

Можно считать, что коммит — это завершенная идея или юнит работы.

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

  • Написать название главы. /Нажать кнопку «Сохранить» в редакторе/
  • Написать первый абзац. /Снова нажать кнопку «Сохранить»/
  • Написать второй абзац. /«Сохранить»/
  • Написать последний абзац. /«Сохранить»/

Мы «сохранили» документ четыре раза, но после этих четырех сохранений у нас на руках первый черновик нашей главы, а этот черновик — один «юнит» нашей работы.

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

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

Чтобы закоммиттить наши изменения, сначала их нужно внести в зону стейджинга (подготовки) при помощи команды git add.

(О стейджинге мы еще поговорим).

Затем нам нужно завершить сохранение изменений при помощи команды git commit.

Считается хорошим тоном добавлять описание того, какие именно изменения вы внесли и, что более важно, — зачем вы это сделали.

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

Давайте закоммитим новый файл с сообщением. Чтобы добавить сообщение, припишем к команде флаг -m (от message).

(main)$ git commit -m "New chapter 1 file with chapter heading"
[main a8f8b95] New chapter 1 file with chapter heading
 1 file changed, 1 insertion(+)
 create mode 100644 chapter-1.txt

Мы сохранили этот кусочек работы и можем увидеть это, просмотрев лог Git при помощи команды git log:

(main)$ git log
commit a8f8b95f19105fe10ed144fead9cab84520181e3 (HEAD -> main)
Author: John Mosesman <johnmosesman@gmail.com>
Date:   Fri Mar 19 12:27:35 2021 -0500

    New chapter 1 file with chapter heading

commit 2592324fae9c615a96f856a0d8b8fe1d2d8439f8 (origin/main, origin/HEAD)
Author: John Mosesman <johnmosesman@users.noreply.github.com>
Date:   Wed Mar 17 08:48:25 2021 -0500

    Update README.md

commit 024ea223ee4055ae82ee31fc605bbd8a5a3673a0
Author: John Mosesman <johnmosesman@users.noreply.github.com>
Date:   Wed Mar 17 08:48:10 2021 -0500

    Initial commit

Глядя на этот лог, мы видим, что у нас в истории проекта есть три коммита.

Последний из них — тот, который мы только что сделали. Мы видим наше сообщение коммита.

До него было еще два коммита: один был сделан, когда я инициализировал проект, а второй — когда обновил файл README.md на GitHub.

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

commit a8f8b95f19105fe10ed144fead9cab84520181e3 (HEAD -> main)

Эта строка называется SHA. Это уникальный ID, сгенерированный для коммита при помощи алгоритма хеширования. Пока просто обратите на него внимание, а позже мы к нему вернемся.

После SHA коммитов мы видим еще пару интересных вещей:

  • (HEAD -> main) рядом с последним коммитом
  • (origin/main, origin/HEAD) рядом с предпоследним коммитом.

Это говорит нам о текущем статусе нашей ветки и удаленных веток (насколько он нам известен).

Что касается последнего коммита, мы видим, что HEAD указывает на нашу локальную ветку main (HEAD -> main). HEAD — это указатель на текущую ветку.

Это имеет смысл. Мы только сделали коммит и пока больше ничего не делали. Мы все еще во временной точке этого коммита.

Если мы посмотрим на предыдущий коммит, начинающийся с 25923, мы увидим рядом с ним (origin/main, origin/HEAD). Это говорит нам о том, что в origin (GitHub) HEAD указывает на наш предыдущий коммит.

В общем, наша машина думает, что последнее изменение в локальной ветке main — коммит с добавленной Главой 1. Также наша машина думает, что на GitHub последнее изменение — коммит, которым я обновил README перед написанием этой статьи.

И это понятно: мы же не сообщали GitHub-у о самом последнем нашем коммите. GitHub все еще думает, что репозиторий соответствует текущему состоянию проекта.

Конец первой части. В следующей части мы отправим наш новый коммит на GitHub.

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

Читайте также:

  • On board parity error
  • Omvl ошибка е029 saver
  • Omsi ошибка при запуске приложения 0xc0000906
  • Omsi 2 ошибка fehler bei bereichsprufung
  • Omsi 2 ошибка d3dx9 dll

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

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