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
должен содержать локальный каталог в чистоте, когда
- имеют
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
вернуться в предыдущее рабочее состояние.
- имеют
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