git: лучший способ возврата git без дополнительного отмененного коммита - PullRequest
8 голосов
/ 06 октября 2009

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

По сути, сейчас у меня есть:

           D---E---F---G master

И я хочу:

             E---G topic
            /
           D master

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

Какой самый чистый способ получить это?

Кроме того, есть и другие люди, которые клонировали этот репозиторий и проверили основную ветку. Если бы я сделал такое изменение в удаленном репо, сработал бы «git pull», чтобы они также могли перейти в то же состояние?

Ответы [ 3 ]

7 голосов
/ 06 октября 2009

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

Если вы планируете в какой-то момент в будущем объединить topic в master, то, вероятно, вы также захотите создать новую общую базу между master и topic, чтобы при затем объедините topic, вы не потеряете коммиты, которые были возвращены в master. Самый простой способ сделать это - сделать коммит 'redo' поверх коммита 'undo', который сбрасывает master обратно в исходное состояние и основывает новую ветвь topic поверх этого.

# checkout master branch (currently at G)
git checkout master

# Reset the index to how we want master to look like
git reset D

# Move the branch pointer back to where it should be, leaving the index
# looking like D
git reset --soft HEAD@{1}

# Make a commit (D') for the head of the master branch
git commit -m "Temporarily revert E, F and G"

# Create the new topic branch based on master.
# We're going to make it on top of master and the 'undo'
# commit to ensure that subsequent merges of master->topic
# or topic->master don't merge in the undo.
git checkout -b topic

# Revert the undo commit, making a redo commit (G').
git revert HEAD

В качестве альтернативы вы могли бы сделать коммиты E ', F' и G ', переделывая каждую часть в отдельности, но, поскольку E, F и G уже есть в вашей опубликованной истории, вероятно, более понятно, если вы просто ссылаетесь на коммит' undo 'и сказать, что этот коммит отменяется. Это то, что git revert делает, так или иначе.

По сути, вы знаете, что это.

D -- E -- F -- G -- D'      <-- master
                     \
                      \
                        G'  <-- topic

Важно то, что вы не переписали историю, а тема основана на master, поэтому слияния не будут случайным образом применять любые 'отмены' коммитов. Теперь вы можете безопасно нажать master и topic в удаленном хранилище.

4 голосов
/ 06 октября 2009

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

При этом я должен подчеркнуть, что делать это безответственно, если у кого-то еще есть эта история. Вам придется принудительно перенести его в центральный репозиторий, а всем остальным придется установить соответствие своих репозиториев, что может быть относительно простым или сложным в зависимости от обстоятельств.

На странице руководства git-rebase есть хороший раздел под названием "восстановление после восходящего потока", в котором обсуждается, как с этим справиться, если вы действительно решите.

Edit:

Для простой истории обычным сценарием было бы, после принудительного ускоренного форсирования в центральном репо (push -f), другие разработчики:

  • Резервное копирование своего старого мастера: git branch -m master master_old
  • получение обновлений и воссоздание мастера из источника: git remote update origin; git branch master origin/master
  • перебазировать все ветки темы на нового мастера: git rebase --onto master master_old topic

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

0 голосов
/ 30 апреля 2010

Я считаю git stash довольно полезным

Просто спрятать его и больше никогда не смотреть на него.

...