Git: Khôi phục nhánh đã xóa (từ xa)


94

Tôi cần khôi phục hai nhánh Git mà tôi đã xóa bằng cách nào đó trong một lần đẩy.

Hai nhánh này được tạo trên một hệ thống khác nhau và sau đó được đẩy đến kho lưu trữ "chia sẻ" (github) của tôi.

Trên hệ thống của tôi, tôi (dường như) đã truy xuất các nhánh trong quá trình tìm nạp:

~/myfolder> git fetch
remote: Counting objects: 105, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 62 (delta 29), reused 0 (delta 0)
Unpacking objects: 100% (62/62), done.
From github.com:mygiturl
 * [new branch]      contact_page -> origin/contact_page
   731d1bb..e8b68cc  homepage   -> origin/homepage
 * [new branch]      new_pictures -> origin/new_pictures

Ngay sau đó, tôi đã thực hiện một nỗ lực để gửi các thay đổi cục bộ của mình lên kho trung tâm. Vì một số lý do, các nhánh này đã bị xóa khỏi cả hệ thống cục bộ của tôi và đại diện trung tâm:

~/myfolder> git push
Counting objects: 71, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (43/43), done.
Writing objects: 100% (49/49), 4.99 KiB, done.
Total 49 (delta 33), reused 0 (delta 0)
To git@github.com:mygiturl.git
 - [deleted]         contact_page
 + e8b68cc...731d1bb homepage -> homepage (forced update)
   bb7e9f2..e0d061c  master -> master
 - [deleted]         new_pictures
   e38ac2e..bb7e9f2  origin/HEAD -> origin/HEAD
   731d1bb..e8b68cc  origin/homepage -> origin/homepage
   e38ac2e..bb7e9f2  origin/master -> origin/master
 * [new branch]      origin/contact_page -> origin/contact_page
 * [new branch]      origin/new_pictures -> origin/new_pictures

Thật không dễ dàng gì để lấy các nhánh ra khỏi cỗ máy nơi sinh của chúng, vì vậy tôi muốn thử khôi phục chúng từ địa phương của mình nếu có thể.

Tất cả thông tin git "hoàn tác" mà tôi đã googled liên quan đến việc khôi phục các cam kết bị mất. Tôi không nghĩ rằng điều đó áp dụng ở đây, vì tôi không có UID cam kết cho các nhánh này.

Tôi muốn biết làm cách nào để lấy lại những thứ này. Tôi cũng muốn biết cách chúng bị xóa ngay từ đầu và cách tôi có thể tránh điều này trong tương lai.

CHỈNH SỬA: theo yêu cầu, đây là cấu hình repo của tôi

user.name=Craig Walker
user.email=github@softcraft.ca
alias.unadd=reset HEAD
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
core.ignorecase=true
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
remote.origin.url=git@github.com:MyGitURL.git
remote.origin.mirror=true
branch.master.remote=origin
branch.master.merge=refs/heads/master
alias.undo=reset --hard
alias.test=push -f ci HEAD:master
alias.st=status
alias.ci=commit
alias.br=branch
alias.co=checkout
alias.ch=checkout
alias.df=diff
alias.lg=log -p
alias.who=shortlog -s --
remote.ci.url=ContinuousIntegrationGitURL
remote.ci.fetch=+refs/heads/*:refs/remotes/ci/*
branch.photo.remote=origin
branch.photo.merge=refs/heads/photos
remote.foo.url=FooGitURL
remote.foo.fetch=+refs/heads/*:refs/remotes/cynthia/*
branch.homepage.remote=origin
branch.homepage.merge=refs/heads/homepage

Có vẻ như bạn có cấu hình tìm nạp và đẩy 'bất thường' hoặc không khớp. Điều gì git config -lhiển thị cho kho lưu trữ cục bộ?
CB Bailey

Hoàn toàn có thể; Tôi đã đăng nó.
Craig Walker

2
remote.origin.fetchRefspec của bạn không thích hợp để sử dụng với remote.origin.mirror = true. Bạn muốn phản chiếu hay bạn muốn sử dụng kho GitHub như một điều khiển từ xa thông thường? Câu trả lời của tôi nên có các lệnh bạn cần theo cả hai cách.
Chris Johnsen

Tôi đoán rằng với kho lưu trữ thứ 2, phản chiếu không còn là một tùy chọn (điều này có thể gây ra việc xóa ngay từ đầu).
Craig Walker

Câu trả lời:


103

Tôi không phải là một chuyên gia. Nhưng bạn có thể thử

git fsck --full --no-reflogs | grep commit

để tìm cam kết HEAD của nhánh đã xóa và lấy lại chúng.


Tôi đã thử fsck trước đó; bạn có biết làm thế nào để tìm ra cam kết là chính xác? Tôi có 20 cái để thử.
Craig Walker

1
Điều này đã làm được; khi tôi có các thông báo cam kết, hãy git branch <uid>lấy lại chúng. Cảm ơn!
Craig Walker

Tốt để nghe. Hãy chắc chắn cũng giải quyết xung đột giữa cài đặt của bạn remotes.origin.mirrorremotes.origin.fetch, nếu không, bạn sẽ gặp phải sự cố một lần nữa (hoặc vô tình làm tắc nghẽn các cam kết được đẩy từ các repo khác).
Chris Johnsen

@Craig: Rất vui được hữu ích :)
iamamac

3
Tôi đã mất một nhánh ứng cử viên phát hành ngày hôm nay. Không biết id cam kết. Đã nhận nó phục hồi bằng cách sử dụng:git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta

23

chỉ hai lệnh cứu mạng tôi

1. Điều này sẽ liệt kê tất cả các HEAD trước đó

git reflog

2. Điều này sẽ hoàn nguyên HEAD để cam kết rằng bạn đã xóa.

git reset --hard <your deleted commit>
ex. git reset --hard b4b2c02

1
Tôi chưa bao giờ đăng ký vào chi nhánh tại địa phương nên HEAD của tôi chưa bao giờ ở đó, do đó tôi không thể tìm thấy ID cam kết với git reflog. Có gì khác tôi có thể thử không?
zyy

1
Tương tự như @zyy Cam kết đã bị xóa bởi thành viên khác trong nhóm từ xa, vì vậy tôi phải lấy lại nó trong máy cục bộ của mình (tôi chưa bao giờ có cam kết đó cục bộ) và đẩy nó trở lại ...
OmGanesh

11

Các nhánh đã xóa của bạn không bị mất, chúng đã được sao chép vào origin / contact_pageorigin / new_pictures "nhánh theo dõi từ xa" bằng cách tìm nạp mà bạn đã hiển thị (chúng cũng bị đẩy ra ngoài theo cách bạn hiển thị, nhưng chúng được đẩy vào refs / remotes / origin / thay vì refs / heads /). Kiểm tra git log origin/contact_pagegit log origin/new_picturesxem liệu các bản sao cục bộ của bạn có “cập nhật” với bất cứ điều gì bạn nghĩ nên có ở đó hay không. Nếu bất kỳ cam kết mới nào được đẩy lên các nhánh đó (từ một số repo khác) giữa lần tìm nạp và lần đẩy mà bạn đã hiển thị, bạn có thể đã "mất" chúng (nhưng có thể bạn có thể tìm thấy chúng trong repo khác gần đây nhất đã đẩy các nhánh đó) .

Tìm nạp / Xung đột Đẩy

Có vẻ như bạn đang tìm nạp ở 'chế độ từ xa' bình thường (refs / đầu từ xa / được lưu trữ cục bộ trong refs / remotes / origin /), nhưng đang đẩy ở 'chế độ phản chiếu' (refs cục bộ / được đẩy vào refs /) từ xa . Kiểm tra .git / config của bạn và điều chỉnh cài đặt remote.origin.fetchremote.origin.push.

Sao lưu

Trước khi thử bất kỳ thay đổi nào, hãy tạo một bản lưu trữ tar hoặc zip đơn giản hoặc toàn bộ kho lưu trữ cục bộ của bạn. Bằng cách đó, nếu bạn không thích những gì xảy ra, bạn có thể thử lại từ một repo đã khôi phục.

Tùy chọn A: Định cấu hình lại như một tấm gương

Nếu bạn định sử dụng repo từ xa của mình như một bản sao của repo cục bộ, hãy làm như sau:

git branch contact_page origin/contact_page &&
git branch new_pictures origin/new_pictures &&
git config remote.origin.fetch '+refs/*:refs/*' &&
git config --unset remote.origin.push &&
git config remote.origin.mirror true

Cuối cùng, bạn cũng có thể muốn xóa tất cả refs / remotes / origin / refs của mình, vì chúng không hữu ích nếu bạn đang hoạt động ở chế độ phản chiếu (các nhánh thông thường của bạn thay thế cho các nhánh theo dõi từ xa thông thường).

Tùy chọn B: Định cấu hình lại như một điều khiển từ xa thông thường

Nhưng vì có vẻ như bạn đang sử dụng repo từ xa này với nhiều repo “công việc”, có thể bạn không muốn sử dụng chế độ phản chiếu. Bạn có thể thử điều này:

git config push.default tracking &&
git config --unset remote.origin.push
git config --unset remote.origin.mirror

Sau đó, bạn cuối cùng sẽ muốn xóa refs / điều khiển từ xa / refs nguồn gốc không có thật trong repo từ xa của bạn: git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures ….

Kiểm tra Đẩy

Hãy thử git push --dry-runxem nó git pushsẽ làm gì mà không cần nó thực hiện bất kỳ thay đổi nào trên repo từ xa. Nếu bạn không thích những gì nó sẽ làm, hãy khôi phục từ bản sao lưu của bạn (tar / zip) và thử tùy chọn khác.


1
Tôi không nghĩ rằng các nhánh theo dõi từ xa đã được giữ lại, nếu chúng đã được sao chép chút nào. 'git branch -a' không hiển thị chúng và tôi không thể tìm thấy bất kỳ tệp nào có những tên đó trong .git dir. Cuối cùng, các lệnh "git log" mà bạn đề xuất trả về "fat: đối số không rõ ràng 'origin / contact_page': bản sửa đổi không xác định hoặc đường dẫn không có trong cây làm việc": - \ Xin cảm ơn.
Craig Walker

1
Chà, những nhánh đó đã ở đó, nhật ký đẩy của bạn cho thấy điều đó. Khi tìm kiếm các giới thiệu trong .gitdir, hãy nhớ kiểm tra .git/packed_refsthêm vào .git/refs/. git show-refsẽ loại bỏ tất cả các giới thiệu cục bộ của bạn (đóng gói hoặc 'rời'). Bạn vẫn có thể tìm thấy các ref trong repo mà ban đầu đã đẩy chúng vào repo GitHub của bạn (trên một máy khác? Repo của người khác?). Nếu không được, miễn là bạn đã không thực hiện một gc hoặc mận, bạn sẽ có thể đến git fsckđầu ra để kiểm tra các cam kết treo lủng lẳng và lắp lại họ: git branch contact_page-recovered <SHA-1-of-dangling-commit>.
Chris Johnsen

pack_refs cũng không có. Các cam kết chắc chắn đã được treo lơ lửng; không biết làm thế nào mà điều đó xảy ra. Cám ơn sự giúp đở cuả bạn!
Craig Walker

8

Nếu gần đây quá trình xóa (Giống như khoảnh khắc Ồ-KHÔNG!), Bạn vẫn sẽ có thông báo:

Deleted branch <branch name> (was abcdefghi).

bạn vẫn có thể chạy:

git checkout abcdefghi

git checkout -b <some new branch name or the old one>


8
  1. tìm ra mã coimmit

    git reflog

  2. khôi phục chi nhánh cục bộ mà bạn đã xóa do nhầm lẫn

    git branch need-recover-branch-name commitId

  3. đẩy lại tên nhánh cần-phục hồi nếu trước đó bạn cũng đã xóa nhánh từ xa

    git push origin need-recover-branch-name


2
Điều này đã làm việc cho tôi. Tôi thích câu trả lời được chấp nhận hơn vì nó ít bước hơn. Tôi đã có thể xem thông báo cam kết của mình từ đó git reflog, thay vì phải đoán và git show.
theUtherSide

3

Dữ liệu vẫn tồn tại trong github, bạn có thể tạo một nhánh mới từ dữ liệu cũ:

git checkout origin/BranchName #get a readonly pointer to the old branch
git checkout –b BranchName #create a new branch from the old
git push origin BranchName #publish the new branch

1

Tôi nghĩ rằng bạn có cấu hình không khớp cho 'tìm nạp' và 'đẩy', vì vậy điều này đã khiến tìm nạp / đẩy mặc định không thực hiện đúng chuyến đi. May mắn thay, bạn đã tìm nạp các nhánh mà bạn đã xóa sau đó, vì vậy bạn sẽ có thể tạo lại chúng bằng một động tác đẩy rõ ràng.

git push origin origin/contact_page:contact_page origin/new_pictures:new_pictures

Như với nhận xét của tôi cho @Chris Johnson, có vẻ như các chi nhánh không còn (không bao giờ?) Tồn tại cục bộ. Khi tôi git push origin origin/contact_page:contact_pagenhận được điều này: error: src refspec origin/contact_page does not match any
Craig Walker

Được rồi, tôi nghĩ tôi biết chuyện gì đã xảy ra, (mặc dù toàn bộ lỗi sẽ hữu ích). push đã cập nhật nhánh đã xóa và loại bỏ ref cục bộ cũng như đó là một ref theo dõi. Nói gì git rev-parse refs/remotes/origin/origin/contact_page? Do cấu hình 'mirror' không có thật, nhánh của tôi bây giờ được tham chiếu ở đây trong kho lưu trữ cục bộ.
CB Bailey

Chào Charles; Vì tôi đã viết bài này nên tôi đã gắn (và sửa) cấu hình của mình nên tôi không thể nhận được đầu ra phân tích cú pháp (ít) nữa. Tuy nhiên, tôi không nghĩ rằng có một thư mục "gốc" lồng nhau trong điều khiển từ xa.
Craig Walker

0

Nếu tổ chức của bạn sử dụng JIRA hoặc một hệ thống tương tự khác được liên kết với git, bạn có thể tìm thấy các cam kết được liệt kê trên chính vé và nhấp vào liên kết để thay đổi mã. Github xóa chi nhánh nhưng vẫn có các cam kết có sẵn cho việc hái anh đào.


-1

Có vẻ như là quá thận trọng, nhưng tôi thường nén một bản sao của bất kỳ thứ gì tôi đang làm trước khi thực hiện các thay đổi kiểm soát nguồn. Trong một dự án Gitlab mà tôi đang thực hiện, gần đây tôi đã xóa nhầm một nhánh từ xa mà tôi muốn giữ lại sau khi hợp nhất một yêu cầu hợp nhất. Hóa ra tất cả những gì tôi phải làm để lấy lại lịch sử cam kết đã được đẩy một lần nữa. Yêu cầu hợp nhất vẫn được Gitlab theo dõi, vì vậy nó vẫn hiển thị nhãn 'đã hợp nhất' màu xanh lam ở bên phải của nhánh. Tôi vẫn nén thư mục cục bộ của mình trong trường hợp có điều gì đó xấu xảy ra.

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.