git push: refs / heads / my / subbranch istnieje, nie można go utworzyć

88

Czy nie jest możliwe utworzenie somme podfolderu w repozytorium na serwerze?

Jeśli zrobię:

git push origin dev/master 

wszystko praca znaleźć

ale jeśli to zrobię

git push origin dev/sub/master

mam to:

error: 'refs/heads/dev/sub' exists; cannot create 'refs/heads/dev/sub/master'

sprawdziłem za pomocą "git branch -r" i bezpośrednio przez ssh, nie ma już utworzonego folderu dev / sub.

Co jest nie tak?

Snyf
źródło
1
Co zwraca git ls-remote origin?
Ikke

Odpowiedzi:

157

To nie jest folder, który istnieje, to gałąź . (Cóż, może gdzieś być zaangażowany folder / katalog - a może nie, ponieważ odniesienia są „pakowane” i przestają istnieć jako pliki w katalogach).

  • Jeśli gałąź bistnieje, nie b/anythingmożna utworzyć żadnej gałęzi o nazwie .
  • Podobnie, jeśli dev/bistnieje gałąź , dev/b/cnie można jej utworzyć.

To jest wewnętrzne ograniczenie gita. W tym konkretnym przypadku zdalny originma nazwaną gałąź dev/sub(niezależnie od tego, czy ją masz, czy nie, ważne jest, czy ma ją zdalny). Aby utworzyć origingałąź o nazwie dev/sub/master, musisz najpierw usunąć gałąź nazwaną dev/subna origin:

git push origin :dev/sub

(Oczywiście usunięcie tej gałęzi może usunąć coś ważnego w tym miejscu, więc upewnij się, że wiesz, co robisz. Ogólnie rzecz biorąc, możesz git fetch originnajpierw chcieć przechwycić ich dev/subjako swoje origin/dev/sub. Możesz wtedy utworzyć lokalną gałąź o nazwie dev/renamed-subwskazującej na to samo zatwierdzenie , utwórz dev/renamed-subna pilocie, usuń pilota dev/sub, a następnie utwórz dev/sub/masterna pilocie.)


Jeśli możesz zalogować się na zdalnym (systemie, który originjest hostowany), możesz przejść do repozytorium tam i po prostu zmienić nazwę lokalnego dev/suboddziału. (Opierając się na komentarzach poniżej, podejrzewam, że istnieje również uszkodzony skrypt do automatycznego wdrażania, który prawdopodobnie powinien zostać naprawiony, aby wdrażać tylko gałęzie „do wdrożenia”, a nie wszystko, co jest przekazywane. Ale zgaduję tutaj.)

torek
źródło
1
Chyba tylko kłopoczemy się tutaj nad terminologią. Przez „wewnętrzne ograniczenie” mam na myśli coś, co git mógłby pokonać bez zmiany sposobu, w jaki ktokolwiek używa gita. Niekwalifikowanym ograniczeniem byłoby coś znacznie bardziej fundamentalnego, na przykład, jeśli ktoś złamie SHA1: chociaż nawet to można przezwyciężyć (np. Przejść na SHA256), szczegóły 40-znakowych SHA-1 są ujawniane np. W większości hooków, więc to ograniczenie przecieka na zewnątrz.
torek
2
To dziwnie drażniący ograniczenie, ponieważ ty chcieć mieć release/1.1i release/1.2z release/1.1/hofix/prevent-upload-bork& release/1.1/hotfix/assure-user-of-competenceitp a przewody komunikatów o błędzie tu nikogo (dziękuję), zamiast określeń ograniczenie! Ale dziękuję za proste i jasne wyjaśnienie.
Benjohn,
2
„To jest wewnętrzne ograniczenie gita”. -- Dobrze ale dlaczego? Czy w ten sposób łatwiej było wdrożyć jakąś logikę? Albo jakieś przejście przez drzewo? Albo co?
D. Kovács
2
@ D.Kovács: zabraniając tego przypadku, Git może po prostu zapisywać skróty referencyjne do plików, których nazwa jest tworzona przez traktowanie odwołania jako nazwy ścieżki. Gdyby Git zezwalał na oba refs/tags/fooi refs/tags/foo/2, na przykład, nie byłby w stanie tego zrobić: musiałby zaimplementować własny magazyn klucz-wartość. Myślę, że Git i tak będzie zmuszony do implementacji własnego magazynu klucz-wartość, ale nie wiem, czy wtedy usunie to ograniczenie.
torek
1
@ ĐinhAnhHuy: Nie znam żadnej formalnej dokumentacji opisującej to ograniczenie. Jednak podmoduły znajdują się w całkowicie oddzielnej przestrzeni nazw: nazwy podmodułów i nazwy gałęzi nie powinny kolidować w taki sam sposób, jak nazwy gałęzi i nazwy plików nie kolidują (tj. Tak, ale dodajesz ujednoznacznienie: git checkout -- masteroznacza wyewidencjonowanie plik o nazwie master, a nie nazwa oddziału).
torek
62

Byłem w stanie, w którym nie mogłem nawet pobrać, ponieważ moje repozytorium zawierało informacje o nieistniejących zdalnych oddziałach, których nawet nie sprawdziłem. Rozwiązałem to uruchamiając kombinację (dzięki @torek):

  • git branch -r lista lokalnych kopii zdalnych oddziałów
  • git ls-remote lista zdalnych oddziałów
  • git fetch --prune originzaktualizować lokalne kopie zdalnych oddziałów ( to właściwie mi nie pomogło )
  • git remote prune originusuń informacje o usuniętych oddziałach zdalnych ( to zrobiło )
meridius
źródło
8
git remote prune originbyło jedynym poleceniem, które uruchomiłem, aby rozwiązać ten stan błędu. Rzeczywiście myląca wiadomość - w moim przypadku próbowałem wcisnąć "release / 2.6.0" i usunąłem cały katalog 'refs / remotes / origin / release *' - ale git narzekał error: update_ref failed for ref 'refs/remotes/origin/release/2.6.0': cannot lock ref 'refs/remotes/origin/release/2.6.0': 'refs/remotes/origin/release' exists; cannot create 'refs/remotes/origin/release/2.6.0'za każdym razem, gdy próbowałem push / pull / fetch
conny
32

Dla mnie ->

Błąd =

fatal: cannot lock ref 'refs/heads/release/wl/2.3': 'refs/heads/release/wl' 
exists; cannot create 'refs/heads/release/wl/2.3'

Rozwiązanie =

$~ git update-ref -d refs/heads/release/wl
$~ git checkout release/wl/2.3
MEZIDI Hamza
źródło
1
git update-ref -d refs / remotes ... rozwiązałem mój problem, że istnieje „refs / remotes / origin / hotfix”; nie można utworzyć 'refs / remotes / origin / hotfix / ISSUE ...
Eduardo
To również rozwiązało mój problem.
Michaił Morfikow
16

Obecnie akceptowane odpowiedź nie może mi pomóc, bo nie mają ref na pilocie zdalnego repo usunąć - to było czysto na mój lokalny! Więc jeśli jesteś w takiej sytuacji, oto co zrobić:

Oto problem, z którym miałem do czynienia:

$ git fetch origin
error: cannot lock ref 'refs/remotes/origin/fix/sub-branch': 
'refs/remotes/origin/fix' exists; cannot create 
'refs/remotes/origin/fix/sub-branch'
From <repo URL>
 ! [new branch]      fix/sub-branch          -> origin/fix/sub-branch
 (unable to update local ref)

Wypróbowałem sugestię zaakceptowanej odpowiedzi, ale otrzymałem to:

$ git push origin :fix
error: unable to delete 'fix': remote ref does not exist
error: failed to push some refs to <repo URL>

Więc ref nawet nie istniał origin- najwyraźniej kręcił się gdzieś w moim lokalnym repozytorium. Więc uciekłem$ git remote show me , który wyprodukował:

Remote branches:
...
refs/remotes/origin/fix             stale (use 'git remote prune' to remove)
...

Który następnie wyjaśnił rozwiązanie:

$ git remote prune origin
Pruning origin
URL: <redacted>
 * [pruned] origin/fix

Dzięki temu problem zniknął:

$ git fetch origin
remote: Counting objects: 5, done.
remote: Total 5 (delta 2), reused 2 (delta 2), pack-reused 3
Unpacking objects: 100% (5/5), done.
From <repo URL>
 * [new branch]      fix/sub-branch          -> origin/fix/sub-branch
awreccan
źródło
3
Tak, ten sam problem, który napotkałeś i git remote prune originnaprawiłeś. Dzięki!
ToddH
3

Wypróbuj to polecenie, aby to naprawić:

git gc

aby uruchomić szereg zadań porządkowych w bieżącym repozytorium i usunąć niedostępne obiekty (przez wywołanie git prunei git fsck --unreachable).

Czytaj więcej: git help gcigit help prune

kenorb
źródło
2

Jeśli wszystko inne zawiedzie, sprawdź, czy Twój system repozytoriów nie ma ograniczeń dotyczących nazw gałęzi. W moim przypadku można było tworzyć tylko gałęzie zaczynające się od SD-<number>. Każde inne nazewnictwo dałoby tylko ogólny:

remote: error: cannot lock ref 'refs/heads/mybranch': 'refs/heads/mybranch/environment-variables' exists; cannot create 'refs/heads/mybranch'
To git.example.com:project/repository.git
 ! [remote rejected] mybranch -> mybranch (failed to update ref)
error: failed to push some refs to '[email protected]:project/repository.git'
Juha Untinen
źródło
1
#!/usr/bin/env bash
echo "update-ref delete refs/tags"
log="git-update-ref-errors.log"
script="./git-update-ref-exist-tags-delete.sh"
git_command="git update-ref -d refs/tags"

echo "log errors from ${git_command} to ${log}"
${git_command} 2>&1 | > ${log}
echo "show errors to ${log}"
cat ${log}
echo create ${script}
touch ${script}
echo "add execute (+x) permissions to ${script}"
chmod +x ${script}
echo "generate ${script} from errors log ${log}"
${git_command} 2>&1 | grep 'exists' | sed -n "s:.*\: 'refs/tags/\(.*\)' exists;.*:git tag -d '\1':p" >> ${script}
echo "execute ${script}"
${script}

echo fetch
log="git-fetch-errors.log"
script="./git-fetch-exist-tags-delete.sh"
git_command="git fetch"
echo "log errors from ${git_command} to ${log}"
${git_command} 2>&1 | > ${log}
echo "show errors from ${log}"
cat ${log}
echo create ${script}
touch ${script}
echo "add execute (+x) permissions to ${script}"
chmod +x ${script}
echo "generate ${script} from errors log ${log}"
${git_command} 2>&1 | grep 'exists' | sed -n "s:.*\: 'refs/tags/\(.*\)' exists;.*:git tag -d '\1':p" >> ${script}
echo "execute ${script}"
${script}
git fetch

echo pull
log="git-pull-errors.log"
script="./git-pull-exist-tags-delete.sh"
git_command="git pull"
echo "log errors from ${git_command} to ${log}"
${git_command} 2>&1 | > ${log}
echo "show errors from ${log}"
cat ${log}
echo create ${script}
touch ${script}
echo "add execute (+x) permissions to ${script}"
chmod +x ${script}
echo "generate ${script} from errors log ${log}"
${git_command} 2>&1 | grep 'exists' | sed -n "s:.*\: 'refs/tags/\(.*\)' exists;.*:git tag -d '\1':p" >> ${script}
echo "execute ${script}"
${script}
git pull

echo push
log="git-push-errors.log"
script="./git-push-exist-tags-delete.sh"
git_command="git push"
echo "log errors from ${git_command} to ${log}"
${git_command} 2>&1 | > ${log}
echo "show errors from ${log}"
cat ${log}
echo create ${script}
touch ${script}
echo "add execute (+x) permissions to ${script}"
chmod +x ${script}
echo "generate ${script} from errors log ${log}"
${git_command} 2>&1 | grep 'exists' | sed -n "s:.*\: 'refs/tags/\(.*\)' exists;.*:git tag -d '\1':p" >> ${script}
echo "execute ${script}"
${script}
git push

Powyższy skrypt zarejestruje błędy w XXX-errors.log i naprawi je, generując i automatycznie uruchamiając plik XXX-exist-tags-delete.sh z pliku XXX-errors.log za pomocą następujących poleceń:

  1. git update-ref -d refs / tags
  2. git fetch
  3. git pull
  4. git push
Tomer Bar-Shlomo
źródło
1

git remote prune origin naprawił problem dla mnie

Andrea Gherardi
źródło
1

Jako użytkownik systemu Windows żadne z dotychczasowych rozwiązań nie rozwiązało problemu. Powodem, dla którego widziałem ten błąd, było to, że (używając nazw gałęzi OP) próbowałem utworzyć oddział, dev/subale ktoś inny utworzył gałąź o nazwieDev i jak wszyscy wiemy, system plików Windows nie rozróżnia wielkości liter.

Kiedy więc system Windows próbował się rozebrać, dev/subnajpierw próbował utworzyć folder dev, ale nie mógł, ponieważ Devjuż istniał.

Rozwiązaniem było usunięcie Devoddziału lokalnie i zdalnie za pomocą git branch -d Dev && git push origin :Dev. ZAgit pull po tym działało dobrze.

Kolejna lekcja, nazwy gałęzi powinny zawsze być pisane małymi literami, aby uniknąć tego rodzaju problemów.

alexkb
źródło
1

Rozumiem, że to już odpowiedział, ale to nie zadziałało. Nie przejmowałem się lokalnymi zmianami, ponieważ były już przyspieszone, ale miałem problemy z wycofaniem. W moim przypadku zmieniliśmy się w połowie drogi między posiadaniem „poprawki” jako gałęzi na system folderów z folderem nadrzędnym jako „poprawką”.

- poprawka ---- poprawka / 1234_bug ---- poprawka / 3456_bug

Więc otrzymywałem następujący błąd:

Fetching from origin Error: cannot lock ref 'refs/remotes/origin/hotfix/1234_bug': 'refs/remotes/origin/hotfix' exists; cannot create 'refs/remotes/origin/hotfix'

Po wyszukaniu podobnych błędów w końcu znalazłem rozwiązanie w wątku dyskusyjnym tutaj .

git remote prune origin
Sanjay Zalke
źródło
0
git checkout -b hotfix/my-new-branch

ga
gm "my commit"

gp --set-upstream origin hotfix/subscribers-function
Oślepiać
źródło
0

Zmień nazwę dev/subna dev/sub/something, a następnie możesz utworzyć gałąź dev/sub/master.

catanore
źródło