Как удалить коммит git

Как удалить коммит git

Убрать последний git-коммит, не меняя файлов проекта

У меня есть локальный репозиторий моего проекта. Там есть несколько коммитов. Последний коммит был сделан необдуманно (вспомнилось, что там есть пара проблем, которые не хотелось бы увековечивать). Я умею возвращаться к предыдущему коммиту (команда Revert). Но это не то, что мне нужно. Так я потеряю много полезного, сделанного между предыдущим коммитом и последним(необдуманным).

В общем, хочу сделать так, чтобы последнего коммита не было, но все мои файлы были такими, какие они есть сейчас.

Как удалить коммит git

2 ответа 2

Убрать последний коммит

console

Просто удаляем последний коммит из ветки, в которой находимся. Указатель ветки перейдет на предыдущий. Все изменения, внесённые в этом коммите, останутся в рабочей области проекта (т.е. в файлах на диске).

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

Как удалить коммит git

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

Последний коммит был сделан необдуманно (вспомнилось, что там есть пара проблем, которые не хотелось бы увековечивать)

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

Для этого тоже есть графический способ: специальная галочка в окне создания коммита:

Источник

artem78 / git_commands_help.md

Заметки по наиболее часто используемым командам GIT для себя и не только

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

Или в чём разница между git pull и git fetch? Если совсем коротко, то:

fetch всего лишь получает изменения с удалённого сервера никак не изменяя локальные ветки. pull вливает эти изменения в текущую ветку по возможности методом «быстрой перемотки» (fast forward).

Влить изменения из одной ветки в другую

Например, из feature в master:

И удалить более ненужную ветку feature (опционально):

Отменить игнорирование предыдущей коммандой:

Извлечение из stash-а

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

Извлечь из запрятанного, но без удаления:

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

Навести порядок в коммитах

Например, в последних пяти:

Также можно переупорядочивать коммиты.

Пример: объединим несколько коммитов в один:

Здесь команда pick оставляет первый коммит в качестве базового, а squash объединяет остальные с первым.

Удаление последних коммитов в ветке

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

Создание простой (легковесной) метки:

Создание аннотированной метки:

Просмотреть список всех тегов:

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

Отправить вместе с коммитами ещё и метки:

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

Примечание: Автоматически git отправляет только аннотированные метки, пропуская легковесные. Рекомендуется аннотированными метками отмечать релизы, а легковесные использовать только в локальном репозитории. (Подробности тут)

Сбросить изменения в определённом файле до коммита

Подтянуть последние изменения из ветки master в feature. Другими словами, нужно переместить feature на конец master:

Поиск «проблемных» коммитов при помощи команды bisect

Допустим, что возникла ситуация, когда после внесения некоторых изменений в проект, что-то сломалось и нужно найти этот «бракованный» коммит. Включаем bisect:

Затем указываем плохой и хороший коммиты:

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

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

В заключение, чтобы завершить работу команды bisect и вернуться к исходному состоянию вводим:

Переименовать локальную ветку

Перенос последнего коммита в другую ветку

Источник

How do I delete unpushed git commits?

I accidentally committed to the wrong branch. How do I delete that commit?

Как удалить коммит git

7 Answers 7

Trending sort

Trending sort is based off of the default sorting method — by highest score — but it boosts votes that have happened recently, helping to surface more up-to-date answers.

It falls back to sorting by highest score if no posts are trending.

Switch to Trending sort

Delete the most recent commit, keeping the work you’ve done:

Delete the most recent commit, destroying the work you’ve done:

Как удалить коммит git

I wonder why the best answer that I’ve found is only in the comments! (by Daenyth with 86 up votes)

This command will sync the local repository with the remote repository getting rid of every change you have made on your local. You can also do the following to fetch the exact branch that you have in the origin as Cleary suggested in the comments.

Как удалить коммит git

Don’t delete it: for just one commit git cherry-pick is enough.

Suppose you have this:

, then you can mark master and move it where you would want to be:

, reset y branch where it should have been:

, and finally move your commits (reapply them, making actually new commits)

Как удалить коммит git

If you want to move that commit to another branch, get the SHA of the commit in question

Then switch the current branch

And cherry-pick the commit to other-branch

Following command worked for me, all the local committed changes are dropped & local is reset to the same as remote origin/master branch.

In fact, if you don’t care about checking out, you can set the branch to whatever you want with:

This would be a programmatic way to remove commits from a branch, for instance, in order to copy new commits to it (using rebase).

Suppose you have a branch that is disconnected from master because you have taken sources from some other location and dumped it into the branch.

You now have a branch in which you have applied changes, let’s call it «topic».

You will now create a duplicate of your topic branch and then rebase it onto the source code dump that is sitting in branch «dump»:

Now your changes are reapplied in branch topic_duplicate based on the starting point of «dump» but only the commits that have happened since «master». So your changes since master are now reapplied on top of «dump» but the result ends up in «topic_duplicate».

You could then replace «dump» with «topic_duplicate» by doing:

Or just by discarding the dump

Perhaps you could also just cherry-pick after clearing the current «topic_duplicate».

Rebasing only works on a branch that already has the commits, so you need to duplicate your topic branch each time you want to do that.

Cherrypicking is much easier:

So the entire sequence will come down to:

When your topic-duplicate branch has been checked out. That would remove previously-cherry-picked commits from the current duplicate, and just re-apply all of the changes happening in «topic» on top of your current «dump» (different ancestor). It seems a reasonably convenient way to base your development on the «real» upstream master while using a different «downstream» master to check whether your local changes also still apply to that. Alternatively you could just generate a diff and then apply it outside of any Git source tree. But in this way you can keep an up-to-date modified (patched) version that is based on your distribution’s version while your actual development is against the real upstream master.

So just to demonstrate:

Hope this helps someone. I was meaning to rewrite this, but I cannot manage now. Regards.

Источник

Remove specific commit

I was working with a friend on a project, and he edited a bunch of files that shouldn’t have been edited. Somehow I merged his work into mine, either when I pulled it, or when I tried to just pick the specific files out that I wanted. I’ve been looking and playing for a long time, trying to figure out how to remove the commits that contain the edits to those files, it seems to be a toss up between revert and rebase, and there are no straightforward examples, and the docs assume I know more than I do.

So here is a simplified version of the question:

Given the following scenario, how do I remove commit 2?

The expected result is

Here is an example of how I have been trying to revert

Как удалить коммит git

15 Answers 15

Trending sort

Trending sort is based off of the default sorting method — by highest score — but it boosts votes that have happened recently, helping to surface more up-to-date answers.

It falls back to sorting by highest score if no posts are trending.

Switch to Trending sort

There are four ways of doing so:

Clean way, reverting but keep in log the revert:

Harsh way, remove altogether only the last commit:

Rebase (show the log of the last 5 commits and delete the lines you don’t want, or reorder, or squash multiple commits in one, or do anything else you want, this is a very versatile tool):

And if a mistake is made:

Quick rebase: remove only a specific commit using its id:

Alternatives: you could also try:

Yet another alternative:

As a last resort, if you need full freedom of history editing (eg, because git don’t allow you to edit what you want to), you can use this very fast open source application: reposurgeon.

Как удалить коммит git

2″. Now you have several options. In the vim you can see some commented lines: one of them tells you that you simply can delete a line (which should be the commit you want to get rid of) and this commit will be removed together with it’s log in your history.

5 worked for me. Then I just removed the commit(s) that I didn’t need and I was able to solve the problem in less than 30 seconds. Thank you.

Here is an easy solution:

(Note: x is the number of commits)

upon executing notepad file will open. Enter drop besides your commit.
If you don’t know Vim, just click on each word pick that you want to edit and then hit the «I» key (for insert mode). Once you’re done typing hit the «esc» key to exit insert mode.

Как удалить коммит git

and that’s it, you are done. Just sync the git dashboard and the changes will be pushed to remote.

Как удалить коммит git

4 includes the last 4 commits.

The algorithm that Git uses when calculating diffs to be reverted requires that

The definition of «adjacent» is based on the default number of lines from a context diff, which is 3. So if ‘myfile’ was constructed like this:

Then it all works as expected.

The second answer was very interesting. There is a feature that has not yet been officially released (though it is available in Git v1.7.2-rc2) called Revert Strategy. You can invoke git like this:

git revert —strategy resolve

and it should do a better job of figuring out what you meant. I do not know what the list of available strategies is, nor do I know the definition of any strategy.

Approach 1

First get the commit hash(ex:1406cd61) that you need to revert. simple fix will be below command,

if you have commit more changes related to 1406cd61 files after 1406cd61 commit, Above simple command will not work. Then you have to do the below steps, which is cherry picking.

Approach 2

Step 1: Find the commit before the commit you want to remove git log

Step 2: Checkout that commit git checkout

Step 4: Now you need to add the commit after the removed commit git cherry-pick

Step 5: Now repeat Step 4 for all other commits you want to keep.

Step 6: Once all commits have been added to your new branch and have been committed. Check that everything is in the correct state and working as intended. Double check everything has been committed: git status

Step 7: Switch to your broken branch git checkout

Step 9: Merge your fixed branch into this branch git merge

You can do the process without creating a new branch by replacing Step 2 & 3 with Step 8 then not carry out Step 7 & 9.

Как удалить коммит git

Your choice is between

You should choose (1) if the erroneous change has been picked up by anybody else and (2) if the error is limited to a private un-pushed branch.

Git revert is an automated tool to do (1), it creates a new commit undoing some previous commit. You’ll see the error and removal in the project history but people who pull from your repository won’t run into problems when they update. It’s not working in an automated manner in your example so you need to edit ‘myfile’ (to remove line 2), do git add myfile and git commit to deal with the conflict. You will then end up with four commits in your history, with commit 4 reverting commit 2.

At this point your text editor will open the interactive rebase view. For example

Как удалить коммит git

If the rebase wasn’t successful, delete the temporary branch and try another strategy. Otherwise continue with the following instructions.

If you’re pushing your topic branch to a remote, you may need to force push since the commit history has changed. If others are working on the same branch, give them a heads up.

Here is a bash script that you can paste in to create a test repository in the /tmp folder:

At this point, we have a file.txt with these contents:

At this point, HEAD is at the 5th commit, HEAD

4 would be the 1st commit (so HEAD

5 results with «fatal: Needed a single revision; invalid upstream HEAD

5″.) A text editor (see screenshot in @Dennis’ answer) will open with these contents:

So we get all commits since (but not including) our requested HEAD

4. Delete the line pick 448c212 3rd git commit and save the file; you’ll get this response from git rebase :

At this point open myrepo_git/ folder/file.txt in a text editor; you’ll see it has been modified:

Basically, git sees that when HEAD got to 2nd commit, there was content of aaaa + bbbb ; and then it has a patch of added cccc + dddd which it doesn’t know how to append to the existing content.

And if previously, we decided to keep the line cccc (the contents of the 3rd git commit that we removed), we would have had:

Well, this was the kind of reading I hoped I’d have found, to start grokking how git rebase works in terms of deleting commits/revisions; so hope it might help others too.

Источник

Шпаргалка по Git

Создание

Локальные изменения

Советую использовать эту команду

История коммитов

Ветки и теги

Обновление и публикация

Слияние и перемещение

Отмена

…и отменить все изменения после него

…и сохранить все изменения как незакоммиченые

…и сохранить неотслеживаемые локальные изменения

Лучшие практики

Добавляйте в коммит связанные изменения

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

Делайте коммиты часто

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

Не публикуйте коммиты с незаконченной работой

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

Тестируйте код перед коммитом

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

Пишите хорошие комментарии

Начните свое сообщение с краткого резюме своих изменений (ориентируйтесь на 50 символов). Отделите это сообщение от основного текста пустой строкой. В теле сообщения следует дать подробные ответы на следующие вопросы:

Используйте слова в настоящем времени («меняется», не «был изменен» или «изменения») чтобы при git merge сгенерированное сообщение выглядело хорошо.

Система контроля версий не хранилище бекапов

Хранение резервных копий файлов на удаленном сервере это только приятный побочный эффект использования системы контроля версий. Но вы не должны использовать Git только для этого. При работе с системой обратите особое внимание на семантику коммитов (смотри пункт 1) — вы не должны просто запихивать файлы в репозиторий.

Используйте ветки

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

Согласуйте рабочий процесс

Git позволяет выбрать из большого количества рабочих процессов: длинные ветки, тематические ветки, слияние или перемещение, gitflow… Что из этого выберите вы зависит от нескольких факторов: ваш проект, ваше общее направление развития, среда разработки и (возможно самое важное) ваши личные предпочтения и предпочтения вашей команды. Что бы вы не выбрали убедитесь, что все следуют процессу, который был согласован.

Источник

Как удалить опрелённый комит в git-е, без удаления последующих?

Как удалить коммит git

Вот хороший алгоритм решения таких проблем:
Как удалить коммит git

Сейчас и на будущее

Как удалить коммит git

Как удалить коммит git

Как удалить коммит git

на самом деле постановка вопроса «удалить коммит» для тех кто пользуется Гитом может резать ухо, потому что все программисты знают, что код можно рефакторить до бесконечности, поэтому команда

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

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

Источник

Delete commit on gitlab

Part of GitLab Collective

If I can’t delete it, can I edit?

When it was the HEAD, I tried:

I already tried to rebase it, but it still stays on the branch. Now I just removed it from the HEAD, but it is still there.

There is another command?

Как удалить коммит git

4 Answers 4

Trending sort

Trending sort is based off of the default sorting method — by highest score — but it boosts votes that have happened recently, helping to surface more up-to-date answers.

It falls back to sorting by highest score if no posts are trending.

Switch to Trending sort

1st command will rest your head to commitid and 2nd command will delete all commit after that commit id on master branch.

Как удалить коммит git

Как удалить коммит git

Supose you have the following scenario:

Where you want to remove d258546 i.e. «bad commit».

then your default editor will pop with something like this:

just remove the line with the commit you want to strip and save+exit the editor:

git will proceed to remove this commit from your history leaving something like this (mind the hash change in the commits descendant from the removed commit):

Please be extra careful and make sure that none coworker is already using the history containing the «bad commit» in their branches.

Alternative option:

We’ve had similar problem and it was not enough to only remove commit and force push to GitLab.
It was still available in GitLab interface using url:

We’ve had to remove project from GitLab and recreate it to get rid of this commit in GitLab UI.

I will assume that you want to edit all commits to remove some strings from them, like for example leaked credentials.

Really purging old commits from a Gitlab server is a tricky task, as mentioned in the Gitlab purge doc, because it involves deleting all internal refs from the server. This is possible with Gitlab versions above or equal to 11.6 (see said doc).

These are the main steps :

a word of warning

Beware that any local copy of the repo made before this will still contain the deleted commits. Also, users trying to pull from those old local copies will end up in a mess.

the detailed process

See more examples at git-filter-repo examples. Gitlab cleanup details are at Gitlab docs on repo cleanup. I made a sample repository to illustrate the process.

Источник

Как удалить коммит в удаленном репозитории?

1 неподходит, т.к. возвращает меня к комиту 3х месячной давности! Нужно удалить коммит, но чтобы все изменения в рабочей директории сохранились! Спасибо!

Как удалить коммит git

Как удалить коммит git

Как удалить коммит git

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

Как удалить коммит git

Как удалить коммит git

. и нет проблем синхронизации.

Как удалить коммит git

Как удалить коммит git

. и есть огромные проблемы с размером репозитория!

в него попала пара сотен МБт дерьмища

Как удалить коммит git

Как удалить коммит git

Как удалить коммит git

Как удалить коммит git

А как ещё ты предлагаешь удалять часть истории?

Как удалить коммит git

В сабжевом случае хорошо подходит это. В том и цимес же, что историю на remote удолять не надо )

Как удалить коммит git

+1, сам так делаю, когда накосячу 🙂

Как удалить коммит git

Не заметил как в него попала пара сотен МБт дерьмища

Кстати, ТС, а как это случилось? Убогий gitignore?

Как удалить коммит git

Каким образом это подходит, если при этом подходе до скончания времен при любом git clone будет тянутся

Как удалить коммит git

Во-первых, вопрос именно о том, как её удалить.

Во-вторых, почему не надо-то? Мастер не стоит, но пока это моя бранча — что хочу, то и ворочу.

Как удалить коммит git

пока это моя бранча — что хочу, то и ворочу.

Даже если твой бранч уже смержили в мастер?

Как удалить коммит git

Не так уж и много + clone не каждый день/неделя/месяц.

А так да, на это внимания не обратил

Как удалить коммит git

Вот здесь не понял. С чего ты взял, что это не общая ветка?

Как удалить коммит git

Как удалить коммит git

И за убожество вида revet ‘my shit commit’ в истории тоже надо линчевать

Линчевать много за что можно, но иногда выбора нет. К тому же, смотря на сколько

Как удалить коммит git

Из зол вида «сотни МБ хлама в БД до скончания веков» и «перезапись последнего запушенного коммита» — первая куда как больше.

Источник

Как привести в порядок историю ваших коммитов в Git

Публикуем перевод статьи, которую мы нашли на hackernoon.com. Ее автор, Thiago Miranda, пишет о том, как сделать работу с Git более удобной и эффективной.

Как удалить коммит git

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

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

1. Что такое история в Git?

Как удалить коммит git

Точный реестр всех коммитов, содержащих произведенные с файлами изменения. В нем вы можете отследить конкретные изменения и время их внесения или сравнить текущую версию с предыдущей. Где посмотреть историю? Введите через Git Bash команду:

Если у вас слишком много коммитов, вы можете переходить от одного комментария к другому с помощью клавиш со стрелками или клавиш Page Up / Page Down — как и в любом другом файле. Чтобы выйти, нажмите горячую клавишу (q).

2. О комментариях к коммитам

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

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

3. Всегда делайте коммиты

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

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

4. Исправьте последний комментарий к коммиту

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

Обратите внимание: если вы уже запушили коммит в удаленный репозиторий, эту команду лучше не использовать.

5. Объедините последние Х коммитов в один

Ситуация: отправив коммит к новой фиче, вы понимаете, что нужно еще одно небольшое изменение, вносите минимальные правки и снова коммитите… В итоге 5 коммитов об одном и том же. Бывало? Подобные коммиты выбиваются из общего вида вашей истории в Git, но при желании их несложно поправить, применив команду:

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

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

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

1 сотрет все коммиты из замерженной ветки. Чтобы узнать больше, посмотрите документацию.

6. Удалите последний коммит с изменениями

Будьте осторожны, так как этот способ сотрет все изменения без возможности откатить. Обычно он используется после экспериментов с кодом, если их результат не соответствует ожиданиям. Я рекомендую сперва попробовать в репозитории-песочнице.

Теперь ваш последний коммит удален, как и все соответствующие изменения в коде.

7. Очистите историю своих коммитов

Как удалить коммит git

Как только вы вошли в него, вы увидите список из 5 последних коммитов (HEAD

5) внутри терминала. Все коммиты отсортированы по дате, т. е. наверху будет самый новый (этот список открывается с помощью Vim — текстового редактора Git по умолчанию, позволяющего редактировать текстовые файлы внутри терминала). И здесь же краткая инструкция с несколькими полезными командами. В большинстве случаев вам понадобятся команды squash и reword.

Заменив команду pick командой squash, вы удалите этот коммит из лога, и все изменения в коде будут сгруппированы с последним коммитом, выделенным командой pick.

Если вы хотите откорректировать комментарий, можно заменить команду pick командой reword и переписать комментарий.

Теперь вы можете перейти к следующему окну, где нужно написать один комментарий для группы коммитов, которые вы собираетесь склеить с помощью squash. Чтобы продолжить, нажмите ESC и введите:

Двоеточие (:) необходимо, чтобы показать, что вы хотите передать команду, (w) — чтобы записать (сохранить) изменения, (q) — чтобы выйти, а (!) — чтобы выполнить команду.

Обратите внимание, что каждая группа коммитов получит ваш комментарий. Результат можно проверить в логе Git.

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

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

Vim получит команду закрыть файл без сохранения.

8. Управляйте индексацией

Обычно следует отправлять коммиты к одному файлу или к группе связанных файлов. Но как тогда оперативно вносить изменения при индексации?

Скажем, у вас есть 3 файла, и нужно закоммитить только 2 из них. В этом случае можно попробовать следующую команду:

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

И проверьте результат:

Добавьте все файлы из какого-либо расширения, например CSS:

Добавили все по ошибке? Тогда очистите индексацию, воспользовавшись командой:

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

Сначала выберите опцию, введя соответствующий номер, например (3), чтобы откатить свои действия.

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

Когда завершите, нажмите (Enter).

Добавление файлов происходит по той же схеме. С помощью опции (4) добавьте неотслеживаемый файл.

Чтобы выйти, введите (q) в меню опций.

9. Вывод

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

Источник

Извлечение максимальной пользы из Git

Как удалить коммит git

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

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

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

Восстановление удалённых коммитов

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

Как удалить коммит git Что если вы хотите восстановить удалённый коммит? Вот тут-то вам и пригодится Reflog

Вот один из таких способов сделать это:

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

Ваше сердце начинает колотиться, пот течёт ручьём — вы знаете, как это бывает.

Теперь возникает вопрос на миллион долларов: как вернуть эти, казалось бы, удалённые коммиты? К счастью, есть ответ: «Reflog».

Использование Reflog для восстановления потерянных стейтов

Вы можете считать Reflog «журналом» Git: это место, где Git протоколирует каждое движение указателя HEAD. Или другими словами: все наиболее интересные действия, такие как commit, merge, checkout, rebase, cherry-pick и другие. Это, конечно, делает его идеальным инструментом для тех неизбежных ситуаций, когда что-то идёт не так.

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

Как удалить коммит git Reflog в действии, с полным журналом всех коммитов, до и после ошибки

Вы также можете добиться того же результата несколько быстрее. Как группа дружелюбных и увлечённых разработчиков графического интерфейса Git «Tower», мы стремимся решить общие болевые точки, связанные с Git. Поэтому в нашем маленьком инструменте вы можете достичь тех же результатов, просто нажав [CMD] + [Z] — как если бы вы хотели исправить простую опечатку в вашем текстовом редакторе. На самом деле, эта же горячая клавиша доступна для целого ряда различных действий, например, когда вы ошибочно удалили ветку, допустили ошибку при операции слияния или закоммитили что-то в неправильной ветке.

Очистка истории коммитов

Во время работы над новой функциональностью «красота» вашей истории коммитов может не быть вашим главным приоритетом — и это понятно: есть много других забот. Но когда вы закончите работу и непосредственно перед тем, как объедините свой труд с веткой вашей команды, вероятно, будет хорошей идеей задержаться на мгновение, чтобы перевести дух.

Очистка коммитов перед их интеграцией в командную ветку очень важна, особенно когда мы хотим поддерживать здоровую кодовую базу. И инструмент Git «Interactive Rebase» — идеальный способ добиться этого.

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

Как удалить коммит git Выбор коммита для удаления из истории коммитов — например, если он содержит конфиденциальные данные

Чтобы исправить эту ошибку, мы инициируем сеанс Interactive Rebase, начиная с родительской ревизии ошибочного коммита:

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

Небольшое примечание: если вы пользуетесь графическим интерфейсом, таким как Tower, вы можете воспользоваться коротким путём: просто щёлкните правой кнопкой мыши на ненужном коммите и выберите опцию «Удалить. » из контекстного меню.

Как удалить коммит git Удаление коммита не повлияет на кодовую базу, но удалит его из истории.

Как уже упоминалось выше, Interactive Rebase может предложить гораздо больше вариантов использования! Если вы хотите узнать больше об Interactive Rebase и его возможностях, посмотрите бесплатную «Аптечку для Git»: коллекцию коротких, полезных и бесплатных видеороликов, посвящённых устранению ошибок в Git.

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

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

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

Гораздо лучше использовать структуру Git «Submodule» : это позволяет подключать сторонний код как Git репозиторий — внутри Git репозитория вашего реального проекта. Это означает, что все кодовые базы останутся аккуратно разделёнными.

Включить сторонний модуль/библиотеку так же просто, как выполнить следующую команду Git:

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

Субмодули, признаться, довольно сложная тема, когда дело доходит до работы с ними на практике. Если вы хотите узнать о них поподробнее, ознакомьтесь с главой «Субмодули» бесплатной онлайн-книги «Learn Version Control with Git».

Генерируем коммиты с точностью

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

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

Вот тогда добавление полного файла в следующий коммит уже не является лучшей стратегией.

Staging выбранных частей ваших изменённых файлов

В примере ниже вы можете увидеть, что на данный момент у нас есть два чанка (= части или области) изменений в нашем файле imprint.html :

Как удалить коммит git Staging выбранных частей ваших изменённых файлов

Предположим, что первый чанк принадлежит одной теме (возможно, мы находимся в процессе унификации и очистки всех заголовков страниц в нашем проекте). Также допустим, что второй чанк принадлежит другой, совершенно не связанной с ним теме.

Как удалить коммит git Точный выбор чанков, которые мы хотим поместить в следующий коммит

Теперь Git берёт нас за руку и проводит по каждому чанку изменений в этом файле. И для каждого из них он задаёт нам простой вопрос: «Осуществить Stage для этого чанка?».

Давайте введём [Y] («Да») для первого и [N] («Нет») для второго. Когда мы затем действительно сделаем коммит, только первый фрагмент изменений будет включён. Второй останется как незафиксированное локальное изменение в нашей рабочей копии для последующего, отдельного коммита.

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

Как удалить коммит git Staging и сброс чанков также возможен и в графическом интерфейсе

Повышение продуктивности работы с Git

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

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

НЛО прилетело и оставило здесь промокоды для читателей нашего блога:

Источник

Git Wizardry

1 Введение

В своей прошлой заметке я постарался осветить в общих чертах стиль работы с
распределенной системой контроля версий git и указать на отличия по сравнению с
классическими централизованными СКВ. Целью было прежде всего обобщение опыта
работы с системой без упоминания тонкостей синтаксиса отдельных команд.

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

2 Работа с локальным репозитарием

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

2.1 Базовые команды

Базовые команды — те, без которых невозможно обойтись в разработке.

2.1.1 git init — создание репозитария

Команда git init создает в директории пустой репозитарий в виде директория
.git, где и будет в дальнейшем храниться вся информация об истории коммитов,
тегах — ходе разработки проекта:

Другой способ создать репозитарий — команда git clone, но о ней чуть позже.

2.1.2 git add и git rm — индексация изменений

Следующее, что нужно знать — команда git add. Она позволяет внести в индекс — временное хранилище — изменения, которые затем войдут в коммит. Примеры
использования:

git add EDITEDFILE — индексация измененного файла, либо оповещение о
создании нового.

git add. — внести в индекс все изменения, включая новые файлы.

Из индекса и дерева одновременно проекта файл можно удалить командой git rm:

git rm FILE1 FILE2 — отдельные файлы

git rm Documentation/\*.txt — хороший пример удаления из документации к git,
удаляются сразу все файлы txt из папки.

Сбросить весь индекс или удалить из него изменения определенного файла можно
командой git reset:

git reset — сбросить нафиг весь индекс.

git reset — EDITEDFILE — удалить из индекса конкретный файл.

Команда git reset используется не только для сбрасывания индекса, поэтому дальше
ей будет уделено гораздо больше внимания.

2.1.3 git status — состояние проекта, измененные и не добавленные файлы, индексированные файлы

Команда git status, пожалуй, можно считать самой часто используемой наряду с
командами коммита и индексации. Она выводит информацию обо всех изменениях,
внесенных в дерево директорий проекта по сравнению с последним коммитом рабочей
ветки; отдельно выводятся внесенные в индекс и неиндексированные
файлы. Использовать ее крайне просто:

Кроме того, git status указывает файлы с неразрешенными конфликтами слияния и
файлы, игнорируемые git.

2.1.4 git commit — совершение коммита

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

Если индекс не пустой, то на его основе будет совершен коммит, после чего
пользователя попросят прокомментировать вносимые изменения вызовом команды
edit(например, в Ubuntu обычно вызывается простенький текстовый редактор nano, у
меня же — emacs). Сохраняемся, и вуала! Коммит готов.

Есть несколько ключей, упрощающих работу с git commit:

git commit FILENAME — внесет в индекс и создаст коммит на основе изменений
единственного файла.

2.1.5 git reset — возврат к определенному коммиту, откат изменений, «жесткий» или «мягкий»

Помимо работы с индексом (см. выше), git reset позволяет сбросить состояние
проекта до какого-либо коммита в истории. В git данное действие может быть двух
видов: «мягкого»(soft reset) и «жесткого» (hard reset).

«Мягкий» (с ключом «—soft») резет оставит нетронутыми ваши индекс и все дерево
файлов и директорий проекта, вернется к работе с указанным коммитом. Иными
словами, если вы обнаруживаете ошибку в только что совершенном коммите или
комментарии к нему, то легко можно исправить ситуацию:

Обратите внимание на обозначение HEAD^, оно означает «обратиться к предку
последнего коммита». Подробней описан синтаксис такой относительной адресации
будет ниже, в разделе «Хэши, тэги, относительная адресация». Соответственно,
HEAD — ссылка на последний коммит. Ссылка ORIG_HEAD после «мягкого» резета
указывает на оригинальный коммит.

Естественно, можно вернуться и на большую глубину коммитов,

1 — больше никто и никогда не увидит этот позорный коммит.

3 — вернее, три последних коммита. Никто. Никогда.

Если команда достигнет точки ветвления, удаления коммита не произойдет.

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

2.1.6 git revert — отмена изменений, произведенных в прошлом отдельным коммитом

Возможна ситуация, в которой требуется отменить изменения, внесенные отдельным
коммитом. Git revert создает новый коммит, накладывающий обратные изменения:

git revert config-modify-tag — отменяем коммит, помеченный тегом.

git revert 12abacd — отменяем коммит, используя его хэш.

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

2.1.7 git log — разнообразная информация о коммитах в целом, по отдельным файлам и различной глубины погружения в историю

Иногда требуется получить информацию об истории коммитов, коммитах, изменивших
отдельный файл; коммитах за определенный отрезок времени и так далее. Для этих
целей используется команда git log.

Простейший пример использования, в котором приводится короткая справка по всем
коммитам, коснувшимся активной в настоящий момент ветки (о ветках и ветвлении
подробно узнать можно ниже, в разделе «Ветвления и слияния»):

За информацию по созданиям, переименованиям и правам доступа файлов отвечает ключ
—summary:

Для исследования истории отдельного файла достаточно указать в виде параметра
его имя (кстати, в моей старой версии git этот способ не срабатывает,
обязательно добавлять » — » перед «README»):

или, если версия git не совсем свежая:

git log — README

Далее будет приводится только более современный вариант синтаксиса. Возможно
указывать время, начиная в определенного момента («weeks», «days», «hours», «s»
и так далее):

Можно отталкиваться от тегов:

git log v1… — все коммиты, начиная с тега v1.

git log v1… README — все коммиты, включающие изменения файла README, начиная с
тега v1.

git log v1..v2 README — все коммиты, включающие изменения файла README, начиная с
тега v1 и заканчивая тегом v2.

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

В принципе, формат вывода можно определить самостоятельно:

Определение формата можно поискать в разделе по git log из Git Community Book
или справке. Красивый ASCII-граф коммитов выводится с использованием ключа
—graph.

2.1.8 git diff — отличия между деревьями проекта; коммитами; состоянием индекса и каким-либо коммитом.

Своего рода подмножеством команды git log можно считать команду git diff,
определяющую изменения между объектами в проекте: деревьями (файлов и
директорий):

git diff — покажет изменения, не внесенные в индекс.

git diff HEAD — изменения в проекте по сравнению с последним коммитом

git diff HEAD^ — предпоследним коммитом

Можно сравнивать «головы» веток:

git diff master..experimental

Ну или активную ветку с какой-либо:

git diff experimental

2.1.9 git show — показать изменения, внесенные отдельным коммитом

Посмотреть изменения, внесенные любым коммитом в истории можно командой git
show:

git show COMMIT_TAG

2.1.10 git blame и git annotate — вспомогательные команды, помогающие отслеживать изменения файлов

При работе в команде часто требуется выяснить, кто именно написал конкретный
код. Удобно использовать команду git blame, выводящую построчную информацию о
последнем коммите, коснувшемся строки, имя автора и хэш коммита:

git blame README

Можно указать и конкретные строки для отображения:

Аналогично работает команда git annotate, выводящая и строки, и информацию о
коммитах, их коснувшихся:

git annotate README

2.1.11 git grep — поиск слов по проекту, состоянию проекта в прошлом

git grep, в целом, просто дублирует функционал знаменитой юниксовой
команды. Однако, он позволяет слова и их сочетания искать в прошлом проекта, что
бывает очень полезно:

git grep tst — поиск слова tst в проекте.

git grep tst v1 — поиск в старой версии проекта.

Команда позволяет использовать логическое И и ИЛИ:

2.2 Ветвление

Операции ветвления и слияния — сердце и душа git, именно эти возможности делают такой
удобной работу с системой.

2.2.1 git branch — создание, перечисление и удаление веток

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

git branch — просто перечислит существующие ветки, отметив активную.

git branch new-branch — создаст новую ветку new-branch.

2.2.2 git checkout — переключение между ветками, извлечение отдельных файлов из истории коммитов

Команда git checkout позволяет переключаться между последними коммитами (если
упрощенно) веток:

Вернуть файл (или просто вытащить из прошлого коммита) позволяет команда вида:

git checkout somefile — вернуть somefile к состоянию последнего коммита
git checkout HEAD

2 somefile — вернуть somefile к состоянию на два коммита назад по ветке.

2.2.3 git merge — слияние веток (разрешение возможных конфликтов).

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

git merge new-feature — попробует объединить текующую ветку и ветку new-feature.

В случае возникновения конфликтов коммита не происходит, а по проблемным файлам
расставляются специальные метки а ля svn; сами же файлы отмечаются в индексе как
«не соединенные» (unmerged). До тех пор пока проблемы не будут решены, коммит совершить
будет нельзя.

Например, конфликт возник в файле TROUBLE, что можно увидеть в git status:

git merge experiment — произошла неудачная попытка слияния.

git status — смотрим на проблемные места.

edit TROUBLE — разрешаем проблемы.

git add. — индексируем наши изменения, тем самым снимая метки.

git commit — совершаем коммит слияния.

Вот и все, ничего сложного. Если в процессе разрешения вы передумали разрешать
конфликт, достаточно набрать:

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

2.2.4 git rebase — построение ровной линии коммитов

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

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

Предположим, имеется две ветки, master и топик, в каждой из которых было совершенно несколько коммитов начиная с момента ветвления.
Команда git rebase берет коммиты из ветки topic и накладывает их на последний коммит ветки
master:

2.2.5 git cherry-pick — применение к дереву проекта изменений, внесенных отдельным коммитом

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

git cherry-pick BUG_FIX_TAG — изменения, внесенные указанным коммитом будут
применены к дереву, автоматически проиндексированы и станут коммитом в активной
ветке.

2.3 Прочие команды и необходимые возможности

Для удобства работы с git было введено дополнительное понятие: тэг. Кроме того
дальше будет пояснена необходимость в хэшах, и его применение; показан способ
обращаться к коммитам при помощи относительной адресации.

2.3.1 Хэш — уникальная идентификация объектов

В git для идентификации любых объектов используется уникальный (то есть с
огромной вероятностью уникальный) хэш из 40 символов, который определяется
хэшируюшей функцией на основе содержимого объекта. Объекты — это все: коммиты,
файлы, тэги, деревья. Поскольку хэш уникален для содержимого, например, файла,
то и сравнивать такие файлы очень легко — достаточно просто сравнить две строки
в сорок символов.

Больше всего нас интересует тот факт, что хэши идентифицируют коммиты. В этом
смысле хэш — продвинутый аналог ревизий Subversion. Несколько примеров
использования хэшей в качестве способа адресации:

git diff f292ef5d2b2f6312bc45ae49c2dc14588eef8da2 — найти разницу текущего
состояния проекта и коммита за номером… Ну сами видите, каким.

git diff f292ef5 — то же самое, но оставляем только шесть первых символов. Git
поймет, о каком коммите идет речь, если не существует другого коммита с таким
началом хэша.

git diff f292 — иногда хватает и четырех символов.

git log febc32. f292 — читаем лог с коммита по коммит.

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

2.3.2 git tag — тэги как способ пометить уникальный коммит

Тэг (tag) — это объект, связанный с коммитом; хранящий ссылку на сам коммит, имя
автора, собственное имя и некоторый комментарий. Кроме того, разработчик может
оставлять на таких тегах собственную цифровую подпись.

Кроме этого в git представленные так называемые «легковесные тэги» («lightweight
tags»), состоящие только из имени и ссылки на коммит. Такие тэги, как правило,
используются для упрощения навигации по дереву истории; создать их очень легко:

git tag stable-1 — создать «легковесный» тэг, связанный с последним
коммитом. Если тэг уже есть, то еще один создан не будет.

git tag stable-2 f292ef5 — пометить определенный коммит.

После создания тэга его имя можно использовать вместо хэша в любых командах
вроде git diff, git log и так далее:

git diff stable-1.1. stable-1

Обычные тэги имеет смысл использовать для приложения к коммиту какой-либо
информации, вроде номера версии и комментария к нему. Иными словами, если в
комментарии к коммиту пишешь «исправил такой-то баг», то в комментарии к тэгу по
имени «v1.0» будет что-то вроде «стабильная версия, готовая к использованию»:

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

2.3.3 Относительная адресация

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

git diff master^

Если после «птички» поставить цифру, то можно адресоваться по нескольким предкам
коммитов слияния:

git diff HEAD^2 — найти изменения по сравнению со вторым предком последнего
коммита в master. HEAD здесь — указатель на последний коммит активной ветки.

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

git diff master^^ — что привнес «дедушка» нынешнего коммита.

git diff master

Обозначения можно объединять, чтобы добраться до нужного коммита:

git diff master

git diff master

Иногда по директориям проекта встречаются файлы, которые не хочется постоянно
видеть в сводке git status. Например, вспомогательные файлы текстовых
редакторов, временные файлы и прочий мусор.

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

Пример содержимого такого файла:

#не нужны объектники и архивы

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

3 «Вместе мы — сила», или основы работы с удаленным репозитарием

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

3.1 Удаленные ветки (remote tracking branches)

Новое понятие здесь — удаленные ветки. Удаленные ветки соответствуют какой-либо
ветке (чаще master) на удаленном сервере. Одна такая создается автоматически при
создании копии удаленного репозитария; все команды, связанные с удаленной
работой, будут по умолчанию использовать именно эту удаленную ветку (обычно
называется «origin»).

Рассмотрим эти команды.

3.2 git clone — создание копии (удаленного) репозитария

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

git clone /home/username/project myrepo — клонируем репозитарий с той же машины
в директорию myrepo.

git clone ssh://user@somehost:port/

user/repository — клонируем репозитарий,
используя безопасный протокол ssh (для чего требуется завести у себя на машине
эккаунт ssh).

git clone git://user@somehost:port/

user/repository/project.git/ — у git имеется
и собственный протокол.

3.3 git fetch и git pull — забираем изменения из центрального репозитария (из удаленной ветки)

Для синхронизации текущей ветки с репозитарием используются команды git fetch и
git pull.

git fetch — забрать изменения удаленной ветки из репозитария по умолчания,
основной ветки; той, которая была использована при клонировании
репозитария. Изменения обновят удаленную ветку (remote tracking branch), после
чего надо будет провести слияние с локальной ветку командой git merge.

git fetch /home/username/project — забрать изменения из определенного
репозитария.

Возможно также использовать синонимы для адресов, создаваемые командой git remote:

git remote add username-project /home/username/project

git fetch username-project — забрать изменения по адресу, определяемому
синонимом.

Естественно, что после оценки изменений, например, командой git diff, из надо
создать коммит слияния с основной:

git merge username-project/master

Команда git pull сразу забирает изменения и проводит слияние с активной веткой:

git pull — забрать из репозитария, для которого были созданы удаленные ветки по
умолчанию.

git pull username-project — забрать изменения из определенного репозитария.

Как правило, используется сразу команда git pull.

3.4 git push — вносим изменения в удаленный репозитарий (удаленную ветку)

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

git push — отправить свои изменения в удаленную ветку, созданную при
клонировании по умолчанию.

git push ssh://yourserver.com/

you/proj.git master:experimental — отправить изменения
из ветки master в ветку experimental удаленного репозитария.

git push origin :experimental — в удаленном репозитарии origin удалить ветку experimental.

git push origin master:master — в удаленную ветку master репозитария origin (синоним
репозитария по умолчанию) ветки локальной ветки master.

4 git-о-день

В этом разделе будут показаны и разобраны подробно несколько обычных и чуть
меньше необычных для работы с git ситуаций.

4.1 Обычный workflow при работе с локальным репозитарием

Git обладает необычайной легкостью в использовании не только как распределенная
система контроля версий, но и в работе с локальными проектами. Давайте разберем
обычный цикл — начиная с создания репозитария — работы разработчика git над
собственным персональным проектом:

Почему именно так? Зачем отказываться от линейной модели? Хотя бы даже потому,
что у программиста появляется дополнительная гибкость: он может переключаться
между задачами (ветками); под рукой всегда остается «чистовик» — ветка
master; коммиты становятся мельче и точнее.

4.2 Workflow при работе с удаленным репозитарием

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

you/proj.git
… возможно, прошло некоторое время.

Итак, первым делом создаем (1) создаем копию удаленного репозитария (по
умолчанию команды вроде git pull и git push будут работать с ним). «Вытягиваем»
последние обновления (2); смотрим, что же изменилось(3); создаем новую ветвь и
переключаемся в нее (4); индексируем все изменения и одновременно создаем из них
коммит (5); переключаемся в главную ветвь (6), обновляем ее (7); проводим
слияние с веткой bad-feature(8) и, обнаружив и разрешив конфликт, делаем коммит
слияния (9).

После совершения коммита отслеживаем изменения(10), запускаем, например,
юнит-тесты и с ужасом обнаруживаем, что после слияния проект валится на большей
части тестов.

В принципе, тесты можно было прогнать и до коммита, в момент
слияния (между пунктами 8 и 9); тогда бы хватило «мягкого» резета.

Таким образом, приходится совершить «жесткий» (11) сброс произошедшего слияния,
ветки вернулись в исходное до состояние. После чего переключаемся в неудачную
ветку (12), вносим необходимые изменения и переименовываем ветку (13). Совершаем
коммит (14); переходим в главную ветку(15), опять ее обновляем (16). На этот раз
бесконфликтно делаем слияние (17), закидываем изменения в удаленный репозитарий
(18) и удаляем ненужную теперь ветку (19). Закрываем ноутбук, одеваемся и идем
домой под утро.

5 Заключение

В топике не рассмотрено несколько важных вопросов, вроде администрирования
общественного репозитария, интеграции с текстовыми редакторами или IDE,
использования SSH под Линукс и Windows; приветствуются замечания, и особенно
дополнения в раздел «git-о-день».

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

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

Источник

Как удалить коммит git

Обучающие материалы по GitHub:

Хорошо подобранное введение в основные команды git

1: Знакомство с Git Commit

Коммит в git репозитории хранит снимок всех файлов в директории. Почти как огромная копия, только лучше

Git пытается быть лёгким и быстрым насколько это только возможно, так что он не просто слепо копирует всю директорию каждый раз, а ужимает (когда это возможно) коммит в набор изменений или «дельту» между текущей версией и предыдущей.

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

Посмотрим, как это выглядит на практике. Справа расположена визуализация небольшого git репозитория. Сейчас в нём два коммита: первый, исходный коммит С0 и один коммит С1 после него, содержащий изменения.

Нажми на кнопку, чтобы совершить коммит

Отлично. Мы только что внесли изменения в репозиторий и сохранили их как коммит. У коммита, который мы только что сделали, есть родитель, С1, который указывает на предыдущий коммит.

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

2: Ветвление в Git

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

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

Посмотрим, что такое ветки на практике

Создадим здесь новую ветку с именем newImage.

Вот и всё, ребята! Ветка newImage теперь указывает на коммит C1.

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

Сообщим Git, что хотим выбрать ветку git checkout [name] Эта команда перенесёт нас на новую ветку в момент, когда мы ещё не коммитили изменения

Вот так! Наши изменения записаны уже в новую ветку

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

3: Слияния веток в Git

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

Слишком запутанно =) На схеме всё проще и понятнее.

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

Мы сделаем merge ветки bugFix в ветку main.

Что мы видим? Во-первых, ветка main теперь указывает на коммит, у которого два родителя. Если проследовать по стрелкам от этого коммита, вы пройдёте через каждый коммит в дереве прямиком к началу. Это означает, что теперь в ветке main содержатся все изменения репозитория.

Смерджим ветку main в ветку bugFix.

Так как ветка bugFix была предшественницей main, Git не делал ничего, только сдвинул bugFix на тот же коммит, где находится main

Теперь все коммиты одного цвета, что означает, что каждая ветка содержит все изменения репозитория! Поздравляем!

Чтобы пройти этот уровень, сделай следующее:

Создай новую ветку под названием bugFix

Переключись на новую ветку bugFix командой git checkout bugFix

Сделай один коммит

Вернись на ветку main при помощи git checkout

Сделай ещё один коммит

Слей ветку bugFix с веткой main при помощи git merge

4: Введение в rebase

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

Посмотрим, как это работает..

У нас здесь снова две ветки. Обрати внимание, что выбрана ветка bugFix (отмечена звёздочкой)

Применим git rebase.

Супер! Теперь изменения из bugFix находятся в конце ветки main и являют собой линейную последовательность коммитов.

Вуаля! Так как main был предком bugFix, git просто сдвинул ссылку на main вперёд.

Чтобы пройти этот уровень, сделай следующее:

Переключись на ветку bugFix Сделай коммит Вернись на main и сделай коммит ещё раз Переключись на bugFix и сделай rebase на main Удачи!

Следующая порция абсолютной git-крутотенюшки. Проголодались?

1: Теряем голову, или detached HEAD

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

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

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

Обычно HEAD указывает на имя ветки (например, bugFix). Когда вы делаете коммит, статус ветки bugFix меняется и это изменение видно через HEAD.

Посмотрим, как это работает. Обратите внимание на то, где находится HEAD до и после коммита.

Вот! HEAD всё это время скрывался за веткой main

Detaching HEAD Отделение (detaching) HEAD означает лишь присвоение его не ветке, а конкретному коммиту. Посмотрим, что было до отделения:

А вот что получилось теперь

Чтобы пройти уровень, давай отделим HEAD от ветки bugFix и присвоим его последнему коммиту в этой же ветке.

Укажи коммит при помощи его идентификатора (hash). Hash для каждого коммита указан в кружке на схеме.

2: Относительные ссылки (^)

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

Хорошая новость в том, что Git достаточно умён в работе с хешами. Ему нужны лишь первые несколько символов для того, чтобы идентифицировать конкретный коммит. Так что можно написать просто fed2 вместо колбасы выше.

С относительными ссылками можно начать с какого-либо удобного места (например, с ветки bugFix или от HEAD) и двигаться от него

Перемещение на один коммит назад ^ Перемещение на несколько коммитов назад

Для начала рассмотрим оператор каретки (^). Когда мы добавляем его к имени ссылки, Git воспринимает это как указание найти родителя указанного коммита.

Так что main^ означает «первый родитель ветки main».

main^^ означает прародитель (родитель родителя) main

Давайте переключимся на коммит Выше main

Опачки! Готово. Сильно проще, чем поиск и указание хеша.

Можно также использовать HEAD как относительную ссылку. Попробуем пройти несколько раз назад по дереву коммитов

Изи! Мы можем путешествовать во времени при помощи HEAD^

Чтобы пройти этот уровень, переместись на первого родителя ветки bugFix. Это отделит HEAD от ветки.

Конечно, можно указать хеш, но надо попробовать использовать относительные ссылки!

3: Относительные ссылки №2

— тильда. Предположим, нужно переместиться на много шагов назад по дереву. Было бы неудобно печатать ^ несколько раз (или несколько десятков раз), так что Git поддерживает также оператор тильда (

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

число коммитов, через которые надо пройти.

Оп! Очевидно, относительные ссылки прекрасны.

Перемещение ветки (branch forcing) Теперь мы разбираемся в относительных ссылках, так что можно реально использовать их для дела.

Переместит (принудительно) ветку main на три родителя назад от HEAD.

Вуаля! Относительная ссылка дала нам возможность просто сослаться на C1, а branch forcing (-f) позволил быстро переместить указатель ветки на этот коммит.

Мы рассмотрели относительные ссылки и branch forcing вкупе, так что теперь пришло время пройти следующий уровень.

Чтобы пройти этот уровень, передвинь HEAD, main и bugFix так, как показано на визуализации.

4: Отмена изменений в Git

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

git reset отменяет изменения, перенося ссылку на ветку назад, на более старый коммит. Это своего рода «переписывание истории»; git reset перенесёт ветку назад, как будто некоторых коммитов вовсе и не было.

Посмотрим, как это работает:

Неплохо! Git просто перенёс ссылку на main обратно на коммит C1. Теперь наш локальный репозиторий в состоянии, как будто C2 никогда не существовал.

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

Чтобы отменить изменения и поделиться отменёнными изменениями с остальными, надо использовать git revert. Посмотрим, как это работает

Забавно, появился новый коммит. Дело в том, что новый коммит C2′ просто содержит изменения, полностью противоположные тем, что сделаны в коммите C2.

После revert можно сделать push и поделиться изменениями с остальными.

Чтобы пройти этот уровень, отмени два последних коммита и в local, и в pushed

Перемещаем труды туда-сюда

Не стесняйтесь менять историю

1: Введение в Cherry-pick

Итак, мы уже освоили основы Git: коммиты, ветки, перемещение по дереву изменений. Уже этих знаний достаточно, чтобы овладеть 90% мощью Git-репозиториев и покрыть нужды разработчиков.

А оставшиеся 10% будут очень полезны при сложных workflow (или если ты попал в сложную ситуацию). Теперь речь пойдёт о перемещении изменений — возможности, позволяющей разработчику сказать «Хочу, чтобы эти изменения были вот тут, а вот эти — вон там» и получить точные, правильные результаты, не теряя при этом гибкости разработки.

На первый взгляд запутанно, но на самом деле всё просто.

Это очень простой и прямолинейный способ сказать, что ты хочешь копировать несколько коммитов на место, где сейчас находишься (HEAD). Мы обожаем cherry-pick за то, что в нём очень мало магии и его очень просто понять и применять.

Посмотрим на демонстрацию.

Вот репозиторий, где есть некие изменения в ветке side, которые мы хотим применить и в ветку main. Мы можем сделать это при помощи команды rebase, которую мы уже прошли, но давай посмотрим, как cherry-pick справится с этой задачей.

Вуаля! Мы хотели перенести коммиты C2 и C4, Git дал нам их там, где они нужны. Всё просто!

Чтобы пройти этот уровень, просто скопируй изменения из этих трёх веток в мастер. Чтобы понять, какие коммиты копировать, посмотри на визуализацию уровня.

2: Введение в интерактивный Rebase

Git cherry-pick прекрасен, когда точно известно, какие коммиты нужны (и известны их точные хеши)

Углубимся в детали.

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

Для «реального» Git, этот интерфейс означает просто открытие файла в редакторе типа vim. Для этой обучалки, я сделал небольшое диалоговое окно, которое по сути делает то же, что и редактор.

После открытия окна интерактивного rebase есть три варианта для каждого коммита:

Ну что ж, посмотрим на примеры!

После нажатия на эту кнопку появится окно интерактивного rebase. Переставь несколько коммитов (или удали кое-какие) и посмотри, что получится в итоге!

Rebasing 4 Commits

(Drag and drop to re-order. Toggle the «Omit/Pick» button to omit or re-add a commit)

Бах! Git скопировал коммиты в точности так, как было указано через интерфейс!

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

Ассорти из приёмов работы с Git, хитростей и советов

1: Выберем один коммит.

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

Каждая отладочная команда (команды) вывода находится в своём коммите. В итоге мы нашли ошибку, исправили её и порадовались!

Но проблема в том, что мы хотим добавить в main только исправление ошибки из ветки bugFix. Если мы воспользуемся простым fast-forward, то в main попадут также отладочные команды. Должен быть другой способ.

Надо заставить git копировать только один из коммитов. Это почти как в предыдущем уровне – мы можем использовать уже известные нам команды:

Чтобы достичь желаемого результата.

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

2: Жонглируем коммитами

Вот ещё одна ситуация, которая часто случается. Есть некоторые изменения (newImage) и другие изменения (caption), которые связаны так, что находятся друг поверх друга в репозитории.

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

Преодолеть эти трудности можно следующим образом:

Это задание можно выполнить несколькими способами (и, гляжу, ты посматриваешь на cherry-picking), но сейчас сосредоточься на вышеописанном методе.

Важно, чтобы совпадало не только дерево коммитов, но и количество апострофов.

3: Жонглируем коммитами №2

Перед прохождением этого уровня обязательно надо пройти предыдущий уровень – ‘Жонглируем коммитами №1’

Важно помнить, что cherry-pick поместит любой коммит сразу после HEAD (только если этот коммит не является предком HEAD)

Вот небольшое демо для напоминания:

Важно, чтобы совпадало не только дерево коммитов, но и количество апострофов.

В прошлых уроках мы усвоили, что ветки просто двигать туда-сюда и они часто ссылаются на разные коммиты как на изменения данных в ветке. Ветки просто изменить, они часто временны и постоянно меняют своё состояние.

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

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

Важно, что после создания они никогда не сменят своего положения, так что можно с лёгкостью сделать checkout конкретного момента в истории изменений

Посмотрим на это на практике.

Создадим тег на C1, который будет нашей версией 1

Готово! Всё просто. Мы назвали тег v1 и заставили его ссылаться на C1 явным образом. Если конкретный коммит не указан, гит пометит тегом HEAD.

Чтобы пройти этот уровень, просто создай теги так, как показано на визуализации, и потом перейди на тег v1. Обрати внимание, что ты перейдёшь в состояние detached HEAD, так как нельзя сделать коммит прямо в тег v1.

В следующем уровне мы попробуем более интересные способы применения тегов.

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

Git describe помогает сориентироваться после отката на много коммитов по истории изменений. Такое может случиться, когда вы сделали git bisect или если вы недавно вернулись из отпуска =)

Git describe выглядит примерно так:

Где ref — это что-либо, что указывает на конкретный коммит. Если не указать ref, то git будет считать, что указано текущее положение (HEAD).

Вывод команды выглядит примерно так:

Где tag – это ближайший тег в истории изменений, numCommits – это на сколько далеко мы от этого тега, а hash – это хеш коммита, который описывается.

Посмотрим на простой пример. Для дерева, показанного ниже:

Команда git describe main выведет:

Тогда как git describe side выведет:

Это, в общем-то, всё, что можно сказать про git describe. Попробуй выполнить команду на нескольких коммитах.

Как только наиграешься, просто сделай один коммит, и уровень будет пройден.

Если ты смелый, ловкий, умелый – потренируйся тут

1: Rebase over 9000 раз

У нас тут куча веток! Было бы круто перенести все изменения из них в мастер.

Но начальство усложняет нашу задачу тем, что желает видеть все коммиты по порядку. Так что коммит С7′ должен идти после коммита С6′ и так далее.

Если что-то пойдёт не так – не надо стесняться использовать reset, чтобы начать всё с чистого листа. Постарайся сделать как можно меньше манипуляций!

2: Здоровая семья, или несколько родителей

Так же как тильда (

), каретка (^) принимает номер после себя.

Но в отличие от количества коммитов, на которые нужно откатиться назад (как делает

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

Git по умолчанию перейдёт на «первого» родителя коммита, но указание номера после ^ изменяет это поведение.

Посмотрим, как это работает.

Вот мерджевый коммит. Если мы перейдём на main^ без номера, то попадём на первого родителя.

(На нашей визуализации первый родитель находится прямо над коммитом)

Теперь попробуем перейти на второго родителя.

Вот. Мы на втором родительском коммите.

сильно помогают перемещаться по дереву коммитов:

Быстро как Флэш!

Более того, эти модификаторы можно применять вместе. Например, так:

Сделаем то же самое, что перед этим, только в одну команду.

Чтобы пройти этот уровень, создай ветку в указанном месте.

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

3: Спутанные ветки

УОУ! В этом уровне придётся попотеть!

У нас тут по несколько коммитов в ветках one, two и three. Не важно почему, но нам надо видоизменить эти три ветки при помощи более поздних коммитов из ветки main.

Ветка one нуждается в изменении порядка и удалении C5. two требует полного перемешивания, а three хочет получить только один коммит

Как пройти этот уровень – решать тебе, а как найдёшь решение – сравни его с нашим при помощи show solution.

Настало время поделиться своими единичками и нулями. Время коллективного программирования

1: Введение в клонирование

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

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

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

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

Набирает популярность использование web-сайтов для визуализации активности удалённых репозиториев (например, GitHub), однако удалённые репозитории всегда выступают в качестве базы для таких инструментов. Поэтому так важно понимать, как устроены удалённые репозитории!

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

Давайте начнём постепенное изучение и взглянем на то, что собой представляет удалённый репозиторий (в нашем представлении).

Чтобы завершить уровень, просто выполните git clone на своём существующем репозитории. Настоящее обучение появится в последующих уроках.

2: Удалённые ветки

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

Во-первых, вы должны были заметить, что у нас в локальном репозитории появилась новая ветка с именем o/main. Такой тип ветки называется удалённой веткой. Поскольку удалённые ветки играют важную и уникальную роль, они обладают рядом специальных свойств.

Важным свойством удалённых веток является тот факт, что когда вы извлекаете их, вы отделяете (detaching) HEAD. Git делает это потому, что вы не можете работать непосредственно в этих ветках; сперва вам необходимо сделать наработки где-либо, а уж затем делиться ими с удалёнными репозиториями (после чего ваши удалённые ветки будут обновлены).

Большинство разработчиков именуют свои главные удалённые репозитории не как o, а как origin. Также общепринятым является именование удалённого репозитория как origin, когда вы клонируете репозиторий командой git clone.

К сожалению, полное имя origin не помещается на элементах дизайна наших уроков, поэтому мы используем краткое o 🙁 Просто помните, когда вы пользуетесь git в реальном проекте, ваш удалённый репозиторий скорее всего будет называться origin!

Давайте посмотрим на всё это в действии.

Давайте извлечём (check out) удалённую ветку и посмотрим что произойдёт

Как вы можете видеть, git отделил (detached) HEAD и не обновил o/main, когда мы добавили новый коммит. Всё потому, что o/main обновится тогда и только тогда, когда обновится сам удалённый репозиторий.

Для завершения уровня выполните коммит единожды на main, а затем на o/main (предварительно переключившись на эту ветку). Это наглядно продемонстрирует поведение удалённых веток, а также покажет, как изменения влияют на состояние удалённых репозиториев.

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

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

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

Вот и всё! Коммиты C2 и C3 были успешно скачаны в наш локальный репозиторий, и наша удалённая ветка o/main отобразила эти изменения соответствующим образом.

Что делает fetch? git fetch выполняет две и только две основные операции. А именно:

связывается с указанным удалённым репозиторием и забирает все те данные проекта, которых у вас ещё нет, при этом. у вас должны появиться ссылки на все ветки из этого удалённого репозитория (например, o/main) Фактически, git fetch синхронизирует локальное представление удалённых репозиториев с тем, что является актуальным на текущий момент времени.

Насколько вы помните, в предыдущем уроке мы сказали, что удалённые ветки отображают состояние удалённых репозиториев на тот момент когда вы ‘общались’ с ними в последний раз. git fetch является тем механизмом, который даёт вам возможность общаться с удалёнными репозиториями! Надеюсь, что связь между удалёнными ветками и командой git fetch теперь прояснилась.

git fetch обычно ‘общается’ с удалёнными репозиториями посредством Интернета (через такие протоколы, как http:// или git://).

Чего fetch не делает? Важно отметить, что команда git fetch забирает данные в ваш локальный репозиторий, но не сливает их с какими-либо вашими наработками и не модифицирует то, над чем вы работаете в данный момент.

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

Одним словом, вы можете относиться к git fetch как к процедуре скачивания.

Чтобы выполнить уровень, просто запустите git fetch и скачайте все коммиты!

Теперь, когда мы познакомились с тем, как извлекать данные из удалённого репозитория с помощью git fetch, давайте обновим нашу работу, чтобы отобразить все эти изменения!

Давайте рассмотрим, как fetch и merge выполняются последовательно

Что же произойдёт, если вместо этих команд мы воспользуемся git pull?

Абсолютно то же самое! Нужно чётко понимать, что git pull существенно уменьшает вашу рутинную работу, если бы вы использовали git fetch и последующее слияние (merging) скаченной ветки.

Мы изучим детали команды git pull чуть позже (включая опции и аргументы вызова команды), а пока что давайте просто попробуем эту команду.

5: Коллективная работа

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

Для того, чтобы добиться своих целей, нам предоставляется команда со звучным именем git fakeTeamwork! Имя команды однозначно даёт понять, что она выполняет. Давайте ознакомимся с демо.

Поведение команды fakeTeamwork по умолчанию заключается в том, чтобы просто «инициировать» коммит на main-е

В данной команде вам доступна возможность указать ветку и количество добавляемых коммитов

git fakeTeamwork foo 3 С помощью одной лишь команды мы симулируем добавление трёх коммитов в ветку foo на удалённом репозитории

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

Вперёд! Склонируйте удалённый репозиторий (с помощью git clone), симулируйте любые изменения на этом удалённом репозитории, сделайте какие-нибудь свои коммиты и затем скачайте «чужие» изменения. Это выглядит как несколько уроков в одном!

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

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

Вы можете рассматривать команду git push как «публикацию» своей работы. Эта команда скрывает в себе множество тонкостей и нюансов, с которыми мы познакомимся в ближайшее время, а пока что давайте начнём с малого.

Здесь у нас имеются изменения, которых нет в удалённом репозитории. Давайте же закачаем их туда!

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

7: Расхождение в истории

Вот мы и познакомились с тем, как забирать (pull) чужие коммиты и как закачивать (push) свои наработки и изменения. Выглядит всё довольно просто, и не ясно какие же могут возникать у людей трудности со всем этим?

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

В этом случае использование команды git push является сомнительным. Как поведёт себя команда git push, если вы её выполните? Может быть, она изменит удалённый репозиторий и вернёт всё к тому состоянию, которое было в понедельник? А может, команда попробует добавить ваш код, не удаляя при этом новый? Или же она проигнорирует ваши изменения, так как они уже устарели?

По причине того, что в данной ситуации (когда история расходится) слишком много двусмысленностей и неопределённостей, git не даст вам закачать (push) ваши изменения. Он будет принуждать вас включить в состав своей работы все те последние наработки и изменения, которые находятся на удалённом репозитории.

Слишком много болтовни! Давайте посмотрим, как всё работает на живом примере

git push Видите? Ничего не произошло. Всё потому, что команда git push не выполнилась успешно. Дело в том, что ваш последний коммит C3 основан на удалённом коммите C1. В свою очередь, удалённый репозиторий уже изменился под воздействием C2. Вот почему git отклонил ваш push.

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

Опа! Мы только что обновили наш локальный образ удалённого репозитория средствами git fetch. Ещё мы перебазировали наши наработки, чтобы они отражали все изменения с удалённого репозитория, и опубликовали их с помощью git push.

А есть ещё какие-либо варианты обновить мои наработки к тому моменту, как удалённый репозиторий был обновлён? Конечно есть! Давайте ознакомимся с парочкой новых штучек, но в этот раз с помощью команды merge.

Несмотря на то, что git merge не передвигает ваши наработки (а всего лишь создаёт новый коммит, в котором Ваши и удалённые изменения объединены), этот способ помогает указать git-у на то, что вы собираетесь включить в состав ваших наработок все изменения с удалённого репозитория. Это значит, что ваш коммит отразится на всех коммитах удалённой ветки, поскольку удалённая ветка является предком вашей собственной локальной ветки.

Давайте взглянем на демонстрацию.

Таким образом, если мы объединим (merge) вместо перебазирования (rebase).

Опа! Мы обновили наше локальное представление удалённого репозитория с помощью git fetch, объединили ваши новые наработки с нашими наработками (чтобы отразить изменения в удалённом репозитории) и затем опубликовали их с помощью git push.

Здорово! А можно ли как-то сделать всё то же самое, но с меньшим количеством команд?

Давайте взглянем на эти оба варианта.

Тот же результат, как и ранее, но намного короче вызов команд.

А теперь с обычным pull.

Рабочий процесс получения изменений (fetching), перебазирования/объединения (rebase/merging) и публикации изменений (pushing) используется довольно часто. В последующих уроках мы изучим более сложные варианты этих рабочих процессов, но пока что давайте остановимся на том, что есть.

Чтобы выполнить задание уровня, сделайте следующее:

8: Заблокированная ветвь main

Когда вы работаете в составе большой команды разработчиков над проектом, то, вероятнее всего, ветвь main будет заблокирована. Для внесения изменений в неё в git существует понятие запроса на слияние Pull Request. В такой ситуации если вы закоммитите свои наработки непосредственно в main ветвь, а после выполните git push, то будет сгенерировано сообщение об ошибке:

Эта политика подразумевает процесс создания новой ветви разработки, внесение в неё всех необходимых коммитов, загрузка изменений в удалённый репозиторий и открытие нового Pull request. Однако вы забыли про это и закоммитили наработки непосредственно в main ветвь. Теперь вы застряли и не можете запушить свои изменения :(.

Решение: Создайте ещё одну ветвь под названием feature и отправьте изменения на удалённый репозиторий. Также не забудьте вернуть вашу локальную main ветвь в исходное состояние (чтобы она была синхронизирована с удалённой). В противном случае у вас могут возникнуть проблемы при следующем выполнении git pull.

Через origin – к звёздам. Продвинутое использование Git Remotes

Весело было быть всесильным мудрым правителем.

Слияние фича-бранчей (веток)

Теперь, когда вы умело владеете командами fetch, pull и push, давайте применим эти навыки в сочетании с новым рабочим процессом (он же workflow).

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

Для этого рабочего процесса мы совместили две вещи:

интеграцию фича-бранчей в main закачку (push) и скачку (pull) с удалённого репозитория

Давайте быстренько вспомним, как нам обновить main и закачать выполненную работу.

Здесь мы выполнили две команды, которые:

2: Слияние с удалённым репозиторием

Merge? Нет, нет, спасибо.

Если мы можем воспользоваться одним из двух методов, то почему же эти упражнения сфокусированы в основном на rebase? К чему такая нелюбовь к merge, когда речь идёт о работе с удалёнными репозиториями?

В среде разработчиков существует огромное количество дебатов около merging и rebasing. Ниже приведены основные за / против метода rebasing:

Например, коммит C1 может быть перебазирован после C3. Соответственно, в дереве работа над C1′ будет отображаться как идущая после C3, хотя на самом деле она была выполнена раньше.

Некоторые разработчики любят сохранять историю и предпочитают слияние (merging). Другие (такие как я) предпочитают иметь чистое дерево коммитов, и пользуются перебазировкой (rebasing). Всё зависит от ваших предпочтений и вкусов 😀

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

3: Слежка за удалённым репозиторием

время операции pull коммиты скачиваются в ветку o/main и затем соединяются в ветку main. Подразумеваемая цель слияния определяется исходя из этой связи.

Во время операции push наработки из ветки main закачиваются на удалённую ветку main (которая в локальном представлении выглядит как o/main). Пункт назначения операции push определяется исходя из связи между main и o/main.

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

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

Именно это объясняет, почему сразу после клонирования вы видите в консоли надпись:

local branch «main» set to track remote branch «o/main» (локальная ветка «main» теперь следит за удалённой веткой «o/main»)

А могу ли я сделать это самостоятельно?

Само собой! Вы можете сказать любой из веток, чтобы она отслеживала o/main, и если вы так сделаете, эта ветка будет иметь такой же пункт назначения для push и merge как и локальная ветка main. Это значит, что вы можете выполнить git push, находясь на ветке totallyNotMain, и все ваши наработки с ветки totallyNotMain будут закачены на ветку main удалённого репозитория!

, которая создаст новую ветку с именем totallyNotMain и укажет ей следить за o/main.

Хватит болтовни, давайте взглянем на демонстрацию! Мы выполним checkout для новой ветки foo и укажем ей, чтобы она отслеживала main с удалённого репозитория.

Как вы увидели, мы использовали o/main, чтобы обновить ветку foo. Обратите внимание, как обновился main!!

Это работает также и для git push.

Оп! Мы закачали наши наработки на ветку main нашего удалённого репозитория. При том, что наша локальная ветка называется абсолютно по-другому.

вы укажете ветке foo следить за o/main. А если вы ещё при этом находитесь на ветке foo, то её можно не указывать:

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

Словом, всё как и раньше, просто отдельная, специальная команда. Здорово!

Отлично! Для выполнения этого уровня давайте выполним push наших наработок в ветку main на удалённом репозитории, при этом не скачивая и не создавая ветку main локально. Я объясню вам оставшееся чуть позже, т.к. это продвинутый курс 😛

4: Аргументы git push

Отлично! Теперь, когда вы знаете, как следить за удалёнными ветками, мы можем начать изучение того, что скрыто под занавесом работы команд git push, fetch и pull. Мы будем рассматривать одну команду за другой, однако принципы у них очень схожи.

Сперва взглянем на git push. В уроке, посвящённом слежению за удалённым репозиторием, вы узнали о том, что git находит удалённый репозиторий и ветку, в которую необходимо push-ить, благодаря свойствам текущей ветки, на которой мы находимся. Это так называемое поведение без аргументов, однако команда git push может быть также использована и с аргументами. Вид команды в данном случае:

дословный перевод с английского будет таким:

Перейди в ветку с именем «main» в моём локальном репозитории, возьми все коммиты и затем перейди на ветку «main» на удалённом репозитории «origin.». На эту удалённую ветку скопируй все отсутствующие коммиты, которые есть у меня, и скажи, когда ты закончишь.

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

Вот так! Мы обновили main на удалённом репозитории, принудительно указав аргументы в push.

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

Как вы видите, команда не выполнилась, так как HEAD потерялся и не находится на удалённо-отслеживаемой ветке.

Хорошо, для выполнения этого уровня давайте обновим обе ветки foo и main на удалённом репозитории. Фишка в том, что команда git checkout не доступна на этом уровне!

Замечание: Удалённые ветки помечены как o/, а не origin/. Дело в том, что полная метка не помещается на экране. Не волнуйтесь по этому поводу. просто используйте знакомый нам origin для обращения к удалённому репозиторию.

Помните, когда в прошлом занятии мы указали в качестве аргумента ветку main для команды git push, мы указали совместно источник, откуда будут приходить коммиты, и пункт назначения (получатель), куда коммиты будут уходить.

К огромному сожалению, это невозможно сделать средствами git. Да ладно! Я пошутил! Конечно, это возможно :). git сам по себе достаточно гибок (даже слишком).

Мы увидим, как именно, на следующем слайде.

Обычно это называется refspec. Refspec — это всего лишь модное имя для определения местоположения, которое git может распознать (например, ветка foo или просто HEAD

Как только вы указали источник и получатель независимо друг от друга, вы можете довольно причудливо и точно использовать команды для работы с удалёнными ветками и репозиториями. Давайте взглянем на демонстрацию!

А что если пункт назначения, в который вы хотите запушить, не существует? Без проблем! Укажите имя ветки, и git сам создаст ветку на удалённом репозитории для вас.

Класс! Довольно легко! 😀

Для выполнения данного уровня попытайтесь привести своё дерево к такому же виду, как на визуализации. И не забудьте о формате:

6: Аргументы для fetch

Ещё бы! Аргументы для команды git fetch на самом деле очень, очень похожи на те, что мы использовали в git push. В данном случае применяется тот же подход, только в противоположном направлении (так как теперь вы скачиваете коммиты, а не закачиваете их).

Давайте ознакомимся с принципами один за одним.

Параметр Если вы указываете пункт назначения в команде git fetch, например так, как в следующем примере:

Git отправится в ветку foo на удалённом репозитории, соберёт с собой все коммиты, которые не присутствуют локально, и затем поместит их в локальную ветку под названием o/foo.

Давайте взглянем на всё это в действии (чтобы освежить в памяти).

Указывая пункт назначения.

мы скачиваем только коммиты с ветки foo и помещаем их в o/foo.

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

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

Давайте взглянем на всё это в действии:

Ого! Видите, git распознал foo

1 как место в origin и затем скачал эти коммиты в bar, которая является локальной веткой. Обратите внимание, что ветки foo и o/foo не изменились, так как в аргументах мы явно указали получателя.

А что, если ветка-получатель не существует на момент запуска команды? Давайте ещё раз взглянем на предыдущий слайд, но на этот раз ветки bar ещё не существует.

Видите, поведение совсем такое же, как и у git push. Git создал ветку-получатель локально прежде чем скачивать данные. Всё как и в случае, когда git создаёт получателя в удалённом репозитории, когда мы закачиваем изменения (если получатель не существует).

Если команда git fetch выполняется без аргументов, она скачивает все-все коммиты с удалённого репозитория и помещает их в соответствующие удалённо-локальные ветки в локальном репозитории.

Достаточно просто, после того как мы пережили все эти технические тонкости.

Ладно, достаточно болтовни! Чтобы выполнить этот уровень, скачайте лишь определённые коммиты так, как представлено в визуализации цели. Пофантазируйте с этими командами!

Вам следует явно указывать источник и получателя для обеих команд fetch. Обратите внимание на визуализацию цели, так как ID-шники могут меняться!

7: Пустой источник

Git использует параметр странным образом. Странность заключается в том, что Вы можете оставить пустым параметр для команд git push и git fetch:

Посмотрим, что же из этого выйдет.

Как видите, мы удалили ветку foo в удаленном репозитории, попытавшить протолкнуть(git push) в неё «ничего».

Наконец, если мы попытаемся притянуть изменения(git fetch) из «ничего» к нам в локальный репозиторий, то это создаст у нас новую ветку

Вот такой вот чудной git!

8: Аргументы для pull

Аргументы для git pull не покажутся вам чем-то новым, учитывая, что вы уже знакомы с аргументами для git fetch и git push 🙂

Как мы помним, git pull сначала выполняет git fetch, а следом сразу git merge с той веткой, в которую притянулись обновления командой fetch. Другими словами, это все равно, что выполнить git fetch с теми же аргументами, которые вы указали для pull, а затем выполнить git merge с веткой, указанной в аргументе команды pull.

Рассмотрим на примерах:

Вот примеры абсолютно эквивалентных команд в git:

git pull origin foo это то же самое, что сделать:

git fetch origin foo; git merge o/foo

1:bugFix; git merge bugFix

Как видно, git pull используется, чтобы за одну команду выполнить fetch + merge.

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

Как видно, мы указали main, поэтому как обычно все обновления притянулись на ветку o/main. Затем мы слили (merge) обновленную ветку o/main с веткой, на которой мы находимся.

Ого, сколько всего выполнено всего одной командой!. Мы создали новую ветку foo в локальном репозитории, скачали на неё изменения с ветки main удаленного репозитория, а затем слили эту ветку с веткой bar, на которой мы находились!

В последнем упражнении необходимо привести дерево к аналогичному в примере. Нужно скачать несколько изменений, создать несколько новых веток, слить одни ветки в другие, но постарайтесь использовать как можно меньше команд. Удачи! 😛

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *