git push: refs / heads / my / subbranch tồn tại, không thể tạo


84

Điều này có phải là không thể tạo thư mục con somme con trong repo trên máy chủ không?

nếu tôi làm:

git push origin dev/master 

mọi thứ làm việc tìm

nhưng nếu tôi làm

git push origin dev/sub/master

tôi hiểu rồi:

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

tôi đã kiểm tra bằng "git branch -r" và trực tiếp với ssh, chưa có thư mục dev / sub nào được tạo.

chuyện gì vậy?


1
Git ls-remote origin trả về cái gì?
Ikke

Câu trả lời:


152

Nó không phải là một thư mục tồn tại, nó là một nhánh . (Chà, có thể có một thư mục / thư mục liên quan ở đâu đó — hoặc có thể không, vì các tham chiếu được "đóng gói" và ngừng tồn tại dưới dạng tệp trong thư mục.)

  • Nếu nhánh btồn tại, không nhánh nào có tên b/anythingcó thể được tạo.
  • Tương tự như vậy, nếu nhánh dev/btồn tại, dev/b/ckhông thể tạo.

Đây là một hạn chế nội bộ của git. Trong trường hợp cụ thể này, điều khiển từ xa origincó một nhánh được đặt tên dev/sub(bất kể bạn có hay không, điều quan trọng là điều khiển từ xa có nó hay không). Để tạo originnhánh có tên trên dev/sub/master, trước tiên bạn phải xóa nhánh có tên dev/subtrên origin:

git push origin :dev/sub

(Tất nhiên, việc xóa nhánh này có thể xóa một thứ gì đó quan trọng ở đó, vì vậy hãy đảm bảo rằng bạn biết mình đang làm gì. Nói chung, git fetch origintrước tiên, bạn có thể muốn nắm bắt chúng dev/sublàm của bạn origin/dev/sub. Sau đó, bạn có thể tạo một nhánh cục bộ có tên dev/renamed-subtrỏ đến cùng một cam kết , tạo dev/renamed-subtrên điều khiển từ xa, xóa điều khiển từ xa dev/sub, sau đó tạo dev/sub/mastertrên điều khiển từ xa.)


Nếu bạn có thể đăng nhập trên điều khiển từ xa (hệ thống originđược lưu trữ trên đó), bạn có thể vào kho lưu trữ ở đó và chỉ cần đổi tên dev/subchi nhánh cục bộ . (Dựa trên các nhận xét bên dưới, tôi nghi ngờ rằng có một tập lệnh tự động triển khai bị hỏng ở đó, có lẽ nên được sửa để chỉ triển khai các nhánh "có thể triển khai", thay vì mọi thứ được đẩy. Nhưng tôi chỉ đoán ở đây.)


1
Tôi đoán rằng chúng ta chỉ đang lộn xộn về thuật ngữ ở đây. Bởi "giới hạn nội bộ", ý tôi là đó là thứ mà git có thể vượt qua mà không cần thay đổi cách mọi người sử dụng git. Một giới hạn không đủ tiêu chuẩn sẽ là một cái gì đó cơ bản hơn nhiều, chẳng hạn như, nếu ai đó phá vỡ SHA1: trong khi điều này thậm chí có thể được khắc phục (ví dụ: chuyển sang SHA256), các chi tiết của SHA-1 gồm 40 ký tự được hiển thị trong, ví dụ, hầu hết các móc, vì vậy hạn chế này bị rò rỉ ra bên ngoài.

2
Đó là một giới hạn khó chịu một cách kỳ lạ, do bạn có thể muốn có release/1.1release/1.2với release/1.1/hofix/prevent-upload-bork& release/1.1/hotfix/assure-user-of-competence, v.v. Và thông báo lỗi dẫn một ở đây (cảm ơn), thay vì nêu rõ giới hạn! Nhưng cảm ơn bạn đã giải thích đơn giản và rõ ràng.
Benjohn

2
"Đây là một hạn chế nội bộ của git." -- Được rôi nhưng tại sao? Một số logic có dễ thực hiện hơn theo cách này không? Hoặc một số người đi ngang qua cây? Hay cái gì?
D. Kovács

2
@ D.Kovács: bằng cách cấm trường hợp đó, Git có thể chỉ cần viết các băm tham chiếu vào các tệp có tên được tạo ra bằng cách coi tham chiếu như một tên đường dẫn. Nếu Git cho phép cả hai refs/tags/foorefs/tags/foo/2, chẳng hạn, nó sẽ không thể làm điều này: nó sẽ cần triển khai kho khóa-giá trị của riêng mình. Tôi nghĩ dù sao thì Git cũng sẽ bị buộc phải triển khai kho giá trị khóa của riêng mình, nhưng tôi không biết liệu sau đó họ có xóa bỏ giới hạn hay không.
torek

1
@ ĐinhAnhHuy: Tôi không biết có tài liệu chính thức nào mô tả hạn chế này. Tuy nhiên, các mô-đun con nằm trong một không gian tên hoàn toàn riêng biệt: tên mô-đun con và tên nhánh không được xung đột theo cách mà tên nhánh và tên tệp không xung đột với nhau (nghĩa là chúng có, nhưng bạn thêm một bộ định cấu hình: git checkout -- masternghĩa là kiểm tra các tập tin được đặt tên master, chứ không phải là tên chi nhánh).
torek

60

Tôi đã ở trong tình trạng thậm chí không thể tìm nạp vì kho lưu trữ của tôi có thông tin về các chi nhánh từ xa không tồn tại mà tôi thậm chí chưa kiểm tra. Tôi đã giải quyết nó bằng cách chạy kết hợp (cảm ơn @torek) của:

  • git branch -r liệt kê các bản sao cục bộ của các chi nhánh từ xa
  • git ls-remote liệt kê các chi nhánh ở xa
  • git fetch --prune origincập nhật bản sao cục bộ của các chi nhánh từ xa ( điều này thực sự không giúp được gì cho tôi )
  • git remote prune originxóa thông tin về các chi nhánh từ xa đã loại bỏ ( điều này đã làm )

8
git remote prune originlà lệnh duy nhất tôi đã chạy để giải quyết trạng thái lỗi này. Thực sự là thông báo gây hiểu lầm - trong trường hợp của tôi, tôi đang cố gắng đẩy một "bản phát hành / 2.6.0" và tôi đã xóa toàn bộ 'refs / remotes / origin / release *' - nhưng git vẫn tiếp tục phàn nàn 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'bất cứ khi nào tôi thử push / pull / fetch
conny 13/03/18

30

Đối với tôi ->

Lỗi =

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

Giải pháp =

$~ git update-ref -d refs/heads/release/wl
$~ git checkout release/wl/2.3

1
git update-ref -d refs / remotes ... đã giải quyết được vấn đề của tôi để tồn tại 'refs / remotes / origin / hotfix'; không thể tạo 'refs / remotes / origin / hotfix / ISSUE ...
Eduardo

Nó cũng đã khắc phục sự cố của tôi.
Mikhail Morfikov

16

Các câu trả lời chấp nhận hiện nay không giúp tôi vì tôi không có một ref trên repo từ xa để xóa - đó là thuần túy về địa phương của tôi! Vì vậy, nếu bạn đang ở trong tình huống đó, đây là những gì cần làm:

Đây là vấn đề tôi đang gặp phải:

$ 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)

Tôi đã thử đề xuất của câu trả lời được chấp nhận nhưng nhận được điều này:

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

Vì vậy, ref thậm chí còn không tồn tại origin- nó rõ ràng chỉ quanh quẩn ở đâu đó trên repo cục bộ của tôi. Vì vậy, tôi đã chạy $ git remote show me, tạo ra:

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

Sau đó, giải pháp rõ ràng:

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

Với điều này, sự cố đã biến mất:

$ 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

3
Đúng, vấn đề tương tự như bạn đã gặp phải và git remote prune originkhắc phục nó. Cảm ơn!
ToddH

3

Hãy thử lệnh này để sửa nó:

git gc

để chạy một số tác vụ quản lý trong kho lưu trữ hiện tại và xóa các đối tượng không thể truy cập (bằng cách gọi git prunegit fsck --unreachable).

Đọc thêm: git help gcgit help prune


2

Nếu vẫn thất bại, hãy kiểm tra xem hệ thống repo của bạn không có giới hạn đối với tên chi nhánh. Trong trường hợp của tôi, bạn chỉ có thể tạo các nhánh bắt đầu bằng SD-<number>. Bất kỳ cách đặt tên nào khác sẽ chỉ cung cấp cho bạn một cái tên chung chung:

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 'git@git.example.com:project/repository.git'

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

Tập lệnh trên sẽ ghi lại lỗi vào XXX-error.log và sửa chúng bằng cách tạo và chạy XXX-exist-tags-delete.sh tự động từ XXX-error.log bằng các lệnh sau:

  1. git update-ref -d refs / tags
  2. git fetch
  3. git kéo
  4. git push


1

Là một người dùng windows, không có giải pháp nào giải quyết được vấn đề cho tôi. Lý do tôi gặp lỗi này là do (sử dụng tên chi nhánh của OP) tôi đang cố tạo một chi nhánh dev/subnhưng ai đó đã tạo một chi nhánh có tênDev và như chúng ta đều biết, các cửa sổ có hệ thống tệp không phân biệt chữ hoa chữ thường.

Vì vậy, khi cửa sổ cố gắng kéo xuống dev/sub, đầu tiên nó đang cố gắng tạo thư mục dev, nhưng không thể vì nó Devđã tồn tại.

Giải pháp là xóa Devchi nhánh cục bộ và từ xa với git branch -d Dev && git push origin :Dev. A git pullsau khi điều này chạy tốt.

Một bài học khác sắp tới, tên chi nhánh phải luôn là chữ thường để tránh kiểu gotcha này.


1

Tôi hiểu điều này đã được trả lời, nhưng nó không hiệu quả với tôi. Tôi không quan tâm đến những thay đổi cục bộ vì nó đã được đẩy lên nhưng có vấn đề kéo lại. Trong trường hợp của tôi, chúng tôi đã thay đổi nửa chừng giữa việc có "hotfix" làm nhánh sang hệ thống thư mục có thư mục mẹ là "hotfix".

- hotfix ---- hotfix / 1234_bug ---- hotfix / 3456_bug

Vì vậy, tôi đã nhận được lỗi sau:

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

Sau khi tìm kiếm các lỗi tương tự, cuối cùng tôi đã tìm thấy giải pháp trên một chuỗi thảo luận ở đây .

git remote prune origin

0
git checkout -b hotfix/my-new-branch

ga
gm "my commit"

gp --set-upstream origin hotfix/subscribers-function

0

Đổi tên dev/subthành dev/sub/something, sau đó bạn có thể tạo nhánh dev/sub/master.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.