Переименуйте главную ветку для локальных и удаленных Git-репозиториев.


821

У меня есть ветка, masterкоторая отслеживает удаленную ветку origin/master.

Я хочу переименовать их master-oldкак локально, так и удаленно. Это возможно?

Что произойдет после переименования удаленной ветви для других пользователей, которые отслеживали origin/master(и которые всегда обновляли свою локальную masterветку через git pull)?
Будет ли они git pullвсе еще работать, или это выдаст ошибку, которую он больше не сможет найти origin/master?

Затем, в дальнейшем, я хочу создать новую masterветку (как локальную, так и удаленную). Опять же, после того, как я это сделал, что теперь будет, если это сделают другие пользователи git pull?

Я думаю, что все это приведет к большим неприятностям. Есть ли чистый способ получить то, что я хочу? Или я должен просто оставить все masterкак есть, создать новую ветку master-newи работать дальше?


2
Рецепт, приведенный в принятом ответе, действительно применяется к ветке с любым именем, но предостережения (как было отмечено) - нет, из-за (по умолчанию) особой роли главной ветви в Git.
Кинан

3
@kynan: я думаю, что я не понимаю. Какие предостережения относятся к мастеру и не применяются к другим веткам? Если бы это была ветка с именем xy и другие люди отслеживали эту ветку, как бы это было иначе?
Альберт

4
Предупреждение о том, что вы не можете нормально удалить удаленного мастера. Это не относится к ответу Аристотеля, так что вы можете пометить его как принятый ответ. Вы правы, любой git push -fвлияет на способность pullиз любой удаленной ветви отслеживания.
Кинан

Вы можете создать новую ветку, master-oldкоторая указывает на тот же коммит, что и предыдущая masterветка. Затем вы можете перезаписать masterветвь с новыми изменениями, делая mergeс oursстратегией. Выполнение слияния работает, когда пульт не допускает внесения изменений без ускоренной передачи. Это также означает, что у других пользователей не будет принудительных обновлений.
день

1
@kynan masterтолько особенный, пока это единственная существующая ветка. Как только у вас есть более одного, все ветви находятся в равных условиях.
jub0bs

Ответы:


615

Самым близким к переименованию является удаление, а затем повторное создание на пульте. Например:

git branch -m master master-old
git push remote :master         # delete master
git push remote master-old      # create master-old on remote

git checkout -b master some-ref # create a new local master
git push remote master          # create master on remote

Однако это имеет много предостережений. Во-первых, ни одна из существующих проверок не узнает о переименовании - git не пытается отслеживать переименования веток. Если нового masterеще не существует, git pull выдает ошибку. Если новый masterбыл создан. тяга будет пытаться слить masterи master-old. Так что, как правило, это плохая идея, если у вас нет сотрудничества со всеми, кто ранее проверял хранилище.

Примечание. Более новые версии git не позволяют удаленно удалять основную ветку по умолчанию. Вы можете переопределить это, установив receive.denyDeleteCurrentзначение конфигурации в warnили ignoreв удаленном хранилище. В противном случае, если вы готовы сразу же создать нового мастера, пропустите git push remote :masterшаг и перейдите --forceк нему git push remote master. Обратите внимание, что если вы не можете изменить конфигурацию пульта, вы не сможете полностью удалить основную ветку!

Это предупреждение относится только к текущей ветви (обычно masterветви); любая другая ветка может быть удалена и воссоздана, как указано выше.


2
ветви - это просто пара (имя, хэш) - ни больше, ни меньше. В ветвях есть reflog, но он никогда не выставляется удаленным клиентам.
bdonlan

122
Я бы создал master-old на удаленном, прежде чем удалить master на удаленном. Я просто параноик
Адам Димитрук

6
Ответ Аристотеля ниже позволяет вам сделать это без удаления мастера, так что я думаю, что это предпочтительнее.
Глиняные Мосты

13
было бы ясно и SAFE , если вы можете использовать new-branch-nameи old-branch-nameвместо master/ master-old, таким образом , это общая проблема.
Jaider

2
Если на удаленную ветку (здесь: master) не ссылаются другие ветви, git может собрать все коммиты на этой ... ну ... «ветке». - Некоторые команды git фарфор вызывают сборку мусора. - Поэтому: сначала создайте новое имя (указывая на тот же коммит), затем удалите старое имя.
Роберт Симер

257

Предполагая, что вы в данный момент master:

git push origin master:master-old        # 1
git branch master-old origin/master-old  # 2
git reset --hard $new_master_commit      # 3
git push -f origin                       # 4
  1. Сначала создайте master-oldветку в originхранилище, основываясь на masterкоммите в локальном хранилище.
  2. Создайте новую локальную ветвь для этой новой origin/master-oldветки (которая будет автоматически настроена как отслеживающая ветвь).
  3. Теперь укажите вашему локальному masterкоммиту, на который вы хотите указать.
  4. Наконец, принудительное изменение masterв originхранилище, чтобы отразить ваш новый локальный master.

(Если вы делаете это любым другим способом, вам потребуется по крайней мере еще один шаг, чтобы убедиться, что master-oldон правильно настроен для отслеживания origin/master-old. Ни одно из других решений, опубликованных на момент написания этой статьи, не включало это.)


11
Это лучший ответ, чем «ответ», я согласен, но для людей, которые пришли сюда, чтобы просто переименовать ветку (не явно мастер), третий шаг не имеет особого смысла.
knocte

Это не имеет абсолютно никакого значения для ответа, находитесь ли вы в masterдругой ветке. Хотя вопрос был плохо назван, он спрашивает о более сложной задаче, чем просто переименование ветви.
Аристотель Пагальцис

3
Это оказалось решением, которое сработало для меня. Я пытался заменить мастера на другую ветку. Я сделал git log -1 origin / what_i_want_as_new_master, чтобы получить $ new_master_commit для шага 3. После нажатия (шаг 4) другие разработчики извлекут и получат сообщения «ваша ветвь впереди мастера на 295 коммитов». Чтобы это исправить, я разослал электронное письмо, сообщающее им о каждом запуске: git pull; git checkout some_random_branch; git branch -D master; мерзавец; мастер проверки git; По сути, им нужно удалить своего локального мастера и вытащить новую версию, иначе они находятся в неправильном месте локально.
nairbv

Вы могли бы сделать это намного проще: предполагая, что они уже включены, masterони могли бы просто сделать так, git fetch && git reset --hard origin/masterчтобы их местность masterбыла такой же, как и у той origin. Я задокументировал это, а также более сложный случай, когда у вас есть локальные коммиты, masterкоторые вы хотите сохранить, в stackoverflow.com/q/4084868
Аристотель Пагальцис

Убедитесь, что в файле удаленной конфигурации указано «denyNonFastforwards = false», или вы получите «remote: error: запрещение пересылки ссылок / заголовков / master (сначала вы должны потянуть)»
gjcamann

160

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

git branch -m old_branch new_branch         # Rename branch locally    
git push origin :old_branch                 # Delete the old branch    
git push --set-upstream origin new_branch   # Push the new branch, set local branch to track the new remote

10
Альтернатива --set-upstreamзаключается в следующем: как только ваша ветка переименована локально и удалена в источнике, просто выполните: git push -u --all
lucifurious

4
Это не будет работать с мастер-веткой, так как git не позволит вам удалить удаленный мастер.
Александр Нето

4
@AlexandreNeto В этом случае вы можете выполнить 3-ю строку перед 2-й, установить для ветви по умолчанию значение new_branchи затем в конечном итоге удалить пульт masterсо 2-й строкой.
Тристан Jahier

3
Удивительно простые шаги. Это лучший ответ на вопрос
сиддхусинг

13
Удалить удаленную ветку git push origin --delete old_branchчуть более читабельно.
ThomasW

35
git checkout -b new-branch-name
git push remote-name new-branch-name :old-branch-name

Возможно, вам придется вручную переключиться на new-branch-nameперед удалениемold-branch-name


Удаляет ли какая-либо часть этого решения локальное имя старой ветки или это отдельное упражнение?
GreenAsJade

4
Я думаю, что в конце должен быть запущен git branch -d old-branch-nameдля удаления локальной старой ветки.
Наби КАЗ

Вы можете нажать изменения только одной команды: git push remote-name new-branch-name :old-branch-name.
Sigod

Таким образом, вы не будете усложнять историю мерзавцев? Потому что вы открываете новую ветку, а просто переименовываете текущую.
андройдвил

1
@androider Нет. Филиалы в git - это простые ссылки .
sigod

29

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

Сначала быстрая картинка: переименование главной ветви и предоставление клиентам возможности быстрой перемотки вперед

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

переименование филиала:

# rename the branch "master" to "master-old"
# this works even if you are on branch "master"
git branch -m master master-old

создание новой "основной" ветки:

# create master from new starting point
git branch master <new-master-start-point>

создание коммита слияния, чтобы иметь историю родитель-потомок:

# now we've got to fix the new branch...
git checkout master

# ... by doing a merge commit that obsoletes
# "master-old" hence the "ours" strategy.
git merge -s ours master-old

и вуаля.

git push origin master

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

используя разумное сообщение коммита слияния:

renamed branch "master" to "master-old" and use commit ba2f9cc as new "master"
-- this is done by doing a merge commit with "ours" strategy which obsoletes
   the branch.

these are the steps I did:

git branch -m master master-old
git branch master ba2f9cc
git checkout master
git merge -s ours master-old

3
Спасибо! git merge -s ours master-oldявляется важной частью, которую пропускают другие ответы. Кроме того, «легко сделать» не означает «легко понять или выяснить», что, по-видимому, имеет место для большинства мерзавцев, но я отвлекся.
Мартин Виднер

3
Мне нравится тот факт, что никакие удаления не упоминаются и что переход для тех, кто работает с клонами апстрима, является "бесшовным". Спасибо!
Пиотрек

12

Я предполагаю, что вы все еще спрашиваете о той же ситуации, что и в предыдущем вопросе . То есть master-new не будет содержать master-old в своей истории. * Если вы называете master-new «master», у вас будет фактически переписанная история. Неважно, как вы попадаете в состояние, в котором мастер не является потомком предыдущей позиции мастера, просто то, что он находится в этом состоянии.

Другие пользователи, пытающиеся получить данные, пока мастер не существует, просто потерпят неудачу в своих попытках (нет такой ссылки на пульте дистанционного управления), и как только они снова появятся в новом месте, их попытки будут пытаться объединить своего мастера с новым удаленным мастером, точно так же, как если бы вы объединили master-old и master-new в своем хранилище. Учитывая то, что вы пытаетесь сделать здесь, слияние может привести к конфликтам. (Если бы они были решены, а результат был перенесен обратно в хранилище, вы оказались бы в еще худшем состоянии - обе версии истории были там.)

Чтобы ответить на ваш вопрос просто: вы должны признать, что иногда в вашей истории будут ошибки. Это нормально. С кем не бывает. В репозитории git.git есть отмененные коммиты. Важно то, что как только мы публикуем историю, это то, что каждый может доверять.

* Если бы это было так, это было бы равносильно внесению некоторых изменений в мастер, а затем созданию новой ветви, где она была раньше. Нет проблем.


Да, это та же проблема, просто была одна идея, как ее решить. Но даже если бы я не делал это переименование ветки, мне было бы интересно, если бы это было возможно. Я думал, что такие ссылки как "master" являются только ссылками на конкретные коммиты. Я действительно не хочу менять историю. Я думал, что просто укажу мастер-ссылку на другую голову. Это также означает, что я никогда не смогу снова использовать имя ветви, если я использовал его раньше?
Альберт

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

8

Выбранный ответ не удалось , когда я попробовал. Он выдает ошибку: refusing to delete the current branch: refs/heads/master. Я думаю, я выложу, что работает для меня:

git checkout master             # if not in master already

git branch placeholder          # create placeholder branch
git checkout placeholder        # checkout to placeholder
git push remote placeholder     # push placeholder to remote repository

git branch -d master            # remove master in local repository
git push remote :master         # remove master from remote repository.

Хитрость заключается в том, чтобы оформить заказ на заполнитель прямо перед отправкой его в удаленный репозиторий. Остальное не требует пояснений, удаление ветки master и ее отправка в удаленный репозиторий должны сработать. Извлеченный из здесь .


При git push remote: master произойдет сбой, если это будет проверено на удаленной стороне - вы увидите «remote: error:» в качестве префикса в строках журнала ошибок.
Рафальмаг

2

Хорошо. Мои 2 цента. Как насчет входа на сервер, перехода в каталог git и переименования ветки в пустом хранилище. Это не имеет всех проблем, связанных с повторной загрузкой той же ветки. Фактически, «клиенты» автоматически распознают измененное имя и изменяют свою удаленную ссылку. После этого (или до) вы также можете изменить локальное имя филиала.


8
Я забыл учетные данные для входа на сервер github. Кто-нибудь с полномочиями там :-P
Даниэль Фишер lennybacon

1

Что о:

git checkout old-branch-name
git push remote-name new-branch-name
git push remote-name :old-branch-name
git branch -m new-branch-name

портит отслеживание веток - пользователям может понадобиться исправить свою ветку локально?
день

1

Это самый простой и «читаемый» способ, который я знаю:

'Переместить' локальную ветку, используя -m

git branch -m my_old_branch_name my_new_branch_name

Нажмите «перемещенную» ветку на пульт, установите «upstream» с помощью -u

git push origin -u my_new_branch_name

(настройка 'upstream', по сути, 'соединяет' вашу локальную ветку с удаленным, так что такие вещи, как fetch, pull и push будут работать)

Удалить старую ветку с пульта

git push origin -D <old_name>

(ваше местное отделение уже ушло, потому что вы «переместили» его на первом этапе)


1

Хорошо , переименовать ветку как локально, так и на удалённом довольно легко! ...

Если вы на ветке, вы легко можете сделать:

git branch -m <branch>

или, если нет, вам нужно сделать:

git branch -m <your_old_branch> <your_new_branch>

Затем отправьте удаление на пульт, как показано ниже:

git push origin <your_old_branch>

Теперь вы сделали, если вы получаете ошибку апстрима, когда пытаетесь нажать, просто выполните:

git push --set-upstream origin <your_new_branch>

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

введите описание изображения здесь


0

Вы можете сделать следующее:

git -m master master-old #rename current master
git checkout -b master   #create a new branch master
git push -f origin master #force push to master

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


0

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

Например:

remote="origin"

if [ "$#" -eq 0 ] # if there are no arguments, just quit
then
    echo "Usage: $0 oldName newName or $0 newName" >&2
    exit 1
elif
    [ "$#" -eq 1 ] # if only one argument is given, rename current branch
then 
    oldBranchName="$(git branch | grep \* | cut -d ' ' -f2)" #save current branch name
    newBranchName=$1
else
    oldBranchName=$1
    newBranchName=$2
fi

git branch -m $oldBranchName $newBranchName

git push $remote :$oldBranchName #delete old branch on remote
git push --set-upstream $remote $newBranchName # add new branch name on remote and track it

Обратите внимание, что здесь удаленное имя по умолчанию «origin» задано жестко, вы можете расширить сценарий, чтобы сделать его настраиваемым!

Затем этот сценарий можно использовать с псевдонимами bash, псевдонимами git или, например, в пользовательских действиях на sourcetree.


-1

Я считаю , что ключ является осознанием того, что вы выполняете двойное переименование: masterк , master-oldа также master-newв master.

Из всех других ответов я синтезировал это:

doublerename master-new master master-old

где мы сначала должны определить doublerenameфункцию Bash:

# doublerename NEW CURRENT OLD
#   - arguments are branch names
#   - see COMMIT_MESSAGE below
#   - the result is pushed to origin, with upstream tracking info updated
doublerename() {
  local NEW=$1
  local CUR=$2
  local OLD=$3
  local COMMIT_MESSAGE="Double rename: $NEW -> $CUR -> $OLD.

This commit replaces the contents of '$CUR' with the contents of '$NEW'.
The old contents of '$CUR' now lives in '$OLD'.
The name '$NEW' will be deleted.

This way the public history of '$CUR' is not rewritten and clients do not have
to perform a Rebase Recovery.
"

  git branch --move $CUR $OLD
  git branch --move $NEW $CUR

  git checkout $CUR
  git merge -s ours $OLD -m $COMMIT_MESSAGE

  git push --set-upstream --atomic origin $OLD $CUR :$NEW
}

Это похоже на изменение истории git rebaseв том смысле, что содержимое ветви совершенно иное, но отличается тем, что клиенты все еще могут безопасно переходить вперед git pull master.


-5
git update-ref newref oldref
git update-ref -d oldref newref

2
Кажется, это не работает для меня, я получаю: git update-ref trunk trunk2 fatal: trunk2: недопустимый SHA1
Gregg Lind
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.