Git: Как поменять местами 2 ветки, локальную и удаленную (Github)

Может ли кто-нибудь дать четкий и простой способ поменять местами имена в 2 ветках с помощью Git, используя Github в качестве удаленного репозитория?

Вот сценарий:

  1. Я создал ветку dev от мастера.
  2. После 1 коммита на dev я создал ветку exp (эксперимент).
  3. Я снова проверил dev и сделал еще 2 коммита.
  4. Затем я понял, что действительно хочу, чтобы exp была веткой, которая сделала эти 2 коммита, поэтому я хотел бы поменять местами exp и dev.

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


Мои плохие попытки исправить это:

Я пробовал несколько вещей и все испортил - переименовал локальные ветки с помощью Git Extensions, но не смог заставить удаленный репозиторий Github отразить это изменение. Я пытался создавать новые ветки, но не всегда могу заставить их отражаться как локально, так и удаленно (независимо от того, где я их делаю).

Наконец-то я смог получить все, что мне было нужно, с помощью основной функции Git Extensions pull с «Prune remote branch», которая, по-видимому, использует fetch с --prune — это отражало удаленные удаления обратно на локальные, а также функцию push с включенными некоторыми параметрами принудительного/удаления.

Сначала я подумал, что могу просто сбросить/переместить обе ветки (т. е. переместить exp до dev, а затем сбросить exp обратно до фиксации, на которой находился dev (2 назад), но при попытке сбросить в Git Extensions он спрашивает мне выбрать мягкий, смешанный или полный сброс - это заставило меня остановиться и пойти другим путем, пытаясь переименовать / создать новые ветки и т. д. Возможно, это был правильный путь - если да, должен ли я сделать мягкий или жесткий reset - или это не имеет значения после внесения каких-либо открытых изменений?Я много искал по этому поводу, и даже понимая рабочий каталог, индекс и ветку, в моем случае это все еще не было ясно.


Вопрос

Должны быть лучшие способы сделать это — как я могу легко поменять местами две ветки (или переименовать 2 ветки, чтобы они эффективно менялись местами), чтобы все изменения отражались как локально, так и удаленно (на Github)?

Я был бы признателен за любое понимание того, почему ваш метод является правильным или самым простым способом. Спасибо!


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


person LightCC    schedule 07.08.2017    source источник


Ответы (3)


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

Я думаю, что проще всего будет переместить коммиты, а не пытаться переименовать ветки. Одним из простых способов было бы выбрать два коммита из dev в exp, а затем удалить два коммита из dev.

git checkout exp
git cherry-pick <SHA-1 of first dev commit>
git cherry-pick <SHA-2 of first dev commit>

А затем удалите два коммита из dev:

git checkout dev
git reset --hard HEAD~2

Обратите внимание, что если вы уже отправили dev на GitHub и кто-то другой мог получить ветку, вам следует вместо этого отменить два коммита:

git checkout dev
git revert A^..B

Здесь A — первая фиксация, а B — вторая фиксация. Обратите внимание, что git revert добавляет новую фиксацию, которая в данном случае функционально отменяет две фиксации в dev, которые вы хотите удалить. Таким образом, dev закончилось бы тремя фиксациями, но это было бы так, как если бы две фиксации в exp никогда не были сделаны в dev.

person Tim Biegeleisen    schedule 07.08.2017
comment
Спасибо - я даже не рассматривал осложнение кого-то уже потянуло. Можете ли вы объяснить, почему вы используете параметр --hard в сбросе? - person LightCC; 07.08.2017
comment
@LightCC Выполнение аппаратного сброса перемещает HEAD ветки обратно в коммит twk, а также сбрасывает этап и рабочий каталог для этого коммита. Следовательно, это действительно похоже на уничтожение двух коммитов. - person Tim Biegeleisen; 08.08.2017
comment
Итак, коммиты уже безопасны, потому что они находятся в ветке exp, но с точки зрения ветки dev вы хотите полностью сбросить до exp~2, без поэтапных или неустановленных изменений. Если бы вместо этого я хотел оставить эти 2 коммита изменений доступными для изменения, повторного размещения и повторной фиксации (как часть новой ветки dev, отдельно от exp), тогда я мог бы использовать --soft, верно? - person LightCC; 08.08.2017
comment
@LightCC Да, выполнение мягкого сброса, предполагая, что ваш текущий рабочий каталог пуст и этап также пуст, был бы способом повторно зафиксировать эти два коммита позже, возможно, с добавлением некоторых новых изменений. - person Tim Biegeleisen; 08.08.2017

Создайте две новые ветки exp2, dev2 из exp и dev соответственно.

$ git checkout exp
$ git branch exp2          # create new branch 'exp2' from 'exp'

$ git checkout dev
$ git checkout -b dev2     # create and checkout to `dev2` branch

Удалите свои локальные и удаленные ветки dev и exp.

$ git branch -D dev        # delete local 'dev' branch
$ git push origin :dev     # delete remote 'dev' branch

$ git branch -D exp        # delete local 'exp' branch
$ git push origin :exp     # delete remote 'exp' branch

Создайте новую локальную ветку exp из dev2 и нажмите на удаленную.

# make sure you are in 'dev2' branch

$ git checkout -b exp
$ git push origin exp

Создайте новую локальную ветку dev из exp2 и нажмите на удаленную.

$ git checkout exp2        # checkout to 'exp2' so, current branch is 'exp2'
$ git checkout -b dev      # create new branch 'dev' 
$ git push origin dev      # push 'dev' branch to remote 

Теперь, если все в порядке, удалите локальные ветки exp2 и dev2. (По желанию)

$ git branch -D dev2      # delete local 'dev2' branch
$ git branch -D exp2      # delete local 'exp2' branch 
person Sajib Khan    schedule 07.08.2017
comment
Привет Саджиб - спасибо. Это выходит за рамки того, что мне нужно для моего примера, но это показывает, как полностью поменять местами две ветки. Это полезный, если не самый простой ответ. - person LightCC; 08.08.2017

Предположим, история фиксации, которую вы описали, как показано ниже:

A---B---…  master
     \
      C---D---E  dev
      |
     exp   

Вы можете использовать следующие команды:

git checkout exp
git merge dev
git push origin exp
git checkout dev
git reset --hard head~2
git push -f origin dev

Тогда история коммитов будет такой:

A---B---…  master
     \
      C    dev
       \
        D---E   exp

Конечно, вы можете переименовывать имена веток, но этот способ более эффективен.

Примечание: если вы работаете совместно с другими и в ветке dev есть новые изменения, вы можете сначала сделать резервную копию изменений в новой ветке, такой как temp, git pull origin dev и git checkout -b temp origin/dev. После замены вашего локального exp на dev вы можете выбрать или объединить изменения других разработчиков с temp на dev.

person Marina Liu    schedule 07.08.2017
comment
Я думаю, вам следует добавить кавиат на случай, если dev уже транслировалось публично. - person Tim Biegeleisen; 07.08.2017
comment
@TimBiegeleisen Хорошо, спасибо за напоминание, и я добавил эту ситуацию. - person Marina Liu; 07.08.2017