이 문서는 GitLab 저장소가 Bitbucket 저장소를 미러링하도록 Mirror Hook을 설정하는 방법의 가이드를 공유하기 위해 작성되었다.


도구명Bitbucket, GitLab
버전

Bitbucket : 8.19.8

GitLab : 15.2

비고-




Bitbucket 저장소와 GitLab 저장소 연동 설정하기

1. GitLab에 저장소 생성하기

TroubleShooting

다음 에러는 GitLab 저장소에 ReadMe 파일이 있을 때 발생한 에러입니다.

2024-10-16 08:33:24,303 ERROR [MirrorRepositoryHook:thread-2]  c.a.s.i.c.HazelcastBucketedExecutor Attempt 5 of 5 at processing bucket 'MirrorRepositoryHook@32:https://gitlab-playground.curvc.com/root/demo-project.git' for executor 'MirrorRepositoryHook' failed: 
com.atlassian.bitbucket.ServerException: An error occurred while executing an external process: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/root/demo-project.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1
	at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateThrowable(GitCommandExitHandler.java:163)
	at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:297)
	at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:32)
	at com.englishtown.bitbucket.hook.PasswordHandler.onExit(PasswordHandler.java:50)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callExitHandler(AbstractFragmentResponseObserver.java:180)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.asResult(AbstractFragmentResponseObserver.java:150)
	at com.atlassian.stash.internal.scm.git.mesh.BidirectionalFragmentResponseObserver.asResult(BidirectionalFragmentResponseObserver.java:66)
	at com.atlassian.stash.internal.scm.git.mesh.GrpcPlumbingClient.call(GrpcPlumbingClient.java:71)
	at jdk.internal.reflect.GeneratedMethodAccessor794.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at jdk.internal.reflect.GeneratedMethodAccessor187.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at jdk.proxy3/jdk.proxy3.$Proxy477.call(Unknown Source)
	at com.atlassian.stash.internal.scm.git.mesh.MeshGitFreeFormCommandBuilder$1.call(MeshGitFreeFormCommandBuilder.java:105)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.runMirrorCommand(MirrorBucketProcessor.java:130)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.lambda$process$0(MirrorBucketProcessor.java:80)
	at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:59)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.process(MirrorBucketProcessor.java:70)
	at com.atlassian.stash.internal.concurrent.HazelcastBucketedExecutor$BucketProcessingBootstrapper.run(HazelcastBucketedExecutor.java:146)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.lang.Thread.run(Thread.java:840)
	... 15 frames trimmed
Caused by: com.englishtown.bitbucket.hook.PasswordHandler$PasswordSafeException: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/root/demo-project.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1
	at com.atlassian.stash.internal.scm.git.command.BioStdioHandler.onComplete(BioStdioHandler.java:92)
	at com.atlassian.stash.internal.scm.git.mesh.LatchedNioStdioHandler.onComplete(LatchedNioStdioHandler.java:61)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.maybeSummarize(AbstractFragmentResponseObserver.java:278)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.finish(AbstractFragmentResponseObserver.java:228)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callOnExit(AbstractFragmentResponseObserver.java:200)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:120)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:41)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onMessage(ClientCalls.java:468)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onMessage(StatefulClientCallListener.java:45)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at com.atlassian.stash.internal.scm.git.mesh.DeadlinePropagatingClientInterceptor$DeadlinePropagatingListener.onMessage(DeadlinePropagatingClientInterceptor.java:169)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInternal(ClientCallImpl.java:667)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:654)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	... 3 common frames omitted


(눈금) GitLab에 아무 파일도 없는 상태 (ReadMe 파일도 cross mark ) 인 경우에는 에러 발생하지 않습니다.

따라서, Initialize Repository with a README 선택 해제해야 합니다.

2. Bitbucket 저장소의 Mirror Hook 설정

  • 저장소의 Repository settings → Hooks

Pipeline 에러

Bitbucket에서 Mirror Hook 활성화 후 거의 바로 저장소 clone 되지만, (오류) Pipeline 에서 에러 발생

GitLab 웹 페이지에 나타나는 에러
      $ /build/build.sh
bash: line 179: /build/build.sh: No such file or directory
Uploading artifacts for failed job
Uploading artifacts...
Runtime platform                                    arch=amd64 os=linux pid=19961 revision=66269445 version=17.3.1
WARNING: gl-auto-build-variables.env: no matching files. Ensure that the artifact path is relative to the working directory (/home/gitlab-runner/builds/2a7FHkMoh/0/test/mirroring-test) 

// build.sh 파일 X
ERROR: No files to upload                          
Cleaning up project directory and file based variables
ERROR: Job failed: exit status 1
GitLab 로그
{
  "severity": "WARN",
  "time": "2024-10-16T01:28:01.706Z",
  "class": "Git::BranchHooksService",
  "correlation_id": "01JA9F0S8ZXF5785N7KSG01K2N",
  "project_id": 6,
  "project_path": "test/mirroring-test",
  "message": "Error creating pipeline",
  "errors": "Missing CI config file",							// CI Config file 이 없어서 발생
  "pipeline_params": {
    "before": "23289086630c099e53bc5a8c614693fac7893568",
    "after": "7a4af81869ff3a1bf222ad120e0fb69e93f70ce8",
    "ref": "refs/heads/master",
    "variables_attributes": [],
    "checkout_sha": "7a4af81869ff3a1bf222ad120e0fb69e93f70ce8"
  },
  "retry": 0
}

CI Config file이 없어서 발생했기 때문에 추가합니다.

미러링 테스트

Bitbucket 저장소에서 Commit right arrow  GitLab 저장소에서 Commit 내역 업데이트

Bitbucket 저장소에서 Pull Request & Merge right arrow GitLab 저장소에 업데이트

Bitbucket의 Git LFS 포함 저장소를 GitLab으로 미러링

(오류) 에러 발생, LFS 파일이 포함된 Commit이 업데이트 되지 않습니다.


GitLab 로그
{
  "correlation_id": "01JABWQS7EC26MEHMCZJ8J6EMG",
  "duration_ms": 114,
  "error": "LFS objects are missing. Ensure LFS is properly set up or try a manual \"git lfs push --all\".",
  "level": "error", // 로그 레벨: 오류 발생
  "method": "POST",
  "msg": "Internal API error",
  "pid": 286,
  "status": 401, // 상태 코드: 권한 없음 (401 Unauthorized)
  "time": "2024-10-17T00:06:15.354Z",
  "url": "http://unix/api/v4/internal/allowed"
}

{
  "component": "gitaly.StreamServerInterceptor",
  "correlation_id": "01JABWQS7EC26MEHMCZJ8J6EMG",
  "error": "GitLab: LFS objects are missing. Ensure LFS is properly set up or try a manual \"git lfs push --all\".", // 오류 메시지: Git LFS 오브젝트 누락
  "grpc.meta.client_name": "gitaly-hooks",
  "grpc.meta.deadline_type": "none",
  "grpc.meta.method_operation": "accessor",
  "grpc.meta.method_scope": "repository",
  "grpc.meta.method_type": "bidi_stream",
  "grpc.method": "PreReceiveHook", // gRPC 메서드: PreReceiveHook
  "grpc.request.fullMethod": "/gitaly.HookService/PreReceiveHook",
  "grpc.request.glProjectPath": "test/bitbucket-java-ex",
  "grpc.request.glRepository": "project-12",
  "grpc.request.repoPath": "@hashed/6b/51/6b51d431df5d7f141cbececcf79edf3dd861c3b4069f0b11661a3eefacbba918.git",
  "grpc.request.repoStorage": "default",
  "grpc.service": "gitaly.HookService",
  "grpc.start_time": "2024-10-17T00:06:15.239",
  "level": "warning",
  "msg": "stopping transaction because pre-receive hook failed", // 메시지: pre-receive hook 실패로 트랜잭션 중단
  "pid": 286,
  "span.kind": "server",
  "system": "grpc",
  "time": "2024-10-17T00:06:15.354Z",
  "user_id": "user-1",
  "username": "root"
}
Bitbucket 로그
2024-10-17 09:07:56,053 ERROR [MirrorRepositoryHook:thread-3]  c.a.s.i.c.HazelcastBucketedExecutor Attempt 5 of 5 at processing bucket 'MirrorRepositoryHook@73:https://gitlab-playground.curvc.com/test/bitbucket-java-ex.git' for executor 'MirrorRepositoryHook' failed: 
com.atlassian.bitbucket.ServerException: An error occurred while executing an external process: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/test/bitbucket-java-ex.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1
	at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.evaluateThrowable(GitCommandExitHandler.java:163)
	at com.atlassian.bitbucket.scm.git.command.GitCommandExitHandler.onError(GitCommandExitHandler.java:297)
	at com.atlassian.bitbucket.scm.DefaultCommandExitHandler.onExit(DefaultCommandExitHandler.java:32)
	at com.englishtown.bitbucket.hook.PasswordHandler.onExit(PasswordHandler.java:50)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callExitHandler(AbstractFragmentResponseObserver.java:180)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.asResult(AbstractFragmentResponseObserver.java:150)
	at com.atlassian.stash.internal.scm.git.mesh.BidirectionalFragmentResponseObserver.asResult(BidirectionalFragmentResponseObserver.java:66)
	at com.atlassian.stash.internal.scm.git.mesh.GrpcPlumbingClient.call(GrpcPlumbingClient.java:71)
	at jdk.internal.reflect.GeneratedMethodAccessor794.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at jdk.internal.reflect.GeneratedMethodAccessor187.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at jdk.proxy3/jdk.proxy3.$Proxy477.call(Unknown Source)
	at com.atlassian.stash.internal.scm.git.mesh.MeshGitFreeFormCommandBuilder$1.call(MeshGitFreeFormCommandBuilder.java:105)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.runMirrorCommand(MirrorBucketProcessor.java:130)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.lambda$process$0(MirrorBucketProcessor.java:80)
	at com.atlassian.stash.internal.user.DefaultEscalatedSecurityContext.call(DefaultEscalatedSecurityContext.java:59)
	at com.englishtown.bitbucket.hook.MirrorBucketProcessor.process(MirrorBucketProcessor.java:70)
	at com.atlassian.stash.internal.concurrent.HazelcastBucketedExecutor$BucketProcessingBootstrapper.run(HazelcastBucketedExecutor.java:146)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.lang.Thread.run(Thread.java:840)
	... 15 frames trimmed
Caused by: com.englishtown.bitbucket.hook.PasswordHandler$PasswordSafeException: Wrapping ProcessFailedException: 'git push --prune https://root:**********@gitlab-playground.curvc.com/test/bitbucket-java-ex.git --force --atomic +refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/* +refs/notes/*:refs/notes/*' exited with code 1
	at com.atlassian.stash.internal.scm.git.command.BioStdioHandler.onComplete(BioStdioHandler.java:92)
	at com.atlassian.stash.internal.scm.git.mesh.LatchedNioStdioHandler.onComplete(LatchedNioStdioHandler.java:61)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.maybeSummarize(AbstractFragmentResponseObserver.java:278)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.finish(AbstractFragmentResponseObserver.java:228)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.callOnExit(AbstractFragmentResponseObserver.java:200)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:120)
	at com.atlassian.stash.internal.scm.git.mesh.AbstractFragmentResponseObserver.onNext(AbstractFragmentResponseObserver.java:41)
	at io.grpc.stub.ClientCalls$StreamObserverToCallListenerAdapter.onMessage(ClientCalls.java:468)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at com.atlassian.stash.internal.scm.git.mesh.StatefulClientCallListener.onMessage(StatefulClientCallListener.java:45)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at com.atlassian.stash.internal.scm.git.mesh.DeadlinePropagatingClientInterceptor$DeadlinePropagatingListener.onMessage(DeadlinePropagatingClientInterceptor.java:169)
	at io.grpc.ForwardingClientCallListener.onMessage(ForwardingClientCallListener.java:33)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInternal(ClientCallImpl.java:667)
	at io.grpc.internal.ClientCallImpl$ClientStreamListenerImpl$1MessagesAvailable.runInContext(ClientCallImpl.java:654)
	at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:37)
	at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:133)
	... 3 common frames omitted


  • 레이블 없음