Обновления были отклонены, потому что кончик вашей текущей ветки позади - но почему?

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

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

   git clone git@github.com:joyofdata/test3.git
   cd test3
   echo "1" > m
   git add .
   git commit -m "m1"
   git push origin master

   git checkout -b feature
   git push -u origin feature
   echo "1" > f
   git add .
   git commit -m "f1"
   git rebase master
   git push origin feature

   git checkout master
   echo "2" >> m
   git add .
   git commit -m "m2"
   git push origin master

   git checkout feature
   echo "2" >> f
   git add .
   git commit -m "f2"
   git rebase master
   git push origin feature (error - see next code box)

Я просто делаю версию файла m в master, затем файл f в компоненте, затем я фиксирую изменение в master, затем я фиксирую изменение в компоненте. Теперь, прежде чем перейти к удаленной ветви функций, я хочу перебазировать ее на master.

Это команда и сообщение об ошибке последней команды в приведенном выше списке:

➜  test3 git:(feature) git push origin feature
To github.com:joyofdata/test3.git
 ! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to 'git@github.com:joyofdata/test3.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

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

➜  test3 git:(feature) git pull origin feature
From github.com:joyofdata/test3
 * branch            feature    -> FETCH_HEAD
Auto-merging f
CONFLICT (add/add): Merge conflict in f
Automatic merge failed; fix conflicts and then commit the result.

➜  test3 git:(feature) ✗ vim f
➜  test3 git:(feature) ✗ git add .
➜  test3 git:(feature) git commit -m "deconflicted"
[feature 3fb647e] deconflicted

➜  test3 git:(feature) git push origin 
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 565 bytes | 565.00 KiB/s, done.
Total 5 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To github.com:joyofdata/test3.git
   0f31f60..3fb647e  feature -> feature

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

➜  test3 git:(feature) git rebase master
First, rewinding head to replay your work on top of it...
Applying: f1
Applying: f1
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.
Applying: f2

➜  test3 git:(feature) git push origin  
To github.com:joyofdata/test3.git
 ! [rejected]        feature -> feature (non-fast-forward)
error: failed to push some refs to 'git@github.com:joyofdata/test3.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Я не понимаю!

Я имею в виду, что я хочу просто применить следующий рабочий процесс:

  • изменить в локальной ветви функций
  • поставить и совершить это изменение
  • git rebase master
  • особенность git push origin

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

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

Всего 2 ответа


Корень проблемы в том, что вы перебираете свою feature . Это небрежный способ выразить это: важно не имя ветки , а коммиты . Но rebase работает путем копирования некоторых коммитов в новые и (предположительно) улучшенные коммиты. Для этого нужно выбросить - или отказаться - старые (и теперь паршивые) коммиты.

Команда git push вызывает другой Git и отправляет им ваши новые и улучшенные коммиты, а затем просит другой репозиторий Git выбросить свои старые (и теперь паршивые) коммиты. Это говорит: нет! Если я попрошу вас спросить, я потеряю некоторые драгоценные коммиты! Эта жалоба возвращается в этой форме:

 ! [rejected]        feature -> feature (non-fast-forward)

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

Конечно, именно это вы и хотите . Примечание: следует ли вам делать это, зависит от того, согласились ли все остальные, кто использует этот другой репозиторий Git - тот, что на GitHub, - что это произойдет.

Чтобы другой Git, один из GitHub, согласился отклонять коммиты из своего репозитория, вы должны установить «флаг принудительного применения» для этой конкретной операции git push . Однако есть два различных типа флага силы:

  • Общая сила: я приказываю вам, другому Git-репозиторию, установить имя вашей ветки таким образом! Это просто и эффективно, и отбрасывает не только старые и паршивые коммиты, которые вы заменили новыми и улучшенными коммитами через rebase, но также и любые другие коммиты, добавленные кем-то еще, которые вы также не заменили новой и улучшенной копией. (Это одна из нескольких причин того, что каждый, кто использует этот репозиторий GitHub, должен заранее договориться о том, что произойдет перебазировка.)

  • Принудительное использование: я приказываю вам, другому Git-репозиторию, сравнить хеш-идентификатор, хранящийся в имени вашей ветви, со значением, которое, я думаю, у вас есть. Если они равны, вам следует заменить это значение новым значением, которое я сейчас предоставляю. Этот вариант принудительного нажатия более безопасен: если вы отменили некоторые коммиты, но с тех пор кто-то еще добавил новые коммиты, которые вы не смогли перебазировать, ваша операция принудительного лизинга завершится неудачей. Другой Git, находящийся на GitHub, скажет: «Хеш-идентификатор, который я сохранил, не совпадает с тем, который, как вы сказали, вы думали, я имел. Поэтому я не принял вашу команду в конце концов.

Если вы и все другие пользователи этого репозитория GitHub заранее договорились о том, что может произойти перебазировка, и вы думаете, что кто-то мог прокрасться за несколько коммитов, пока вы не искали, вы должны использовать опцию --force-with-lease чтобы git push чтобы узнать, так ли это на самом деле.

Если в репозитории GitHub нет других пользователей (или никто из них не использует ветку возможностей), это не требуется, и вы можете просто использовать git push --force . Единственный человек, с которым вам нужно согласиться, - это вы сами: вы даете себе разрешение принудительно нажать на ветку feature ? Если это так, вы можете принудительно нажать ветвь feature .

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


Быстрый ответ - не перебазировать ветки вверх по течению, эта ссылка объясняет проблему и решение: https://git-scm.com/docs/git-rebase#_recovering_from_upstream_rebase

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

$ git log --pretty=oneline --graph --all
* b5b045591ec6584e8f896d85399b7ed5b08d8098 (HEAD -> feature) f2
* 5187c95d6d91b550b9b2cc10ad673a52add620f6 f1
* cea62f3fd0349390115ee5e263730656b7a52d2d (origin/master, master) m2
| * f043b50940593c1ded4631f3681420ad57c0b190 (origin/feature) f1
|/
* 4847339d95d8f02c25538da7e51be14cbb30530d m1

когда выполнить

$ git push origin feature

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

Таким образом, вы можете удалить источник / функцию удаленной ветви

  1. Unset upstream

    $ git checkout feature
    $ git branch --unset-upstream
    
  2. Удалить удаленную ветку

    $ git push origin --delete feature
    
  3. Нажмите ваши изменения добавив вверх по течению

    $ git push -u origin feature
    

Ветвь заканчивается так

$ git log --pretty=oneline --graph --all
* b5b045591ec6584e8f896d85399b7ed5b08d8098 (HEAD -> feature) f2
* 5187c95d6d91b550b9b2cc10ad673a52add620f6 f1
* cea62f3fd0349390115ee5e263730656b7a52d2d (origin/master, master) m2
* 4847339d95d8f02c25538da7e51be14cbb30530d m1

Согласно этому примеру, коммит b5b045 имеет изменения коммита f043b50, поэтому изменения не теряются, вы можете проверить с помощью

$ git diff f043b50 b5b045

Есть идеи?

10000