Почему git rebase отбрасывает мои коммиты?

Я пытаюсь перебазировать ветку поверх master, что я уже делал тысячу раз. Но сегодня он не работает:

> git status
On branch mystuff
Your branch and 'master' have diverged,
and have 6 and 2 different commits each, respectively.
  (use "git pull" to merge the remote branch into yours)

nothing to commit, working directory clean

> git rebase
First, rewinding head to replay your work on top of it...

> git status
On branch mystuff
Your branch is up-to-date with 'master'.

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

    [a directory from the project]

nothing added to commit but untracked files present (use "git add" to track)

>

Все начинается как обычно, но затем Git завершает перебазирование, не помещая туда ни одного из моих коммитов; моя ветка mystuff оказывается на том же коммите, что и master.

Очевидным выводом будет то, что мои коммиты уже где-то в мастере. Но это нет, клянусь. Я вернулся к истории. Коммиты есть в паре других веток функций, но их нигде нет в истории master. (И я все равно могу сказать, что они не в мастере по состоянию файлов, когда я извлек мастер.)

Итак, если коммитов еще нет в моей восходящей истории, почему еще git rebase отказывается размещать мои коммиты сверху?

Как ни странно, если я выбираю коммиты на мастер один за другим, это работает. И тогда я могу переместить свою ветку mystuff в конец и вернуть master туда, где она была. (Но зачем мне это нужно было делать именно так?)

ИЗМЕНИТЬ:

В документации по git rebase сказано следующее:

Текущая ветвь сбрасывается на <upstream> или <newbase>, если была указана опция --onto. Это имеет тот же эффект, что и git reset --hard <upstream> (или <newbase>). ORIG_HEAD указывает на конец ветки перед сбросом.

Коммиты, которые ранее были сохранены во временной области, затем повторно применяются к текущей ветке, один за другим, по порядку. Обратите внимание, что любые фиксации в HEAD, которые вносят те же текстовые изменения, что и фиксация в HEAD..<upstream>, опускаются (т. е. уже принятый вышестоящий патч с другим сообщением о коммите или отметкой времени будет пропущен).

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

Конфигурация моих веток:

[branch "master"]
    remote = origin
    merge = refs/heads/master
[branch "mystuff"]
    remote = .
    merge = refs/heads/master

person Ryan Lundy    schedule 01.04.2014    source источник
comment
Что такое git status после возвращения git rebase?   -  person lrineau    schedule 01.04.2014
comment
Что происходит, когда вы делаете git rebase master или git rebase master <branch>?   -  person    schedule 01.04.2014
comment
Возможно ли совместное использование всего каталога? Если вы что уверены, что делаете все правильно, это может помочь найти ошибку или что-то еще.   -  person mgarciaisaia    schedule 01.04.2014
comment
@ Ирино, посмотри правку. Неотслеживаемый каталог связан с тем, что одним из коммитов, которые не были перебазированы, было изменение .gitignore для игнорирования этого каталога.   -  person Ryan Lundy    schedule 01.04.2014
comment
@Cupcake, хороший вопрос. git rebase и git rebase --onto master не работают, как указано выше... но git rebase master работает! Но почему? Если master является восходящим потоком, то git rebase должен работать без аргумента ветки, не так ли?   -  person Ryan Lundy    schedule 01.04.2014
comment
Можете ли вы включить конфигурацию git для вашей ветки mystuff?   -  person joshtkling    schedule 01.04.2014
comment
@joshtkling, конечно. См. выше.   -  person Ryan Lundy    schedule 02.04.2014
comment
Не подсказка, исходя из этого. Я не вижу веских причин, по которым git rebase будет вести себя иначе, чем git rebase master.   -  person joshtkling    schedule 02.04.2014
comment
Какую версию git вы используете? Недавно было выпущено несколько обновлений/исправлений для перебазирования последних двух версий git, которые могут помочь.   -  person onionjake    schedule 03.04.2014
comment
@onionjake, 1.9.0.msysgit.0. Я просмотрел недавние заметки о выпуске, чтобы узнать, есть ли что-нибудь важное, но я ничего не нашел.   -  person Ryan Lundy    schedule 03.04.2014
comment
Не нужно ругаться. Просто проверьте свою ветку и запустите 'git cherry origin/master'. Он сообщит вам, если ваши коммиты уже находятся в источнике/мастере.   -  person the.malkolm    schedule 08.04.2014
comment
Еще одно подтверждение того, что это работало: я использую Jenkins для сборки на своем компьютере, и у меня было всего git rebase на шаге после извлечения из нашего основного репозитория. Мне никогда не приходилось говорить, какая ветвь. Я использую это с конца 2013 года без проблем до недавнего времени.   -  person Ryan Lundy    schedule 08.04.2014
comment
Я предлагаю сделать синхронизацию с основной веткой: git pull --rebase master   -  person enrique-carbonell    schedule 23.04.2014
comment
Похоже на ошибку в git, вызванную использованием remote = .. Я бы предложил сделать git fsck, и если ничего не получится, попробуйте сообщить об этом разработчикам git. Если вы не можете поделиться с ними всем репо, я думаю, у них могут быть какие-то скрипты для анонимизации копии репо.   -  person Mikko Rantalainen    schedule 12.05.2014
comment
Попробуйте указать ветку rebase в коммите rebase.   -  person Mohanraj    schedule 18.05.2014
comment
Я бы попытался сделать git rebase -i origin/master, где -i означает интерактивный, чтобы увидеть, какие коммиты отображаются в списке.   -  person Namek    schedule 11.07.2014
comment
Я предполагаю, что вы начали вносить изменения в ветке master, поняли это, сделали git checkout -tb topic && git branch -f master HEAD~... && git rebase. Кстати, мне интересно, почему вы хотели бы иметь master и topic вверх по течению...   -  person x-yuri    schedule 14.01.2021
comment
@x-yuri Нет, я этого не делал.   -  person Ryan Lundy    schedule 14.01.2021


Ответы (3)


Это укусило меня по крайней мере дюжину раз после определенного обновления git. Теперь есть различие между git rebase и git rebase master: первый был изменен, чтобы использовать тот же причудливый механизм "вилки". В ответе на этот вопрос есть подробное объяснение:

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

МОЙ СЦЕНАРИЙ: у меня есть 4 коммита на master, которые я решил теперь переместить в ветвь topic, плюс я хочу изменить их порядок. Если я сделаю это так...

  1. Создать новую ветку topic, отслеживая текущую ветку (master)

    git checkout -b topic -t
    
  2. Перемотать master назад:

    git checkout master
    git reset --hard origin/master
    
  3. Изменить порядок коммитов на topic

    git checkout topic
    git status  # "Your branch is ahead of 'master' by 4 commits" Good!
    git rebase --interactive
    

... затем интерактивный экран перебазирования показывает этот зловещий список коммитов:

    # no-op

О-о... Я сохраняю файл и продолжаю. Да, похоже, мерзавец снова выбросил мою работу. topic теперь указывает на ту же фиксацию, что и master и origin/master.

Итак, я предполагаю, что вызвало это для вас:

  1. обновление git

  2. Вы сделали что-то вроде моего шага 2 в своей ветке master.

В моем непрофессиональном понимании механизм fork-point просматривает reflog и замечает, что эти коммиты были удалены из вышестоящей ветки, и приходит к выводу, что для обновления вашей тематической ветки они должны быть удалены и там. .

Решение вместо:

git rebase

Используйте один из:

git rebase --no-fork-point
git rebase master

Но я подозреваю, как и я, вы бы не стали делать это каждый раз. (Я имею в виду, что мы установили восходящую ветвь по какой-то причине, верно?) Таким образом, вы просто научитесь распознавать, когда происходит эта катастрофа, использовать git reflog и git reset --hard для восстановления, а затем использовать приведенную выше команду.

Тем не менее, вам нужно быть осторожным сейчас - я думаю, что это чрезвычайно опасно. У меня были времена, когда я переустанавливал большую ветку, и несколько коммитов молча исчезали с самого начала, и я не замечал этого в течение нескольких дней! Мне довольно удобно майнить git reflog для аварийного восстановления, но я не уверен, что все так. Интересно, не стал ли git быть слишком умным здесь.

person Luke Usherwood    schedule 30.11.2016
comment
Следующий вопрос: есть ли параметр конфигурации git, чтобы изменить поведение обратно? (Дополнительные баллы: может быть, только для местных филиалов?) Я не смог найти ни одного упоминания при поиске git help. - person Luke Usherwood; 30.11.2016
comment
Ага! Да, это это проблема. Это может быть изменено с уведомлений о том, что коммиты были удалены оттуда, на уведомления о том, что коммиты ранее были совмещены с восходящим потоком, а затем предполагается их там заменили «улучшенными копиями». Автоматической опции --no-fork-point нет, но вы можете добавить ее: см. сценарий перебазирования, около строки 454, с test "$fork_point" = auto && fork_point=t. Замените на, если установлено значение auto, проверьте в конфигурации окончательное значение. - person torek; 30.11.2016
comment
--no-fork-point не изменило результат для меня, но это объяснение все еще было полезным. после восстановления моего коммита с помощью reflog я просто перебрал свой коммит в новую ветку, которую я сделал из master. - person allieferr; 03.10.2018
comment
В конце концов, я избегаю этого, используя псевдоним git reup для обозначения git rebase @{u} и просто никогда не выполняя перебазирование без вызова этого псевдонима или указания другой восходящей ветки. - person Ryan Lundy; 13.01.2021
comment
Почему вы сделали master восходящим потоком topic? о.о - person x-yuri; 14.01.2021
comment
@x-yuri Потому что в конечном итоге тема будет объединена с основной. Я не уверен, что вас смущает в этом. - person Ryan Lundy; 14.01.2021
comment
@RyanLundy Ну, обычно восходящие потоки - это удаленные ветки. Какие преимущества дает ваша установка? - person x-yuri; 14.01.2021
comment
@x-yuri Я все еще могу легко нажать на пульт: git push origin. Пока у меня указана восходящая ветвь, даже если это другая локальная ветвь, а не удаленная, Git с радостью перейдет из моей локальной ветки в удаленную ветку с совпадающим именем. Таким образом, я могу видеть, где я нахожусь по отношению к ветке, в которую я в конечном итоге сольюсь (с git status), в то время как я могу без проблем нажать на удаленный. - person Ryan Lundy; 14.01.2021

Запустите git branch -vv, чтобы увидеть восходящие ветки. Похоже, ваш апстрим для mystuff не то, что вы думаете. Может быть, у вас произошел несчастный случай при редактировании, и в вашей конфигурации появилось несколько записей [branch "mystuff"]?

person Jack O'Connor    schedule 01.08.2014

Сам собирался задать этот вопрос, но как попытался задать, нашел ответ.

Есть 2 ситуации, в которых вы можете оказаться, когда вам понадобится перебазирование. Рассмотрим следующую историю:

A---B---C master

Соавтор №1 изменяет коммит C, добавляет коммит D и делает git push -f:

A---B---C'---D master

Соавтор №2 добавляет коммит E и делает git fetch:

A---B---C'---D origin/master
     \
      C---E master

Можно сказать, что В — последний общий предок, С и С' различаются, я хочу сохранить все изменения. Тогда ваша ожидаемая история:

A---B---C'---D---C"---E" master

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

A---B---C'---D---E" master

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

Первый режим выбирается, когда вы явно указываете восходящий поток:

$ git rebase origin/master

Последний (режим --fork-point):

$ git -c pull.rebase=true pull
$ git pull --rebase
$ git rebase
$ git rebase --fork-point origin/master

Более подробное описание приведено здесь. скрипт, воспроизводящий проблему.

person x-yuri    schedule 13.01.2021