Переименование веток удаленно в Git

408

Если есть репозиторий, к которому у меня есть git://доступ только (и обычно это просто push + pull), есть ли способ переименовать ветки в этом репозитории так же, как я делал бы локально git branch -m?

КДТ
источник
48
Связанный «дублирующий» вопрос просит переименовать ветку «как локально, так и удаленно». Этот вопрос, однако, только спрашивает, как переименовать ветки удаленно, что позволяет упростить. Это то , что я делаю , чтобы переименовать ветку на сервере без необходимости проверки и / или создать локальную ветвь: git push origin origin/old_name:refs/heads/new_name && git push origin :old_name.
Щуберт
1
@sschuberth: вы можете дать обе команды за один раз. И это действительно должно быть ответом на этот вопрос.
Иоахим Брейтнер
2
@JoachimBreitner Вы правы, я выполнил эту оптимизацию уже в моем сценарии .
Щуберт
1
@sschuberth, вы должны опубликовать свой комментарий в качестве ответа, так как он мне нравится больше, чем остальные ниже.
phatmann
Готово .
Щуберт

Ответы:

481

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

$ git branch new-branch-name origin/old-branch-name
$ git push origin --set-upstream new-branch-name
$ git push origin :old-branch-name

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

$ git fetch origin
$ git remote prune origin

ПРИМЕЧАНИЕ. Если ваша старая ветка является вашей основной веткой, вам следует изменить настройки основной ветки. В противном случае при запуске $ git push origin :old-branch-nameвы получите сообщение об ошибке «удаление текущей ветки запрещено» .

Сильвен Дефресне
источник
8
Ну, если старое и новое имена совпадают, то это означает, что вам не нужно переименовывать ветку, поэтому нет смысла запускать команду в первую очередь ;-)
Sylvain Defresne
9
Конечно. Я просто имею в виду, что если вы вызываете это автоматически (как часть какого-то другого скрипта), вы можете не делать этого неправильно, если можете избежать этого.
Таинственный Дан
9
Путь Дэна: изменить порядок команд, чтобы они всегда работали. Путь Earth Engine: всегда не забывайте проверять, иначе вы потеряете данные. Я знаю, какой бы я выбрал.
Дорадус
2
Пользователи могут просто запустить: git fetch origin --prune(для эффективного извлечения новых веток, а также избавления от ссылок, которые больше не находятся на удаленном компьютере).
DolphinDream
2
Можно использовать -dили --deleteвместо :новых версий git.
Цитракс
285

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

git push <remote> <remote>/<old_name>:refs/heads/<new_name> :<old_name>

Я написал этот скрипт ( git-rename-remote-branch ), который предоставляет удобный ярлык для простого выполнения вышесказанного.

В качестве функции bash:

git-rename-remote-branch(){
  if [ $# -ne 3 ]; then
    echo "Rationale : Rename a branch on the server without checking it out."
    echo "Usage     : $(basename $0) <remote> <old name> <new name>"
    echo "Example   : $(basename $0) origin master release"
    exit 1 
  fi

  git push $1 $1/$2:refs/heads/$3 :$2
}

Чтобы интегрировать комментарий @ ksrb : в основном это делается двумя нажатиями в одной команде: сначала git push <remote> <remote>/<old_name>:refs/heads/<new_name>нажать новую удаленную ветку на основе старой удаленной ветви отслеживания, а затем git push <remote> :<old_name>удалить старую удаленную ветку.

sschuberth
источник
10
Для тех, кому нужен псевдоним этой команды: rename = "! F () {источник происхождения git push / $ 1: refs /heads / $ 2: $ 1;}; f" это можно использовать как> git rename <old_name> < new_name>
Джонатан Шмидт
33
Для тех, кто интересуется, что на самом деле означает эта команда, это, по сути, 2 git push <remote>/<old_name>:refs/heads/<new_name>нажатия, означает нажатие нового пульта, который использует старый пульт в качестве src, а затем git push [space]:<old_name> удаление старого пульта
ksrb
3
Зачем вам нужно использовать refs/heads/name? Разве вы не можете просто использовать nameнапрямую, делая первую команду git push <remote> <remote>/<old_name>:<new_name>?
Дрю Ноакс
6
Нет, потому что удаленная ветвь <new_name>еще не существует. Если ветка не существует, Git требует, чтобы вы использовали полное имя, так как в противном случае <new_name>также можно сослаться на имя тега.
Щуберт
3
Мы используем этот подход в нашей системе сборки. Единственное предостережение, с которым мы сталкиваемся - если оно refs/heads/<new_name> уже существует. Удаление все еще успешно, в результате чего <remote>/<old_name>только удаляется. Некоторые проверки перед рукой могут легко избежать этого.
Апейрон,
172

Первая проверка в ветке, которую вы хотите переименовать:

git branch -m old_branch new_branch
git push -u origin new_branch

Чтобы удалить старую ветку из remote:

git push origin :old_branch
Шашанк Хегде
источник
12
Когда вы перемещаете переименованную ветвь (new_branch) в удаленную (origin), вы также должны установить ее восходящий поток для отслеживания ветви с новым именем (например git push -u origin new_branch), иначе переименованная ветвь (new_branch) продолжит отслеживать origin / old_branch. И как только вы удалите удаленный old_branch, new_branch все равно будет отслеживать origin / old_branch, хотя теперь эта ветвь исчезла.
DolphinDream
@DolphinDream Я отредактировал ответ, включив в него ваши полезные изменения.
mVChr
10

Конечно. Просто переименуйте ветку локально, нажмите на новую ветку и удалите старую.

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

Лили Баллард
источник
1
поэтому при попытке удалить master я попытался $ git clone ../src $ cd src $ git branch notmaster $ git checkout notmaster $ git branch -d master $ git push ../src: master Но он жалуется: назначение refspec не соответствует существующему ref на удаленном сервере и не начинается с refs /, и мы не можем угадать префикс, основываясь на исходном ref. ошибка: не удалось отправить некоторые ссылки на '../alpha/' У пульта действительно есть ветка с именем master
kdt
2

TL; DR

«Переименование» удаленной ветви на самом деле является двухэтапным процессом (не обязательно заказывается):

  • удаление старой удаленной ветки ( git push [space]:<old_name>как объяснил ksrb );
  • нажмите в новую удаленную ветку (разница между парой команд ответов ниже).

Удаление

Я использую TortoiseGit, и когда я впервые попытался удалить ветку через командную строку, я получил это:

$ git push origin :in
  • фатальный: «происхождение» не похоже на git-репозиторий

  • Неустранимый: Не удалось прочитать из удаленного хранилища.

Пожалуйста, убедитесь, что у вас есть правильные права доступа и хранилище существует.

Скорее всего, это связано с тем, что у страницы не загружен закрытый ключ (который TortoiseGit автоматически загружает в страницу ). Более того, я заметил, что команды TortoiseGit не имеют originссылки в них (например git.exe push --progress "my_project" interesting_local:interesting).

Я также использую Bitbucket и, как и другие сетевые онлайн-менеджеры Git (GitHub, GitLab), я смог удалить удаленную ветку напрямую через их интерфейс (страница веток):

Удалить ветку Bitbucket

Тем не менее, в TortoiseGit вы также можете удалить удаленные ветки через Обзор ссылок :

Обзорное меню

Если щелкнуть правой кнопкой мыши на удаленной ветви (список удаленных), появится опция Удалить удаленную ветку :

TortoiseGit удаленная ветка удалить

Нажимать

После удаления старого удаленного филиала я толкнул прямо в новый удаленный филиал через TortoiseGit просто введя новое имя в Remote: поле Нажимает окно и эта ветвь была создана автоматически и отображается в Bitbucket .

Однако, если вы все еще предпочитаете делать это вручную, то, что еще не было упомянуто в этой теме, это -u= --set-upstream.

Из git pushдокументации , -uэто всего лишь псевдоним --set-upstream, так что команды в ответах Сильвиану ( -set-upstream new-branch) и Shashank ( -u origin new_branch) эквивалентны, так как отдаленные реф по умолчанию , чтобыorigin , если никакой другой ссылок не было определено ранее:

  • git push origin -u new_branch= git push -u new_branch из описания документов :

    Если конфигурация отсутствует, по умолчанию используется origin.

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

CPHPython
источник
проблема в том, что ваш пульт не называется origin. Вы должны назвать свой пульт, как вы получаете от запуска команды git remote. Git работает с sshтем, что подразумевает использование открытых + закрытых ключей. Я предполагаю, что Autoload Putty keysTortoiseGit просто автоматически загружает необходимые ключи, чтобы вы вообще могли что-либо делать с вашей удаленной ссылкой. Последнее, что git push -uне является псевдонимом для отправки в удаленную ветвь, это псевдоним для отправки в удаленную ветвь, которая была создана локально, и ее удаленная ссылка еще не имеет этой ветви .
Juanecabellob
1
@juancab -u- это псевдоним --set-upstreamи «если конфигурация отсутствует, по умолчанию используетсяorigin ». Сильвен и Шашанк используют это для продвижения во вновь созданную удаленную ветку . Ключевой вопрос может быть связано с Pageant , не имея его загрузке , когда я пытался git push origin :inна раковине. Так что я не понимаю вашего отрицательного мнения, я просто указал на мои и неадекватные детали в других ответах, объяснил их и решил их.
CPHPython
Вы заявляете неправильные вещи, и большая часть этого ответа не связана с самим вопросом. Если вы указываете, что сработало для вас, я призываю вас ограничить ответ тем, что сработало, и если вы действительно хотите дать объяснение, пожалуйста, сообщите себе лучше. Кстати, -uэто псевдоним для, --set-upstreamно это не псевдоним для продвижения в удаленную ветку, как вы сказали. Чтобы добавить в удаленную ветку, вам нужно однозначно git push <remote>, и, если она еще не удалена, вы добавляете git push -u <remote>. Следовательно, -uиспользуется для создания ссылки на ветку в удаленном режиме.
juanecabellob
1
@juancab, возможно, то, что вы сочли неправильным, было в основном псевдонимом или выбором слов. Я реструктурировал свой ответ и перефразировал его, чтобы дать полное объяснение решения, которое я нашел для переименования удаленной ветви.
CPHPython
Я бы перефразировал это дальше. Теперь это имеет больше смысла, но это все еще слишком долго. Я бы более конкретно отнесся к проблеме, то есть скажу, что для пользователей TortoiseGit предложенные решения не будут работать. Вы рассказываете историю, и это сбивает с толку и заставляет пользователей избегать чтения. Я отредактирую ваш ответ предложением.
juanecabellob
1

Я не знаю почему, но ответ @Sylvain Defresne не работает для меня.

git branch new-branch-name origin/old-branch-name
git push origin --set-upstream new-branch-name
git push origin :old-branch-name

Я должен сбросить восходящий поток и затем снова установить поток. Вот как я это сделал.

git checkout -b new-branch-name
git branch --unset-upstream
git push origin new-branch-name -u
git branch origin :old-branch-name
Артур Брайант
источник
0

Я не знаю, правильно это или неправильно, но я поместил «старое имя» ветви в «новое имя» ветви, а затем полностью удалил старую ветку следующими двумя строками:

git push origin old_branch:new_branch
git push origin :old_branch
EpicPandaForce
источник
Насколько я могу судить, это именно то, что делают все остальные ответы. Ваш ответ просто более краткий.
Прояснитель
-1

Вы можете создать новую ветвь на основе ветки со старым именем. Так же, как это, затем удалите старую ветку, снова !!!введите описание изображения здесь

Побер Вонг
источник
Это GitHub, а не Git. ;)
Bouncner
-4

В добавление к уже приведенным ответам, вот версия, которая сначала проверяет, существует ли новая ветвь (так что вы можете безопасно использовать ее в скрипте)

if git ls-remote --heads "$remote" \
    | cut -f2 \
    | sed 's:refs/heads/::' \
    | grep -q ^"$newname"$; then
    echo "Error: $newname already exists"
    exit 1
fi
git push "$oldname" "$remote/$oldname:refs/heads/$newname" ":$oldname"

(чек от этого ответа )

myzzzl
источник
Я бы использовал git show-ref --quiet --verify -- refs/heads/$new_nameвместо ls-remote | cut | sed | grep.
Энди