Инструменты пользователя

Инструменты сайта


learning:git

Содержание

githowto.com

Первоначальная настройка

# Кто автор коммитов в этом экземпляре гита - имя и адрес
git config --global user.name "Your Name"
git config --global user.email "your_email@whatever.com"
# Задать main веткой по умолчанию
git config --global init.defaultBranch main
# Корректно обрабатывать окончания строк (для Windows)
git config --global core.autocrlf true
git config --global core.safecrlf warn

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

# Создать новый репозиторий (можно уже после создания файлов проекта в каталоге)
git init # создастся подкаталог .git
# Добавить файл и закоммитить с комментарием
git add hello.html
git commit -m "Initial Commit"
# Проверить состояние репозитория
git status
On branch main # Сейчас на ветке main
nothing to commit, working tree clean # Нет файлов, ожидающих записи, репозиторий равен текущему состоянию каталога
# Переименовать master в main, если гит старый и команда, делающая ветку main основной, не сработала
git branch -m master main

Внесение изменений

# Если что-то добавить в файл и посмотреть состояние репозитория:
git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hello.html
 
no changes added to commit (use "git add" and/or "git commit -a")
# Можно откатить файл обратно
git restore hello.html
# А можно добавить его в коммит (проиндексировать)
git add hello.html
# После добавления статус показывает, что файл проиндексирован
git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   hello.html
# Можно откатить индексацию (файл вернётся к добавленному, но не индексированному состоянию)
git restore --staged hello.html
 
# Отдельный шаг индексации позволяет разделять добавленные файлы на разные коммиты,
# чтобы не связанные между собой изменения не попадали в один коммит.
# К примеру, изменены 3 файла - a.html, b.html и c.html, и файл c.html не связан с другими.
git add a.html
git add b.html
git commit -m "Changes for a and b"
git add c.html
git commit -m "Unrelated change to c"

Коммит

Если не задать параметр -m для git commit, то откроется редактор. Он задаётся в одной из настроек

  • переменная среды GIT_EDITOR
  • параметр конфигурации core.editor
  • переменная среды VISUAL
  • переменная среды EDITOR
git config --global core.editor emacs # emacs
git config --global core.editor "code --wait" # VSCode

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

История проекта

git log
 
git log
commit 204912e8c6cf87c0743ffa5646f4c7438d6ebeaa (HEAD -> main)
Author: Your Name <you@example.com>
Date:   Tue Jan 21 16:26:12 2025 +0300
 
    Added HTML header
 
commit 88622c4f43f5caa7a891542f09564c68fc362682
Author: Your Name <you@example.com>
Date:   Tue Jan 21 16:15:07 2025 +0300
 
    Added H1 tag
 
commit 1a3a27e686a3baeec77a9f44a65471b88495a3e1
Author: unknown <user@DESKTOP.workgroup>
Date:   Tue Jan 21 15:17:07 2025 +0300
 
    Initial Commit
 
# Вид настраивается, например, однострочный вид
git log --pretty=oneline
204912e8c6cf87c0743ffa5646f4c7438d6ebeaa (HEAD -> main) Added HTML header
88622c4f43f5caa7a891542f09564c68fc362682 Added H1 tag
1a3a27e686a3baeec77a9f44a65471b88495a3e1 Initial Commit
# Ещё варианты
git log --oneline --max-count=2 # 2 последних коммита
git log --oneline --since="5 minutes ago" # за последние 5 минут
git log --oneline --until="5 minutes ago" # кроме последних 5 минут
git log --oneline --author="Your Name" # фильтр по автору
git log --all --pretty=format:"%h %cd %s (%an)" --since="7 days ago" # Укороченный хэш, время, коммент, автор
204912e Tue Jan 21 16:26:12 2025 +0300 Added HTML header (Your Name)
88622c4 Tue Jan 21 16:15:07 2025 +0300 Added H1 tag (Your Name)
1a3a27e Tue Jan 21 15:17:07 2025 +0300 Initial Commit (unknown)
git log --pretty=format:"%h %ad | %s%d [%an]" --date=short # Ещё вариант
204912e 2025-01-21 | Added HTML header (HEAD -> main) [Your Name]
88622c4 2025-01-21 | Added H1 tag [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]
 
# Сделать последний вариант pretty format по умолчанию
git config --global format.pretty '%h %ad | %s%d [%an]'
git config --global log.date short

https://git-scm.com/docs/git-log

Откат на старые версии

# Откатиться на самый первый коммит (достаточно первых 7 символов хэша как указатель)
git checkout 1a3a27e
Note: switching to '1a3a27e'.
 
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
 
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
 
  git switch -c <new-branch-name>
 
Or undo this operation with:
 
  git switch -
 
Turn off this advice by setting config variable advice.detachedHead to false
 
HEAD is now at 1a3a27e Initial Commit
 
# hello.html выглядит как в самом начале
cat .\hello.html
Hello, World
# Вернуться на последнюю версию в ветке main
git switch main
# hello.html теперь опять со всеми изменениями
cat .\hello.html
<html>
  <body>
    <h1>Hello, World!</h1>
  </body>
</html>

Создание тэгов версий

Работать с хэшами коммитов неудобно. Можно задать человеческий тэг, тогда можно будет сослаться на него.

git tag v1 # задать тэг текущей версии
git log -n 1
204912e 2025-01-21 | Added HTML header (HEAD -> main, tag: v1) [Your Name]
 
### Задать тэг предыдущей версии
# Переключиться на предыдущую версию
git checkout v1^ # или git checkout v1~1
git tag v1-beta
git log -n 1
88622c4 2025-01-21 | Added H1 tag (HEAD, tag: v1-beta) [Your Name]
 
# Теперь можно переключаться по тэгам
git checkout v1
Previous HEAD position was 88622c4 Added H1 tag
HEAD is now at 204912e Added HTML header
git checkout v1-beta
Previous HEAD position was 204912e Added HTML header
HEAD is now at 88622c4 Added H1 tag
 
# Список тэгов
git tag
v1
v1-beta
 
# Тэги в логе
git log main --all
204912e 2025-01-21 | Added HTML header (tag: v1, main) [Your Name]
88622c4 2025-01-21 | Added H1 tag (HEAD, tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

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

До индексации

Чтобы откатить изменения в файле, ещё не добавленном в коммит:

# Вот есть изменения, которые надо отменить
git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hello.html
 
no changes added to commit (use "git add" and/or "git commit -a")
 
# Откатить изменения
git restore hello.html
 
# Теперь чисто, изменений нет
git status
On branch main
nothing to commit, working tree clean

После индексации

Отмена изменений в файле, добавленном в коммит

git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   hello.html
 
# Убрать файл из индекса (коммита). Файл при этом остался изменённым!
git restore --staged hello.html
 
# Дальше действовать как до индексации
git restore hello.html

Отмена коммитов

Есть несколько способов откатить кривой коммит.

Новый коммит, отменяющий предыдущий

revert - история коммитов сохраняется: есть и кривой коммит, и отменяющий его.

git revert HEAD
[main 20dea26] Revert "Wrong commit"
 1 file changed, 1 deletion(-)
PS C:\temp\githowto\repositories\work> git log
20dea26 2025-01-21 | Revert "Wrong commit" (HEAD -> main) [Your Name]
c90b848 2025-01-21 | Wrong commit [Your Name]
204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

Удаление коммита из истории

reset

  • Изменит текущую ветку, чтобы она указывала на выбранный коммит.
  • Опционально сбросит область подготовки до соответствия с указанным коммитом.
  • Опционально сбросит рабочую директорию до соответствия с указанным коммитом.
# Сбросит ветку до коммита v1 (здесь: бесследно удалится 2 последних коммита, откатятся изменения в файлах)
git reset --hard v1
 
# Лог чист
git log
204912e 2025-01-21 | Added HTML header (HEAD -> main, tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]
# Тем не менее, коммиты ещё есть в списке всех, просто их нет в ветке main
git log --all
20dea26 2025-01-21 | Revert "Wrong commit" (tag: wrong) [Your Name]
c90b848 2025-01-21 | Wrong commit [Your Name]
204912e 2025-01-21 | Added HTML header (HEAD -> main, tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

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

Здесь у одного из удалённых коммитов есть тэг, его надо удалить, чтобы сборщик мусора смог на нём отработать.

git tag -d wrong
Deleted tag 'wrong' (was 20dea26)
# Теперь в списке всех коммитов также нет ошибочных
git log --all
204912e 2025-01-21 | Added HTML header (HEAD -> main, tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

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

Внесение изменений в коммиты

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

git commit -m "Add copyright"
[main 3d91d05] Add copyright
 1 file changed, 1 insertion(+)
git log
3d91d05 2025-01-22 | Add copyright (HEAD -> main) [Your Name]
204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]
 
git add .\hello.html
git commit --amend -m "Add copyright with email"
[main b0d54f0] Add copyright with email
 Date: Wed Jan 22 13:41:15 2025 +0300
 1 file changed, 1 insertion(+)
# Последний коммит заменён на новый
git log
b0d54f0 2025-01-22 | Add copyright with email (HEAD -> main) [Your Name]
204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

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

Создание веток и переключение между ними

# Создать ветку style
git switch -c style
Switched to a new branch 'style'
 
# Старый способ (не рекомендуется)
git checkout -b style
 
git status
On branch style
nothing to commit, working tree clean
 
# Переключение между ветками (hello.html будет разным после коммитов в ветку style)
git switch main
cat hello.html
git switch style
cat hello.html

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

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

# После обычного переименования/перемещения файлов руками
git status
On branch style
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    hello.html
        deleted:    style.css
 
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        css/
        index.html
 
no changes added to commit (use "git add" and/or "git commit -a")
 
# Перенести файлы корректно
mkdir css
git mv style.css css/style.css
git mv hello.html index.html
git status
 
# Теперь статус в порядке
git status
On branch style
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        renamed:    style.css -> css/style.css
        renamed:    hello.html -> index.html
 
# Чтобы посмотреть изменения файла до переименования, добавить параметр --follow
git log css/style.css
4a6c610 2025-01-22 | Renamed hello.html; moved style.css (HEAD -> style) [Your Name]
 
git log --follow css/style.css
4a6c610 2025-01-22 | Renamed hello.html; moved style.css (HEAD -> style) [Your Name]
aa9e5d8 2025-01-22 | Add css [Your Name]

Просмотр отличающихся веток

# --all - показать все ветки (по умолчанию показывается текущая ветка)
# --graph - дерево в виде простых текстовых линий
git log --all --graph
* b022e6a 2025-01-22 | Add README (HEAD -> main) [Your Name]
| * 4a6c610 2025-01-22 | Renamed hello.html; moved style.css (style) [Your Name]
| * 632e4e7 2025-01-22 | Include css into hello.html [Your Name]
| * aa9e5d8 2025-01-22 | Add css [Your Name]
|/
* b0d54f0 2025-01-22 | Add copyright with email [Your Name]
* 204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
* 88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
* 1a3a27e 2025-01-21 | Initial Commit [unknown]

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

Слить ветку main в style

# Перейти в ветку style
git switch style
Switched to branch 'style'
# Слить ветки
git merge main
Merge made by the 'ort' strategy.
 README | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 README
# График коммитов
git log --all --graph
*   98277e2 2025-01-22 | Merge branch 'main' into style (HEAD -> style) [Your Name]
|\
| * b022e6a 2025-01-22 | Add README (main) [Your Name]
* | 4a6c610 2025-01-22 | Renamed hello.html; moved style.css [Your Name]
* | 632e4e7 2025-01-22 | Include css into hello.html [Your Name]
* | aa9e5d8 2025-01-22 | Add css [Your Name]
|/
* b0d54f0 2025-01-22 | Add copyright with email [Your Name]
* 204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
* 88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
* 1a3a27e 2025-01-21 | Initial Commit [unknown]

Путем периодического слияния ветки main с веткой style происходит перенос изменений из main и поддерживается совместимость изменений style с изменениями в основной ветке. Однако, это делает графики коммитов уродливыми. Альтернатива слиянию - перебазирование (rebase).

Конфликтующие изменения в ветках и разрешение конфликта

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

Файл index.html ветки style

<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
  <head>
    <link type="text/css" rel="stylesheet" media="all" href="style.css" />
  </head>
  <body>
    <h1>Hello, World!</h1>
  </body>
</html>

Файл hello.html ветки main

<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
  <head>
    <title>Hello World Page</title>
  </head>
  <body>
    <h1>Hello, World!</h1>
    <p>Let's learn Git together.</p>
  </body>
</html>

После попытки слива веток

git switch style
Switched to branch 'style'
 
git merge main
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Файл index.html выглядит так:

<!-- Author: Alexander Shvets (alex@githowto.com) -->
<html>
  <head>
<<<<<<< HEAD:index.html
    <link type="text/css" rel="stylesheet" media="all" href="style.css" />
=======
    <title>Hello World Page</title>
>>>>>>> main:hello.html
  </head>
  <body>
    <h1>Hello, World!</h1>
    <p>Let's learn Git together.</p>
  </body>
</html>

Часть между <<<<<<< и >>>>>>> является конфликтом. Верхняя часть соответствует ветке style, которая является текущей веткой (или HEAD) репозитория. Нижняя часть соответствует изменениям из ветки main. Видно, что часть с <p>Let's learn Git together.</p> git сделал сам.

# Можно отменить слияние веток
git merge --abort
 
# А можно отредактировать index.html и закоммитить его
git add index.html
git commit -m "Resolved merge conflict"
 
git status
On branch style
nothing to commit, working tree clean
 
git log --all --graph
*   e71d981 2025-01-22 | Resolved merge conflict (HEAD -> style) [Your Name]
|\
| * 9e1309b 2025-01-22 | Added meta title (main) [Your Name]
* | 98277e2 2025-01-22 | Merge branch 'main' into style [Your Name]
|\|
| * b022e6a 2025-01-22 | Add README [Your Name]
* | 4a6c610 2025-01-22 | Renamed hello.html; moved style.css [Your Name]
* | 632e4e7 2025-01-22 | Include css into hello.html [Your Name]
* | aa9e5d8 2025-01-22 | Add css [Your Name]
|/
* b0d54f0 2025-01-22 | Add copyright with email [Your Name]
* 204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
* 88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
* 1a3a27e 2025-01-21 | Initial Commit [unknown]

У Git нет графических инструментов слияния, но можно настроить сторонние.

rebase вместо merge

# В ветке style коммит ''Renamed hello.html; moved style.css'' последний перед слиянием с main.
git log --graph
*   e71d981 2025-01-22 | Resolved merge conflict (HEAD -> style) [Your Name]
|\  
| * 9e1309b 2025-01-22 | Added meta title (main) [Your Name]
* | 98277e2 2025-01-22 | Merge branch 'main' into style [Your Name]
|\| 
| * b022e6a 2025-01-22 | Add README [Your Name]
* | 4a6c610 2025-01-22 | Renamed hello.html; moved style.css [Your Name]
* | 632e4e7 2025-01-22 | Include css into hello.html [Your Name]
* | aa9e5d8 2025-01-22 | Add css [Your Name]
|/  
* b0d54f0 2025-01-22 | Add copyright with email [Your Name]
* 204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
* 88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
* 1a3a27e 2025-01-21 | Initial Commit [unknown]
 
# Сброс ветки style к этому коммиту
git reset --hard HEAD~2 # Вариант: git reset --hard 4a6c610
HEAD is now at 4a6c610 Renamed hello.html; moved style.css
 
# В ветке main есть два коммита, которых нет в ветке style: новый файл README и конфликтующее изменение в файле index.html.
# Перенести эти изменения в ветку style с помощью команды rebase.
git switch style
 
git rebase main
Auto-merging hello.html
CONFLICT (content): Merge conflict in hello.html
error: could not apply 632e4e7... Include css into hello.html
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Could not apply 632e4e7... Include css into hello.html
 
git status

Опять возник конфликт, но в hello.html, а не в файле index.html, как в прошлый раз. Это связано с тем, что rebase находился в процессе применения изменений style поверх ветки main. Файл hello.html в main еще не был переименован, поэтому он все еще имеет старое имя. При слиянии возник бы «обратный» конфликт. При слиянии изменения ветки main были бы применены поверх ветки style. В ветке style файл переименован, поэтому конфликт возник бы в файле index.html.

После устранения конфликта можно продолжить rebase (коммит уже не нужен!)

git add .
 
git rebase --continue
[detached HEAD 31f51f7] Include css into hello.html
 1 file changed, 3 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/style.
 
git status
On branch style
nothing to commit, working tree clean
 
git log --graph --all
* 53c3dbd 2025-01-22 | Renamed hello.html; moved style.css (HEAD -> style) [Your Name]
* 31f51f7 2025-01-22 | Include css into hello.html [Your Name]
* d835c42 2025-01-22 | Add css [Your Name]
* 9e1309b 2025-01-22 | Added meta title (main) [Your Name]
* b022e6a 2025-01-22 | Add README [Your Name]
* b0d54f0 2025-01-22 | Add copyright with email [Your Name]
* 204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
* 88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
* 1a3a27e 2025-01-21 | Initial Commit [unknown]

Конечный результат перебазирования очень похож на результат слияния. Ветка style в настоящее время содержит все свои изменения, а также все изменения ветки main. Однако, дерево коммитов значительно отличается. Дерево коммитов ветки style было переписано таким образом, что ветка main является частью истории коммитов. Это делает цепь коммитов линейной и гораздо более читабельной.

Используйте команду rebase:

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

Не используйте команду rebase:

  • Если текущая ветка является публичной и общей. Переписывание таких веток будет мешать работе других членов команды.
  • Если важна точная история ветки коммитов (поскольку команда rebase переписывает историю коммитов).

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

Слив в ветку main

git switch main
 
git merge style
Updating 9e1309b..53c3dbd
Fast-forward
 css/style.css            | 3 +++
 hello.html => index.html | 4 +++-
 2 files changed, 6 insertions(+), 1 deletion(-)
 create mode 100644 css/style.css
 rename hello.html => index.html (70%)

Т. к. последний коммит в main предшествует последнему коммиту ветки style, Git может выполнить ускоренное слияние, просто переместив указатель ветки вперед, на тот же коммит, что и ветка style. При ускоренном слиянии конфликты не возникают. Кроме того, при ускоренном слиянии не создается фиксация слияния.

Теперь ветки style и main идентичны.

Несколько репозиториев

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

cd C:\temp\githowto\repositories
git clone work home
Cloning into 'home'...
done.
 
ls
    Каталог: C:\temp\githowto\repositories
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        01.02.2025      9:11                home
d-----        26.01.2025     11:59                work
 
# Если посмотреть историю, то у обоих репозиториев одинаковые коммиты, но у клонированного добавились ветки
# origin/style, origin/main, origin/HEAD
git log --all
53c3dbd 2025-01-22 | Renamed hello.html; moved style.css (HEAD -> main, origin/style, origin/main, origin/HEAD) [Your Name]
...

origin - указание первичного репозитория

При клонировании репозитория исходный сохраняется как origin. Традиционно origin используется в качестве имени первичного централизованного репозитория.

git remote
origin
 
git remote show origin
* remote origin
  Fetch URL: C:/temp/githowto/repositories/work
  Push  URL: C:/temp/githowto/repositories/work
  HEAD branch: main
  Remote branches:
    main  tracked
    style tracked
  Local branch configured for 'git pull':
    main merges with remote main
  Local ref configured for 'git push':
    main pushes to main (up to date)

Локальные и удалённые ветки

Если вывести список веток в клонированном репозитории, то будет видна только main.

git branch
* main
 
# С параметром -a будут видны все ветки
git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/style

Ветки в удаленном репозитории не рассматриваются как локальные. Если нужна ветка style, то нужно её создать.

Синхронизация изменений из удалённого репозитория

git fetch - получение новых коммитов из удаленного репозитория без изменения локальных веток.

# Внесение изменений в удалённый репозиторий
cd ../work
git add .\README
git commit -m "Changed README in original repo"
[main 7cc9cfb] Changed README in original repo
 1 file changed, 2 insertions(+), 1 deletion(-)
 
# Получение изменений в локальном
cd ../home
git fetch
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 372 bytes | 28.00 KiB/s, done.
From C:/temp/githowto/repositories/work
   53c3dbd..7cc9cfb  main       -> origin/main
 
# Коммит приехал, но не интегрировался в локальную ветку main (HEAD не на последнем коммите)
# Соответственно, файл локальный файл README не изменился.
git log --all
7cc9cfb 2025-02-01 | Changed README in original repo (origin/main, origin/HEAD) [Your Name]
53c3dbd 2025-01-22 | Renamed hello.html; moved style.css (HEAD -> main, origin/style) [Your Name]
31f51f7 2025-01-22 | Include css into hello.html [Your Name]
d835c42 2025-01-22 | Add css [Your Name]
9e1309b 2025-01-22 | Added meta title [Your Name]
b022e6a 2025-01-22 | Add README [Your Name]
b0d54f0 2025-01-22 | Add copyright with email [Your Name]
204912e 2025-01-21 | Added HTML header (tag: v1) [Your Name]
88622c4 2025-01-21 | Added H1 tag (tag: v1-beta) [Your Name]
1a3a27e 2025-01-21 | Initial Commit [unknown]

Слияние полученных изменений удалённого репозитория с локальным

git merge сливает полученные ранее изменения в локальный репозиторий.

git merge origin/main
Updating 53c3dbd..7cc9cfb
Fast-forward
 README | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Теперь файл README изменён и локально.

Есть возможность сразу и получить изменения из удалённого репозитория, и сразу слить их в локальный - это git pull.
Т. е., git pull = git fetch + git merge origin/main.

Добавление локальной ветки, отслеживающей удалённую

# Добавить ветку style, отслеживающую origin/style
git branch --track style origin/style
branch 'style' set up to track 'origin/style'.
 
# Локальная ветка style появилась в списке веток
git branch -a
* main
  style
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/style
 
# и в логе
git log --max-count=2
7cc9cfb 2025-02-01 | Changed README in original repo (HEAD -> main, origin/main, origin/HEAD) [Your Name]
53c3dbd 2025-01-22 | Renamed hello.html; moved style.css (origin/style, style) [Your Name]

Чистый репозиторий

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

cd ..
# Традиционно "чистый" репозиторий создаётся с .git в конце имени
git clone --bare work work.git
Cloning into bare repository 'work.git'...
done.
PS C:\temp\githowto\repositories> ls work.git
 
    Каталог: C:\temp\githowto\repositories\work.git
 
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        02.02.2025      9:39                hooks
d-----        02.02.2025      9:39                info
d-----        02.02.2025      9:39                objects
d-----        02.02.2025      9:39                refs
-a----        02.02.2025      9:39            164 config
-a----        02.02.2025      9:39             73 description
-a----        02.02.2025      9:39             21 HEAD
-a----        02.02.2025      9:39            274 packed-refs

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

cd work
# Добавить чистый репозиторий work.git как shared
git remote add shared ../work.git
 
# Чистые репозитории обычно располагаются на удаленном сервере и туда нельзя зайти, чтобы подтянуть изменения.
# Поэтому необходимо как-нибудь передать наши изменения в репозиторий.
 
# Внести изменения, например, в README в репе work и закоммитить
git add README
git commit -m "Added shared comment to readme"
[main 576bd94] Added shared comment to readme
 1 file changed, 1 insertion(+), 1 deletion(-)
 
# Передать изменения в чистый репозиторий
git push shared main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 399 bytes | 66.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
To ..\work.git
   7cc9cfb..576bd94  main -> main

Получение изменений из общего репозитория

# Перейти в репозиторий назначения
cd ../home
# Добавить чистый репозиторий work.git как shared (так же, как ранее в исходном репозитории work)
git remote add shared ../work.git
# Отслеживать ветку main в shared
git branch --track shared main
branch 'shared' set up to track 'main'.
# Получить изменения из shared/main
git pull shared main
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Unpacking objects: 100% (3/3), 379 bytes | 27.00 KiB/s, done.
From ../work
 * branch            main       -> FETCH_HEAD
 * [new branch]      main       -> shared/main
Updating 7cc9cfb..576bd94
Fast-forward
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Теперь файл README изменился и в home.

Git-сервер

Git умеет быть и сервером.

cd ..
ls
 
    Каталог: C:\temp\githowto\repositories
 
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        02.02.2025     10:11                home
d-----        26.01.2025     11:59                work
d-----        02.02.2025     10:06                work.git
 
 
# Запуск демона git (добавить --enable=receive-pack, чтобы разрешить push. Внимание: 
# сервер не производит аутентификацию, поэтому любой сможет отправлять изменения в ваш репозиторий!)
git daemon --verbose --export-all --base-path=.
[20528] Ready to rumble
# Это появляется позже после подключения клиента
[21436] Connection from [::1]:34050
[21436] unable to set SO_KEEPALIVE on socket: Input/output error
[21436] Extended attribute "host": localhost
[21436] Extended attribute "protocol": version=2
[21436] Request upload-pack for '/work.git'

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

cd C:\temp\githowto\repositories
# Клонировать work.git с сервера в локальный net_work
git clone git://localhost/work.git net_work
Cloning into 'net_work'...
remote: Enumerating objects: 33, done.
remote: Counting objects: 100% (33/33), done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 33 (delta 4), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (33/33), done.
Resolving deltas: 100% (4/4), done.
 
# Файлы появились
ls net_work
 
    Каталог: C:\temp\githowto\repositories\net_work
 
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        02.02.2025     10:22                css
-a----        02.02.2025     10:22            295 index.html
-a----        02.02.2025     10:22            100 README
learning/git.txt · Последнее изменение: 02.02.2025 07:32 — viacheslav

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki