Git : 삭제 된 (원격) 분기 복구


94

푸시 중에 삭제 한 두 개의 Git 브랜치를 복구해야합니다.

이 두 브랜치는 다른 시스템에서 생성 된 다음 "공유"(github) 저장소로 푸시되었습니다.

내 시스템에서 나는 (분명히) 가져 오는 동안 분기를 검색했습니다.

~/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

그 직후 나는 로컬 변경 사항을 중앙 저장소로 보내도록 푸시했습니다. 어떤 이유로 이러한 분기는 내 로컬 시스템과 중앙 저장소 모두에서 삭제되었습니다.

~/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

출생지 기계에서 가지를 제거하는 것은 그리 쉬운 일이 아니므로 가능한 한 내 지역에서 분기를 복구하고 싶습니다.

내가 검색 한 모든 git "undo"정보는 손실 된 커밋을 복구하는 데 필요합니다. 이 분기에 대한 커밋 UID가 없기 때문에 여기에 적용되지 않는다고 생각합니다.

이걸 어떻게 되 찾을 수 있는지 알고 싶습니다. 또한 처음에 삭제 된 방법과 향후이를 방지 할 수있는 방법도 알고 싶습니다.

편집 : 요청에 따라 여기에 내 저장소 구성이 있습니다.

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

'비정상적'이거나 일치하지 않는 가져 오기 및 푸시 구성이있는 것 같습니다. git config -l로컬 저장소에 대해 무엇을 표시합니까?
CB Bailey

아마도; 내가 게시했습니다.
Craig Walker

2
귀하의 remote.origin.fetchrefspec은와 함께 사용하기에 적합하지 않습니다 remote.origin.mirror = true. 미러링 하시겠습니까, 아니면 GitHub 저장소를 일반 리모컨으로 사용 하시겠습니까? 내 대답에는 어느 쪽이든 필요한 명령이 있어야합니다.
Chris Johnsen

두 번째 저장소에서는 미러링이 더 이상 옵션이 아니라고 생각합니다.
Craig Walker

답변:


103

나는 전문가가 아닙니다. 하지만 시도 할 수 있습니다

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

삭제 된 분기의 HEAD 커밋을 찾아 다시 가져옵니다.


이전에 fsck를 시도했습니다. 어떤 커밋이 올바른 커밋인지 알아내는 방법을 알고 있습니까? 시도 할 시간이 20 개 있습니다.
Craig Walker

1
이것은 그것을했다; 커밋 메시지를 git branch <uid>받으면 다시 가져 왔습니다. 감사!
Craig Walker

듣기 좋네요. 또한 설정 remotes.origin.mirrorremotes.origin.fetch설정 사이의 충돌을 해결해야합니다 . 그렇지 않으면 문제가 다시 발생할 수 있습니다 (또는 의도하지 않게 다른 리포지토리에서 푸시 된 커밋).
Chris Johnsen

@Craig : :) 도움이 될 다행
iamamac

3
오늘 릴리스 후보 브랜치를 잃었습니다. 커밋 ID를 몰랐습니다. 다음을 사용하여 복구했습니다.git fsck --full --no-reflogs | cut -d' ' -f3 | xargs -P8 git log --oneline | grep 'Release 2.60.0.157'
spezifanta

23

단 두 개의 명령이 내 생명을 구합니다

1. 이것은 모든 이전 HEAD를 나열합니다.

git reflog

2. 삭제 한 커밋으로 HEAD를 되돌립니다.

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

1
나는 지점에 로컬로 체크인하지 않았으므로 내 HEAD가 거기에 없었으므로 git reflog. 내가 시도 할 수있는 다른 것이 있습니까?
zyy

1
@zyy와 동일 함 원격의 다른 팀 구성원이 커밋을 삭제 했으므로 내 로컬 컴퓨터로 다시 가져와 (로컬 커밋을 한 적이 없음) 다시 푸시해야합니다.
OmGanesh

11

삭제 된 분기는 손실되지 않고 origin / contact_pageorigin / new_pictures "원격 추적 분기"에 표시 한 가져 오기에 의해 복사되었습니다 (또한 표시 한 푸시에 의해 밀려 났지만 refs / remotes /로 푸시되었습니다. refs / heads / 대신 origin /). 로컬 사본이 거기에 있어야한다고 생각하는 것이 무엇이든 "최신"인지 확인 git log origin/contact_page하고 확인하십시오 git log origin/new_pictures. 보여준 가져 오기와 푸시 사이에 새 커밋이 (다른 저장소에서) 해당 브랜치에 푸시 된 경우 해당 브랜치가 "손실"되었을 수 있습니다 (하지만 가장 최근에 해당 브랜치를 푸시 한 다른 저장소에서 찾을 수있을 것입니다). .

가져 오기 / 푸시 충돌

정상적인 '원격 모드'(원격 참조 / 헤드 / 원격 참조 / 원격 / 원점 /에 로컬로 저장 됨)에서 가져 오지만 '미러 모드'(로컬 참조 / 원격 참조 /로 푸시)로 푸시하는 것 같습니다. . .git / config를 확인하고 remote.origin.fetchremote.origin.push설정을 조정하십시오 .

백업 만들기

변경을 시도하기 전에 간단한 tar 또는 zip 아카이브 또는 전체 로컬 저장소를 만드십시오. 이렇게하면 어떤 일이 발생하는지 마음에 들지 않으면 복원 된 저장소에서 다시 시도 할 수 있습니다.

옵션 A : 미러로 재구성

원격 저장소를 로컬 저장소의 미러로 사용하려면 다음을 수행하십시오.

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

미러 모드에서 작동하는 경우 유용하지 않기 때문에 결국 모든 ref / remotes / origin / ref를 삭제할 수도 있습니다 (일반 분기가 일반적인 원격 추적 분기를 대신 함).

옵션 B : 일반 원격으로 재구성

그러나 여러 "작업"저장소와 함께이 원격 저장소를 사용하는 것 같으므로 미러 모드를 사용하고 싶지 않을 것입니다. 이것을 시도해 볼 수 있습니다.

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

그런 다음 결국 원격 저장소에서 가짜 ref / remotes / origin ref를 삭제해야합니다 git push origin :refs/remotes/origin/contact_page :refs/remotes/origin/new_pictures …..

푸시 테스트

시도 git push --dry-run는 무엇을보고 git push는 원격의 repo에 어떤 변경을하지 않고 할 것입니다. 수행 할 작업이 마음에 들지 않으면 백업 (tar / zip)에서 복구하고 다른 옵션을 시도하십시오.


1
원격 추적 분기가 전혀 복사되지 않았다면 유지되지 않았다고 생각합니다. 'git branch -a'는 그것들을 보여주지 않으며 .git dir에서도 그 이름을 가진 파일을 찾을 수 없습니다. 마지막으로, 당신이 추천 한 "git log"명령은 "fatal : ambiguous argument 'origin / contact_page': unknown revision or path not in the working tree"를 반환합니다 :-\ 감사합니다.
Craig Walker

1
글쎄, 그 지점이 거기에 있었고 푸시 로그에 표시됩니다. 에서 심판를 찾을 때 .git디렉토리 확인해야합니다 .git/packed_refs뿐만 아니라 .git/refs/. git show-ref모든 로컬 참조 (포장 또는 '느슨 함')를 덤프합니다. 원래 GitHub 리포지토리로 푸시했던 리포지토리에서 참조를 찾을 수 있어야합니다 (다른 머신에서? 다른 사람의 리포지토리?). 실패하면 gc 또는 prune을 수행하지 않은 한 git fsck출력에서 매달린 커밋을 검사하고 다시 연결할 수 있습니다 git branch contact_page-recovered <SHA-1-of-dangling-commit>..
Chris Johnsen

packed_refs도 그것을 가지고 있지 않았습니다. 커밋은 확실히 매달려 있었다. 어떻게 된 건지 모르겠어요 그래도 도와 ​​주셔서 감사합니다!
Craig Walker

8

삭제가 충분히 최근 인 경우 (예 : Oh-NO! 순간) 여전히 메시지가 있어야합니다.

Deleted branch <branch name> (was abcdefghi).

계속 실행할 수 있습니다.

git checkout abcdefghi

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


8
  1. Coimmit ID 찾기

    git reflog

  2. 실수로 삭제 한 로컬 브랜치를 복구

    git branch need-recover-branch-name commitId

  3. 이전에 원격 분기를 삭제 한 경우 need-recover-branch-name을 다시 푸시하십시오.

    git push origin need-recover-branch-name


2
이것은 나를 위해 일했습니다. 단계가 훨씬 적기 때문에 받아 들여지는 대답보다 선호합니다. git reflog추측 할 필요없이 에서 커밋 메시지를 볼 수있었습니다 git show.
theUtherSide 2011

3

데이터는 여전히 github에 존재하므로 이전 데이터에서 새 분기를 만들 수 있습니다.

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

'가져 오기'와 '푸시'에 대한 구성이 일치하지 않아 기본 가져 오기 / 푸시가 제대로 왕복하지 않는 것으로 생각됩니다. 다행히도 나중에 삭제 한 브랜치를 가져 왔으므로 명시적인 푸시로 다시 만들 수 있습니다.

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

@Chris Johnson에 대한 내 의견과 마찬가지로 지점이 더 이상 로컬에 존재하지 않는 것으로 보입니다. 내가 git push origin origin/contact_page:contact_page이것을 얻을 때 : error: src refspec origin/contact_page does not match any
Craig Walker

좋아요, 무슨 일이 일어 났는지 알 것 같습니다 (전체 오류가 도움이 되겠지만). 푸시는 삭제 된 분기를 업데이트하고 참조를 추적 참조 일뿐만 아니라 로컬에서 제거했습니다. 무엇합니까 git rev-parse refs/remotes/origin/origin/contact_page말은? 가짜 'mirror'구성으로 인해 my 브랜치는 이제 로컬 저장소에서 여기에 참조됩니다.
CB Bailey

안녕 찰스; 이 글을 작성한 이후로 구성을 수정 (및 수정)하여 더 이상 (의미있는) rev-parse 출력을 얻을 수 없습니다. 그러나 나는 리모트에 이중 중첩 "origin"디렉토리가 있다고 생각하지 않는다.
Craig Walker

0

조직에서 JIRA 또는 git에 연결된 다른 유사한 시스템을 사용하는 경우 티켓 자체에 나열된 커밋을 찾고 코드 변경 링크를 클릭 할 수 있습니다. Github는 브랜치를 삭제하지만 여전히 체리 피킹에 사용할 수있는 커밋을 가지고 있습니다.


-1

너무 조심스러워 보일지 모르지만 소스 제어를 변경하기 전에 작업해온 모든 파일의 복사본을 자주 압축합니다. 작업중인 Gitlab 프로젝트에서 최근 병합 요청을 병합 한 후 유지하고 싶은 실수로 원격 분기를 삭제했습니다. 커밋 기록으로 되돌리려면 다시 푸시하는 것이 전부였습니다. 병합 요청은 여전히 ​​Gitlab에 의해 추적되었으므로 브랜치 오른쪽에 파란색 '병합'레이블이 계속 표시됩니다. 문제가 발생할 경우를 대비하여 로컬 폴더를 압축했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.