Правильное использование git pull --rebase

Git

1. Сценарий проблемы

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

$ git push origin master

# 结果如下
To github.com:hello/demo.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git@github.com:hello/demo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

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

$ git pull origin master

# 结果如下
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 2 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (2/2), done.
From github.com:hello/demo
   3824da0..f318a05  master     -> origin/master
Merge made by the 'recursive' strategy.
 one.md | 2 ++
 1 file changed, 2 insertions(+)
 
$ git push origin master

# 结果如下
Enumerating objects: 10, done.
Counting objects: 100% (8/8), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 1.24 KiB | 1.24 MiB/s, done.
Total 8 (delta 5), reused 0 (delta 0)
To github.com:hello/demo.git
   f318a05..1aefef1  master -> master

Это правда, что push удается, но в настоящее время используйтеgit logПосмотреть историю коммитов:

$ git log

# 结果如下
commit 1aefef1a2bedbd3ebd82db8dcf802011a35a9888 (HEAD -> master, origin/master, origin/HEAD)
Merge: 24cfa5c f318a05
Author: hello <hello@qq.com>
Date:   Tue Jul 23 09:53:47 2019 +0800

    Merge branch 'master' of github.com:hello/demo

commit 24cfa5c3ad271e85ff0e64793bf2bcc9d700c233
Author: hello <hello@qq.com>
Date:   Tue Jul 23 09:50:06 2019 +0800

    feat: 新功能提交

commit f318a05b1a4cbc0a6cf8d7dc7d3fb99cbafb0363
Author: world <world@qq.com>
Date:   Tue Jul 23 09:48:20 2019 +0800

    feat: 其他功能提交

...

Вы обнаружите, что есть дополнительная фиксация слияния, и эта фиксация выполняетсяgit pull origin masterавтоматически генерируется при . Если несколько человек делают это много раз, в записи коммита будет много таких автоматически сгенерированных коммитов слияния, что очень уродливо.

2. Решения

Чтобы решить вышеуказанные проблемы, автоматически сгенерированный коммит слияния больше не будет отображаться, пока вы выполняетеgit pull origin masterпринеси это, когда--rebaseПросто:

$ git pull --rebase origin master

$ git push origin master

3. Пример проекта

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

# 在 demo 目录下执行以下命令
$ ls

# 结果如下
one.md  two.md

$ cat one.md

# 结果如下
hello one

$ cat two.md

#结果如下
hello two

Два студента-разработчика A и B используют удаленную ветвь (master) для совместной разработки. Студент модифицировалone.mdфайл, сделал фиксацию и отправил мастеру удаленной ветки:

$ cat one.md

# 结果如下
hello one

new feature from one

$ git push origin master

# 结果如下
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 1.24 KiB | 1.24 MiB/s, done.
Total 4 (delta 3), reused 0 (delta 0)
To github.com:hello/demo.git
   f318a05..1aefef1  master -> master

В это время одноклассник Б об этом не знал, и не обновлял пул удаленной ветки на локальную. Студент B изменил егоtwo.mdфайл, также сделал коммит и попытался отправить его на мастер удаленной ветки:

$ cat two.md

# 结果如下
hello two

new feature from two

$ git push origin master

# 结果如下
To github.com:hello/demo.git
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git@github.com:hello/demo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Обнаружил ошибку и не смог нажать. В этот момент выполните следующую команду:

$ git pull --rebase

$ git push origin master

можно успешно толкнуть.

4. Меры предосторожности

  • воплощать в жизньgit pull --rebaseдолжен содержать локальный каталог в чистоте, когда. То есть: не может существовать в состоянииmodifiedдокумент. (существуетUntracked filesэто не имеет значения)
  • Если возникает конфликт, вы можете разрешить конфликт вручную и продолжитьrebase, вы также можете отказаться от этогоrebase

4.1 Исполнениеgit pull --rebaseдолжен содержать локальный каталог в чистоте, когда

  1. имеютmodifiedфайл состояния

Когда есть изменения в файле под локальным управлением версиями, выполните указанную выше команду:

$ git pull --rebase

# 结果如下
error: cannot pull with rebase: You have unstaged changes.
error: please commit or stash them.

Вышеупомянутая ошибка появится и не может работать.

Проверьте статус файла на этом этапе:

$ git status

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

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

	modified:   two.md

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

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

  • Если эта версия была завершена, вы можете сначала отправить ее (commit)немного
  • Если эта модификация не была завершена, вы можете сначала сохранить ее:git stash

После выполнения одной из вышеуказанных операций повторите попытку.git pull --rebase, больше не будет сообщать об ошибке.

если сделаноgit stashоперация, вы можетеgit stash popвернуться в предыдущее рабочее состояние.

  1. имеютUntracked files

Проверьте состояние локального файла:

$ git status

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

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

	three.md

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

Если это так, выполните непосредственноgit pull --rebaseПроблем не будет.

4.2 Если есть конфликт, вы можете разрешить конфликт вручную и продолжитьrebase, вы также можете отказаться от этогоrebase

В приведенном выше примере проекта, если учащиеся A и B изменили один и тот же файл. Тогда очень вероятно, что будут конфликты.Когда одноклассник Б придет выполнять команду, произойдет следующая ситуация:

$ git pull --rebase

# 结果如下
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From gitlab.lrts.me:fed/gitlab-merge
   93a1a93..960b5fc  master     -> origin/master
First, rewinding head to replay your work on top of it...
Applying: feat: 其他功能提交
Using index info to reconstruct a base tree...
M	one.md
Falling back to patching base and 3-way merge...
Auto-merging one.md
CONFLICT (content): Merge conflict in one.md
error: Failed to merge in the changes.
Patch failed at 0001 feat:其他功能提交
hint: Use 'git am --show-current-patch' to see the failed patch

Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".

В этом случае вы можете вручную открытьone.mdфайл для разрешения конфликтов перед выполнением:

$ git add one.md

$ git rebase --continue

Решать проблему.

также можно использоватьgit rebase --abortОткажитесь от этой операции перебазирования.

5. Резюме

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

# 把本地发生改动的文件贮藏一下
$ git stash

# 把远程最新的 commit 以变基的方式同步到本地
$ git pull --rebase

# 把本地的 commit 推送到远程
$ git push

# 把本地贮藏的文件弹出,继续修改
$ git stash pop