Zdalna zmiana nazw oddziałów w Git

407

Jeśli istnieje repozytorium, do którego mam tylko git://dostęp (i zwykle wystarczyłoby push + pull), czy istnieje sposób na zmianę nazwy gałęzi w tym repozytorium w taki sam sposób, w jaki zrobiłbym to lokalnie git branch -m?

kdt
źródło
48
Połączone pytanie „duplikat” wymaga zmiany nazwy oddziału „zarówno lokalnie, jak i zdalnie”. To pytanie dotyczy jednak tylko zdalnej zmiany nazw oddziałów, co pozwala na uproszczenie. To jest to, co zrobić, aby zmienić nazwę oddziału na serwerze bez konieczności KASY i / lub stworzenia lokalnego oddziału: git push origin origin/old_name:refs/heads/new_name && git push origin :old_name.
sschuberth
1
@sschuberth: możesz wydać oba polecenia za jednym razem. I to naprawdę powinna być odpowiedź na to pytanie.
Joachim Breitner,
2
@ JoachimBreitner Masz rację, optymalizację przeprowadziłem już w tym skrypcie .
sschuberth,
1
@sschuberth, powinieneś opublikować swój komentarz jako odpowiedź, ponieważ podoba mi się to bardziej niż pozostałe poniżej.
phatmann
Sporządzono .
sschuberth

Odpowiedzi:

480

Musisz tylko utworzyć nową gałąź lokalną o żądanej nazwie, wcisnąć ją do pilota, a następnie usunąć starą gałąź zdalną:

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

Następnie, aby zobaczyć starą nazwę oddziału, każdy klient repozytorium musiałby zrobić:

$ git fetch origin
$ git remote prune origin

UWAGA: Jeśli twoja stara gałąź jest główną gałęzią, powinieneś zmienić ustawienia głównej gałęzi. W przeciwnym razie po uruchomieniu $ git push origin :old-branch-namepojawi się błąd „usunięcie bieżącego oddziału zabronione” .

Sylvain Defresne
źródło
8
Cóż, jeśli stare i nowe nazwy są takie same, oznacza to, że nie trzeba zmieniać nazwy gałęzi, więc nie ma sensu uruchamianie polecenia w pierwszej kolejności ;-)
Sylvain Defresne
9
Pewnie. Mam na myśli to, że jeśli wywołujesz to w sposób zautomatyzowany (jako część funkcji innego skryptu), równie dobrze możesz nie zrobić tego źle, jeśli możesz tego uniknąć.
Tajemniczy Dan
9
Sposób Dana: zmieniaj kolejność poleceń, aby zawsze działały. Sposób Earth Engine: zawsze pamiętaj, aby sprawdzić, albo stracisz dane. Wiem, który wybrałbym.
Doradus
2
Użytkownicy mogą po prostu uruchomić: git fetch origin --prune(aby skutecznie pobrać nowe gałęzie, a także pozbyć się referencji już nie na pilocie).
DolphinDream,
2
Może używać -dlub --deletezamiast :w nowszych wersjach git.
Zitrax
285

Jeśli naprawdę chcesz po prostu zmienić nazwę gałęzi zdalnie, bez zmiany nazwy żadnych oddziałów lokalnych w tym samym czasie , możesz to zrobić za pomocą jednego polecenia:

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

Napisałem ten skrypt ( git-rename-remote-branch ), który zapewnia przydatny skrót do łatwego wykonywania powyższych czynności.

Jako funkcja 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
}

Aby zintegrować komentarz @ ksrb : W zasadzie wykonuje to dwa git push <remote> <remote>/<old_name>:refs/heads/<new_name>naciśnięcia jednego polecenia, najpierw wypychając nową gałąź zdalną na podstawie starej gałęzi zdalnego śledzenia, a następnie git push <remote> :<old_name>usuwając starą gałąź zdalną.

sschuberth
źródło
10
Dla tych, którzy chcieliby otrzymać alias tego polecenia: rename = "! F () {git push origin origin / $ 1: refs / heads / $ 2: $ 1;}; f" może to być użyte jako> git rename <nazwa_oleju> < nowa_nazwa>
Jonathan Schmidt
33
Dla tych, którzy są ciekawi, co właściwie oznacza to polecenie, w zasadzie 2 git push <remote>/<old_name>:refs/heads/<new_name>naciśnięcia oznaczają wypchnięcie nowego pilota, który używa starego pilota jako src, a następnie git push [space]:<old_name> usunięcie starego pilota
ksrb
3
Dlaczego musisz używać refs/heads/name? Czy nie możesz użyć namebezpośrednio, wykonując pierwsze polecenie git push <remote> <remote>/<old_name>:<new_name>?
Drew Noakes,
6
Nie, ponieważ gałąź zdalna <new_name>jeszcze nie istnieje. Jeśli gałąź nie istnieje, Git wymaga użycia pełnej nazwy, ponieważ w przeciwnym razie <new_name>może również odnosić się do nazwy znacznika.
sschuberth,
3
Stosujemy to podejście w naszym systemie kompilacji. Jedynym zastrzeżeniem, jakie napotykamy, jest to, że refs/heads/<new_name> już istnieje. Usuwanie nadal kończy się powodzeniem, co powoduje <remote>/<old_name>jedynie usunięcie. Niektóre sprawdzanie przed ręką może tego łatwo uniknąć.
Apeiron
172

Pierwsza kasa do oddziału, którego nazwę chcesz zmienić:

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

Aby usunąć stary oddział z remote:

git push origin :old_branch
Shashank Hegde
źródło
12
Po przesunięciu gałęzi o zmienionej nazwie (new_branch) do zdalnego (pochodzenia), powinieneś również ustawić jego upstream, aby śledził gałąź o nowej nazwie (np. git push -u origin new_branch), W przeciwnym razie gałąź o zmienionej nazwie (new_branch) będzie nadal śledzić pochodzenie / old_branch. A kiedy usuniesz zdalny old_branch, new_branch nadal będzie śledzić pochodzenie / old_branch, choć teraz gałąź zniknęła.
DolphinDream,
@DolphinDream Zredagowałem odpowiedź, aby uwzględnić twoją przydatną zmianę upstream.
mVChr
10

Pewnie. Wystarczy zmienić nazwę gałęzi lokalnie, wcisnąć nową gałąź i wcisnąć usunięcie starej.

Jedynym prawdziwym problemem jest to, że inni użytkownicy repozytorium nie będą zmieniać nazw lokalnych oddziałów śledzenia.

Lily Ballard
źródło
1
więc kiedy próbuję usunąć master, próbowałem $ git clone ../src $ cd src $ git oddział notmaster $ git kasa notmaster $ git oddział -d master $ git push ../src: master Ale to narzeka: Miejsce docelowe refspec nie pasuje do istniejącego ref na pilocie, ani nie zaczyna się od refs /, i nie możemy zgadnąć prefiksu na podstawie źródłowego ref. błąd: nie udało się wypchnąć niektórych referencji do „../alpha/” Pilot naprawdę ma gałąź o nazwie master
kdt
2

TL; DR

„Zmiana nazwy” zdalnej gałęzi jest w rzeczywistości procesem dwuetapowym (niekoniecznie zamówionym):

  • usunięcie starej zdalnej gałęzi ( git push [space]:<old_name>jak wyjaśnił ksrb );
  • wcisnąć do nowej zdalnej gałęzi (różnica między kilkoma poleceniami odpowiedzi poniżej).

Kasowanie

Korzystam z TortoiseGit i kiedy po raz pierwszy próbowałem usunąć gałąź za pomocą wiersza poleceń, otrzymałem:

$ git push origin :in
  • fatal: „origin” nie wydaje się być repozytorium git

  • fatal: Nie można odczytać ze zdalnego repozytorium.

Upewnij się, że masz odpowiednie prawa dostępu, a repozytorium istnieje.

Było to prawdopodobnie spowodowane tym, że pageant nie ma załadowanego klucza prywatnego (który TortoiseGit ładuje się automatycznie do pageant ). Ponadto zauważyłem, że polecenia TortoiseGit nie mają w sobie originref (np git.exe push --progress "my_project" interesting_local:interesting.).

Używam również Bitbucket i, podobnie jak innych internetowych menedżerów git online (GitHub, GitLab), mogłem usunąć zdalną gałąź bezpośrednio przez ich interfejs (strona oddziałów):

Usuń oddział Bitbucket

Jednak w TortoiseGit możesz również usuwać zdalne gałęzie za pomocą Przeglądaj referencje :

Przeglądaj menu Referencje

Klikając prawym przyciskiem myszy gałąź zdalną (listę pilotów) pojawia się opcja Usuń gałąź zdalną :

Zdalne usuwanie gałęzi TortoiseGit

Popychanie

Po usunięciu starej zdalnej gałęzi przepchnąłem bezpośrednio do nowej zdalnej gałęzi poprzez TortoiseGit , wpisując nową nazwę w polu Remote: w oknie Push, a gałąź ta została automatycznie utworzona i widoczna w Bitbucket .

Jeśli jednak nadal wolisz to robić ręcznie, kwestią, o której jeszcze nie wspomniano w tym wątku, jest to, że -u= --set-upstream.

Z git pushdokumentów , -uto tylko alias --set-upstream, więc polecenia w odpowiedziach Sylvaina ( -set-upstream new-branch) i Shashank ( -u origin new_branch) są równoważne, ponieważ zdalne odwołanie domyślnie jest ustawione,origin jeśli żadne inne odwołanie nie zostało wcześniej zdefiniowane:

  • git push origin -u new_branch= git push -u new_branch z opisu dokumentacji :

    Jeśli brakuje konfiguracji, domyślnie jest to origin.

Ostatecznie nie wpisałem ręcznie ani nie użyłem żadnego z poleceń sugerowanych przez inne odpowiedzi tutaj, więc być może może to być przydatne dla innych w podobnej sytuacji.

CPHPython
źródło
Problem polega na tym, że twój pilot nie jest wywoływany origin. Musisz nazwać swojego pilota, gdy tylko uruchomisz polecenie git remote. Git współpracuje z sshtym, co sugeruje, że używasz kluczy publicznych + prywatnych. Zakładam, że Autoload Putty keysTortoiseGit po prostu automatycznie ładuje potrzebne klucze, abyś mógł cokolwiek zrobić za pomocą zdalnego odwołania. Ostatnią rzeczą jest to, że git push -unie jest to alias do wypychania do zdalnej gałęzi, to alias do wypychania do zdalnej gałęzi, która została utworzona lokalnie, a jej zdalne odwołanie nie ma jeszcze tej gałęzi .
juanecabellob
1
@juancab -uto alias --set-upstreami „jeśli brakuje konfiguracji, domyślnie jest toorigin ”. Sylvain i Shashank używają tego do wypychania do nowo utworzonego zdalnego oddziału . Kluczowy problem może być ze względu na korowód nie mając załadowany kiedy próbowałem git push origin :inna skorupce. Więc nie rozumiem twojego zdania, po prostu wskazałem moje i nieadresowane szczegóły w innych odpowiedziach, wyjaśniłem je i rozwiązałem.
CPHPython
Stwierdzasz złe rzeczy, a większość tej odpowiedzi nie ma związku z samym pytaniem. Jeśli wskazujesz, co Ci się udało, zachęcam do ograniczenia odpowiedzi do tego, co zadziałało, a jeśli naprawdę chcesz podać wyjaśnienie, prosimy o lepsze informacje. Btw: -uto alias dla, --set-upstreamale nie jest to alias do wypychania do zdalnej gałęzi, jak powiedziałeś. Aby przepchnąć się do zdalnego oddziału, którego wyjątkowo potrzebujesz git push <remote>, a jeśli jeszcze go nie ma, dodaj git push -u <remote>. Dlatego -usłuży do tworzenia odniesienia do oddziału w zdalnym.
juanecabellob
1
@juancab, być może to, co uważałeś za złe, to głównie frazowanie aliasów lub wybór słów. Przekształciłem odpowiedź i przeredagowałem ją, aby zapewnić pełne wyjaśnienie rozwiązania, dla którego znalazłem zmianę nazwy oddziału zdalnego.
CPHPython
Przeredagowałbym to dalej. Teraz ma to większy sens, ale wciąż jest za długie. Chciałbym bardziej sprecyzować problem, tzn. Stwierdzić, że dla użytkowników TortoiseGit proponowane rozwiązania nie będą działać. Opowiadasz historię, która jest myląca i sprawia, że ​​użytkownicy unikają czytania. Przeredaguję twoją odpowiedź z propozycją.
juanecabellob
1

Nie wiem dlaczego, ale odpowiedź @Sylvain Defresne nie działa dla mnie.

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

Muszę rozbroić strumień wyjściowy, a następnie ponownie ustawić strumień. Oto jak to zrobiłem.

git checkout -b new-branch-name
git branch --unset-upstream
git push origin new-branch-name -u
git branch origin :old-branch-name
Arthur Bryant
źródło
0

Nie wiem, czy to jest dobre, czy złe, ale przesunąłem „starą nazwę” gałęzi do „nowej nazwy” gałęzi, a następnie całkowicie usunąłem starą gałąź z następującymi dwoma wierszami:

git push origin old_branch:new_branch
git push origin :old_branch
EpicPandaForce
źródło
O ile wiem, dokładnie tak robią wszystkie pozostałe odpowiedzi. Twoja odpowiedź jest bardziej zwięzła.
Jaśniejsze
-1

Możesz utworzyć nowy oddział na podstawie oddziału o starej nazwie. Tak po prostu usuń starą gałąź !!!wprowadź opis zdjęcia tutaj

Pober Wong
źródło
To jest GitHub, nie Git. ;)
Bouncner
-4

Dodając do już udzielonych odpowiedzi, oto wersja, która najpierw sprawdza, czy nowy oddział już istnieje (abyś mógł bezpiecznie używać go w skrypcie)

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"

(czek pochodzi z tej odpowiedzi )

myzzzl
źródło
Użyłbym git show-ref --quiet --verify -- refs/heads/$new_namezamiast ls-remote | cut | sed | grep.
Andy