Перейменуйте головну гілку як локальних, так і віддалених сховищ Git


820

У мене є гілка, 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стратегією. Злиття працює тоді, коли пульт не дозволяє здійснювати нешвидкі зміни вперед. Це також означає, що інші користувачі не матимуть примусових оновлень.
dnozay

1
@kynan masterє особливим лише до тих пір, поки це єдине існуюче відділення. Як тільки у вас є більше, всі гілки нарівні.
jub0bs

Відповіді:


614

Найближче до перейменування - це видалення та повторне створення на пульті. Наприклад:

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
гілки - це просто (ім’я, хеш) пара - нічого більше, нічого менше. Існує рефлог на відділеннях, але це ніколи не піддається віддаленим клієнтам.
bdonlan

122
Я б створив master-old на віддаленому перед видаленням master на віддалений. Я просто параноїк.
Адам Дімітрук

6
Відповідь Арістотеля нижче дозволяє це зробити, не видаляючи майстра, тому я вважаю, що краще.
Clay Bridges

13
було б зрозуміло і БЕЗПЕЧНО, якщо ви можете використовувати new-branch-nameі old-branch-nameзамість master/ master-old, то це загальна проблема.
Jaider

2
Якщо на видалену гілку (тут: master) не посилаються інші гілки, git може сміття збирати всі комісії на цьому ... ну ... "гілка". - Деякі команди git porcelain викликають збирання сміття. - Тому: спершу створіть нове ім’я (вказуючи на ту саму комісію), потім видаліть стару назву.
Роберт Сімер

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
Це краща відповідь, ніж "відповідь", я погоджуюся, але для людей, які прийшли сюди просто перейменувати гілку (не явно магістр), 3-й крок не має великого сенсу.
knocte

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

3
Це виявилося рішення, яке працювало на мене. Я намагався замінити майстра на іншу галузь. Я зробив журнал git -1 origin / what_i_want_as_new_master, щоб отримати $ new_master_commit за крок 3. Після поштовху (крок 4) інші розробники потягнуть і отримають повідомлення "ваша філія випереджає майстра на 295 комітів". Щоб виправити це, я надіслав електронний лист, в якому повідомляв їх про кожного запуску: git pull; git checkout some_random_branch; git гілка -D майстер; git pull; майстер каси git; По суті, їм потрібно усунути свого місцевого господаря та витягнути нову версію, інакше вони не знаходяться в неправильному місці.
nairbv

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

Переконайтеся, що у віддаленому конфігураційному файлі є "denyNonFastforwards = false", або ви отримаєте "remote: error: заперечення не швидкого перемотування вперед /
head

159

З 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за допомогою другого рядка.
Трістан Джах'єр

3
Дивовижні прості кроки. Це найкраща відповідь на питання
siddhusingh

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для видалення локальної старої гілки.
Nabi KAZ

Ви можете натиснути зміни тільки однієї команди: git push remote-name new-branch-name :old-branch-name.
сигід

Таким чином ви не ускладните історію git? Тому що ви відкриваєте нову філію, а не просто перейменовуючи поточну.
androidevil

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є найважливішим твором, який пропускають інші відповіді. Крім того, "легко зробити" не означає "легко зрозуміти або дізнатися", що, здається, має місце з великою кількістю git, але я відхиляюся.
Мартін Віднер

3
Мені подобається те, що жодних видалень не згадується і що перехід для тих, хто працює з клонами висхідної течії, є "безпроблемним". Дякую!
Піотрек

12

Я припускаю, що ви все ще запитуєте про ту саму ситуацію, що і в попередньому запитанні . Тобто, master-new не міститиме master-old у своїй історії. * Якщо ви називати master-new "master", ви фактично переписуєте історію. Не має значення, як ти потрапиш у такий стан, коли господар не є нащадком попередньої посади господаря, просто те, що він знаходиться в такому стані.

Інші користувачі, які намагаються витягнути, поки майстра не існує, просто відмовлять (не існує такої рефлексу на віддаленому), і як тільки він знову з’явиться на новому місці, їхнім витяжкам доведеться спробувати об'єднати свого господаря з новим віддаленим майстром, так само, як якщо б ви об'єднали master-old і master-new у своєму сховищі. З огляду на те, що ви намагаєтеся зробити тут, об'єднання матиме конфлікти. (Якби вони були вирішені, а результат був відтіснений назад у сховище, ви опинилися б у ще гіршому стані - обидві версії історії існують.)

Щоб відповісти на ваше запитання просто: ви повинні прийняти, що іноді у вашій історії будуть помилки. Це нормально. Це трапляється з усіма. У сховищі git.git є повернені коміти. Важливим є те, що колись ми публікуємо історію, це те, що кожен може довіряти.

* Якби це було, це було б рівноцінно натисканню деяких змін на головний, а потім створення нової гілки там, де раніше. Нема проблем.


Так, це та сама проблема, просто була одна ідея, як її вирішити. Але навіть якби я не робив цього перейменування гілок, мені було цікаво, якщо це буде можливо. Я вважав, що такі реферати як "майстер" - це лише посилання на конкретні коміти. Я дійсно не хочу змінювати будь-яку історію. Я думав, що я просто вкажу майстер-посилання на іншу голову. Це також означає, що я ніколи більше не можу використовувати ім’я гілки, якщо я колись використовував її раніше?
Альберт

Дійсно, гілки - це рефлекси - покажчики на коміти. Річ у тому, що ми очікуємо, що керівник відділення розвиватиметься певним чином (а саме завжди швидким пересуванням). З точки зору когось іншого, переміщення гілки у вашому публічному репо-релізі - це те саме, що переписування історії філії. Він більше не вказує на зобов’язання, що містить усе, до чого раніше.
Каскабель

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.

Хитрість полягає в тому, щоб зайти до заповнювача безпосередньо перед тим, як натиснути його на віддалений сховище. Решта - це пояснення самостійно, видалення головної гілки та переміщення її у віддалений сховище має працювати вже зараз. Звідси витягнуто .


Не вдасться на git push remote: master, якщо це встановлено на віддаленій стороні - у рядках журналу помилок ви побачите "віддалений: помилка:".
rafalmag

2

Добре. Мої 2 копійки. Як щодо входу в систему на сервері, переходу до каталогу git та перейменування гілки у голому сховищі. У цьому немає всіх проблем, пов’язаних із перезавантаженням тієї ж гілки. Власне, "клієнти" автоматично розпізнають змінене ім'я та змінять їх віддалену посилання. Після цього (або раніше) ви також можете змінити місцеву назву гілки.


8
Я забув облікові дані для входу на сервер github. Усі, хто має повноваження там :-P
Daniel Fisher 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

плутається з відстеженням філій - користувачам, можливо, доведеться виправляти свою гілку локально?
dnozay

1

Це найпростіший і «читабельніший» спосіб, про який я знаю:

"Перемістити" місцеву гілку за допомогою -m

git branch -m my_old_branch_name my_new_branch_name

Натисніть на "переміщену" гілку на віддалений, встановіть "вгору" за допомогою -u

git push origin -u my_new_branch_name

(налаштування "вище за течією" по суті "з'єднує" вашу локальну гілку з віддаленим, щоб такі речі, як витягнення, потягнення та натискання, спрацювали)

Видаліть стару гілку з пульта

git push origin -D <old_name>

(ваша місцева філія вже відсутня, тому що ви її "перемістили" на 1-му кроці)


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

Зверніть увагу, що тут віддалене ім'я "походження" за замовчуванням жорстко закодовано, ви можете розширити сценарій, щоб зробити його налаштованим!

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


-1

Я вважаю, що ключовим є усвідомлення того, що ви виконуєте подвійне перейменування: masterto master-oldі master-newto to master.

З усіх інших відповідей я синтезував це:

doublerename master-new master master-old

де спочатку ми повинні визначити функцію doublerenameBash:

# 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 trunk2 fatal: trunk2: не дійсний SHA1
Gregg Lind
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.