Самые типичные ошибки и вопросы, связанные с Git, и удобные способы их решения

💖 Нравится? Поделись с друзьями ссылкой

Если используется аутентификация по паролю:

  1. $ git clone https://username:password@gitsrv/opt/git/repository.git

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

Показать все ветки:
  1. $ git branch
Создать новую ветку:
  1. $ git branch
Перейти в новую ветку:
  1. $ git checkout
Создать новую ветку и перейти в неё:
  1. $ git checkout -b
Удалить локальную ветку:
  1. $ git branch -d
Удалить ветку из удаленного репозитория:
  1. $ git push origin --delete

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

Как удалить последний коммит?

  1. $ git reset --soft HEAD^
Git How To. Глава 16. Отмена коммитов
Git How To. Глава 17. Удаление коммиттов из ветки
Официальная документация Git. Основы Git - Отмена изменений

Как изменить последний коммит?

  1. $ git add new_file.txt
  2. $ git commit --amend

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

  1. $ git commit --amend
  2. $ git commit --amend -m "Новый комментарий"

Как объединить несколько коммитов?

  1. $ git rebase -i HEAD~3
Вместо HEAD~3 можно использовать hash коммита. Нужно передать hash того коммита, до которого нужно всё объединить (сплющить).
Откроется редактор со списком коммитов, вверху будет самый старый коммит.
  1. pick 1111111 Commit 1 comment
  2. pick 2222222 Commit 2 comment
  3. pick 3333333 Commit 3 comment
Нужно заменть pick на squash, чтобы получилось так:
  1. pick 1111111 Commit 1 comment
  2. squash 2222222 Commit 2 comment
  3. squash 3333333 Commit 3 comment
Далее нужно сохранить файл и выйти. Будет снова будет открыт текстовой редактор со всеми комментариями к коммитам. Нужно отредактировать, сохранить и выйти. После этих действий коммиты будут объединены.

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

  1. $ git checkout -- file.txt

Как отменить все незафиксированные (незакомиченные) изменения?

  1. $ git checkout

Как придержать некоторые файлы для следующего коммита?

Допустим, вы хотите закоммитить изменения в некоторых файлах, а изменения в других файлах зафиксировать в следующем коммите. Тогда можно временно удалить их из репозитория (unstage files), а потом снова добавить.
  1. $ git reset HEAD file.txt
Эта команда удалит файл из репозитория, в старых коммитах он останется. Head указывает на последний коммит в текущей ветке.

Если не удаётся сделать push на удаленный репозиторий из-за того, что текущая версия репозитория меньше, чем на удаленном репозитории

В этом случае можно сделать принудительный push.
  1. $ git push -f origin master

Слияние веток

Как взять из другой ветки только некоторые файлы?

  1. $ git checkout branchname -- path/to/file.file

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

Вывод на экран информации об удалённом репозитории

  1. $ git remote show origin
На экран будет выведено, что-то вроде этого:
  1. * remote origin
  2. Fetch URL: git@gitsrv:/opt/git/test-project.git
  3. Push URL: git@gitsrv:/opt/git/test-project.git
  4. HEAD branch: master
  5. Remote branch:
  6. master new (next fetch will store in remotes/origin)
  7. Local ref configured for "git push":
  8. master pushes to master (local out of date)

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

  1. $ git remote add origin git@gitsrv:/opt/git/test-project.git

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

Они выглядят как (имя удал. репоз.)/(ветка). Например, если вы хотите посмотреть, как выглядела ветка master на сервере origin во время последнего соединения с ним, проверьте ветку origin/master. Если вы с партнёром работали над одной проблемой, и он выложил ветку iss53, у вас может быть своя локальная ветка iss53; но та ветка на сервере будет указывать на коммит в origin/iss53.

Всё это, возможно, сбивает с толку, поэтому давайте рассмотрим пример. Я создал удаленный репозиторий на GitHub https://github.com/n0tb0dy/RemoreBranches

Там я сделал три коммита


При клонировании удаленного репозитория Git автоматически назовёт его origin , заберёт оттуда все данные, создаст указатель на то, на что там указывает ветка master , и назовёт его локально origin/master (но вы не можете его двигать). Git также сделает вам вашу собственную ветку master , которая будет начинаться там же, где и ветка master в origin , так что вам будет с чем работать.

“origin” это не специальное название

Это подобно названию ветки master, которое дается по умолчанию при создании локального репозитория. Точно так же как ветка master создается по умолчанию при команде git init , точно также по умолчанию используется название origin при команде git clone . Если вы дадите команду git clone –o booyah, то вы получите booyah/master как вашу удаленную ветку по умолчанию.

И так возвращаемся к нашим… коммитам. На удаленном репозитории они выглядят так

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

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

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

Удаление удаленных веток

Имеется конечно в виду удаление веток на удаленном сервере

$ git push origin --delete serverfix


Хлоп! И ветка на удаленном сервере исчезла. Но в принципе эта команда просто удаляет указатель ветки на удаленном сервере. Git сервер продолжит хранить всю информацию о коммитах до тех пор пока вы не запустите команду уборки мусора.

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

Они выглядят как (имя удал. репоз.)/(ветка) . Например, если вы хотите посмотреть, как выглядела ветка master на сервере origin во время последнего соединения с ним, проверьте ветку origin/master . Если вы с партнёром работали над одной проблемой, и он выложил ветку iss53 , у вас может быть своя локальная ветка iss53 ; но та ветка на сервере будет указывать на коммит в origin/iss53 .

Всё это, возможно, сбивает с толку, поэтому давайте рассмотрим пример. Скажем, у вас в сети есть свой Git-сервер на git.ourcompany.com . Если вы с него что-то склонируете (clone), Git автоматически назовёт его origin , заберёт оттуда все данные, создаст указатель на то, на что там указывает ветка master , и назовёт его локально origin/master (но вы не можете его двигать). Git также сделает вам вашу собственную ветку master , которая будет начинаться там же, где и ветка master в origin, так что вам будет с чем работать (см. рис. 3-22).

Рисунок 3-22. Клонирование Git-проекта даёт вам собственную ветку master и origin/master, указывающий на ветку master в origin.

Если вы сделаете что-то в своей локальной ветке master , а тем временем кто-то ещё отправит (push) изменения на git.ourcompany.com и обновит там ветку master , то ваши истории продолжатся по-разному. Ещё, до тех пор, пока вы не свяжетесь с сервером origin, ваш указатель origin/master не будет сдвигаться (см. рис. 3-23).



Рисунок 3-23. При выполнении локальной работы и отправке кем-то изменений на удалённый сервер каждая история продолжается по-разному.

Для синхронизации вашей работы выполняется команда git fetch origin . Эта команда ищет, какому серверу соответствует origin (в нашем случае это git.ourcompany.com); извлекает оттуда все данные, которых у вас ещё нет, и обновляет ваше локальное хранилище данных; сдвигает указатель origin/master на новую позицию (см. рис. 3-24).


Рисунок 3-24. Команда git fetch обновляет ваши удалённые ссылки.

Чтобы продемонстрировать то, как будут выглядеть удалённые ветки в ситуации с несколькими удалёнными серверами, предположим, что у вас есть ещё один внутренний Git-сервер, который используется для разработки только одной из ваших команд разработчиков. Этот сервер находится на git.team1.ourcompany.com . Вы можете добавить его в качестве новой удалённой ссылки на проект, над которым вы сейчас работаете с помощью команды git remote add так же, как было описано в главе 2. Дайте этому удалённому серверу имя teamone , которое будет сокращением для полного URL (см. рис. 3-25).



Рисунок 3-25. Добавление дополнительного удалённого сервера.

Теперь можете выполнить git fetch teamone , чтобы извлечь всё, что есть на сервере и нет у вас. Так как в данный момент на этом сервере есть только часть данных, которые есть на сервере origin , Git не получает никаких данных, но выставляет удалённую ветку с именем teamone/master , которая указывает на тот же коммит, что и ветка master на сервере teamone (см. рис. 3-26).



Рисунок 3-26. У вас появилась локальная ссылка на ветку master на teamone-е.

Отправка изменений

Если у вас есть ветка serverfix , над которой вы хотите работать с кем-то ещё, вы можете отправить её точно так же, как вы отправляли вашу первую ветку. Выполните git push (удал. сервер) (ветка) :

$ git push origin serverfix Counting objects: 20, done. Compressing objects: 100% (14/14), done. Writing objects: 100% (15/15), 1.74 KiB, done. Total 15 (delta 5), reused 0 (delta 0) To [email protected]:schacon/simplegit.git * serverfix -> serverfix

Это в некотором роде сокращение. Git автоматически разворачивает имя ветки serverfix до refs/heads/serverfix:refs/heads/serverfix , что означает “возьми мою локальную ветку serverfix и обнови из неё удалённую ветку serverfix”. Мы подробно обсудим часть с refs/heads/ в главе 9, но обычно её можно опустить. Вы также можете выполнить git push origin serverfix:serverfix - произойдёт то же самое - здесь говорится “возьми мой serverfix и сделай его удалённым serverfix”. Можно использовать этот формат для отправки локальной ветки в удалённую ветку с другим именем. Если вы не хотите, чтобы ветка называлась serverfix на удалённом сервере, то вместо предыдущей команды выполните git push origin serverfix:awesomebranch . Так ваша локальная ветка serverfix отправится в ветку awesomebranch удалённого проекта.

$ git fetch origin remote: Counting objects: 20, done. remote: Compressing objects: 100% (14/14), done. remote: Total 15 (delta 5), reused 0 (delta 0) Unpacking objects: 100% (15/15), done. From [email protected]:schacon/simplegit * serverfix -> origin/serverfix

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

Чтобы слить эти наработки в свою текущую рабочую ветку, выполните git merge origin/serverfix . Если вам нужна своя собственная ветка serverfix , над которой вы сможете работать, то вы можете создать её на основе удалённой ветки:

$ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. Switched to a new branch "serverfix"

Это даст вам локальную ветку, на которой можно работать. Она будет начинаться там, где и origin/serverfix .

Отслеживание веток

Получение локальной ветки с помощью git checkout из удалённой ветки автоматически создаёт то, что называется отслеживаемой веткой . Отслеживаемые ветки - это локальные ветки, которые напрямую связаны с удалённой веткой. Если, находясь на отслеживаемой ветке, вы наберёте git push , Git уже будет знать, на какой сервер и в какую ветку отправлять изменения. Аналогично выполнение git pull на одной из таких веток сначала получает все удалённые ссылки, а затем автоматически делает слияние с соответствующей удалённой веткой.

При клонировании репозитория, как правило, автоматически создаётся ветка master , которая отслеживает origin/master , поэтому git push и git pull работают для этой ветки "из коробки" и не требуют дополнительных аргументов. Однако, вы можете настроить отслеживание и других веток удалённого репозитория. Простой пример, как это сделать, вы увидели только что - git checkout -b [ветка] [удал. сервер]/[ветка] . Если вы используете Git версии 1.6.2 или более позднюю, можете также воспользоваться сокращением --track:

$ git checkout --track origin/serverfix Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. Switched to a new branch "serverfix"

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

$ git checkout -b sf origin/serverfix Branch sf set up to track remote branch refs/remotes/origin/serverfix. Switched to a new branch "sf"

Теперь ваша локальная ветка sf будет автоматически отправлять (push) и получать (pull) изменения из origin/serverfix.

Удаление веток на удалённом сервере

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

$ git push origin:serverfix To [email protected]:schacon/simplegit.git - serverfix

Хлоп. Нет больше ветки на вашем сервере. Вам может захотеться сделать закладку на текущей странице, так как эта команда вам понадобится, а синтаксис вы, скорее всего, забудете. Можно запомнить эту команду вернувшись к синтаксису git push [удал. сервер] [лок. ветка]:[удал. ветка] , который мы рассматривали немного раньше. Опуская часть [лок. ветка] , вы, по сути, говорите “возьми ничто в моём репозитории и сделай так, чтобы в [удал. ветка] было то же самое”.



Рассказать друзьям