[번역] 당신이 (아마도) 몰랐던 20가지 Git 명령 🧙‍♂️

surim014·2022년 12월 29일
71

Article

목록 보기
7/7
post-thumbnail

원문: https://dev.to/lissy93/20-git-commands-you-probably-didnt-know-about-4j4o

git 매뉴얼을 찾아본 적이 있거나 man git을 실행해본 적이 있다면 git에는 우리가 주로 사용하는 것보다 훨씬 더 많은 것이 있다는 것을 알게 될 것입니다. 이런 많은 명령은 매우 강력하며 삶을 훨씬 더 편안하게 만들어 줄 수 있습니다. (어떤 것들은 약간 한정적이지만, 여전히 알아두면 좋습니다.)

이 게시물은 제가 가장 좋아하지만 잘 사용되지 않는 20가지 git 기능에 관해 설명합니다. 이 기능을 사용하면 개발 프로세스를 레벨업하는 것과 더불어 동료들에게 감동을 주고, git 인터뷰 질문을 답변하는 데 도움을 줄 수 있으며 가장 중요한 것은 즐거운 시간을 보낼 수 있습니다!

목차 (TL;DR)

Git Web - 내장된 GUI 열기
Git Notes - commit에 추가 정보 첨부
Git Bisect - 전문가처럼 디버깅
Git Grep - 무엇이든 검색
Git Archive - 공유를 위해 프로젝트 압축
Git Submodules - 다른 저장소를 내 저장소로 가져오기
Git Bugreport - 시스템 정보로 버그 보고서 컴파일
Git Fsck - 연결할 수 없는 객체 확인 및 복구
Git Stripspace - 후행 공백 제거
Git Diff - 두 파일 간의 변경 사항 비교
Git Hooks - git 명령이 실행될 때 스크립트 실행
Git Blame - 작성자 표시
Git Large File Storage - git에 대용량 파일 저장
Git Garbage Collection - git 저장소 최적화
Git Show - 모든 git 객체를 쉽게 검사
Git Describe - 마지막 태그를 기반으로 읽을 수 있는 이름 지정
Git Tag - 특정 지점에서 버전 태그 생성
Git Reflog - 저장소에서 수행된 모든 git 작업 나열
Git Log - commit 로그 및 브랜치 다이어그램 보기
Git Cherry Pick - 브랜치로 기능 가져오기
Git Switch - 브랜치 사이를 빠르게 점프
Git Standup - git commit을 기반으로 마지막 근무일에 수행한 작업을 기억
Bonus - 더 많은 명령으로 git 확장!

Git Web

git instaweb을 실행하여 작업 중인 저장소를 즉시 gitweb에서 둘러볼 수 있습니다.

Git에는 로컬 저장소 검색을 위한 웹 기반 비주얼라이저가 내장되어 있어 브라우저의 GUI를 통해 저장소를 보고 관리할 수 있으며 다음과 같은 유용한 기능이 포함되어 있습니다.

  • 수정 사항 검색 및 단계별 검토, 다른 점, 파일 내용 및 메타 데이터 검사
  • commit 로그, 브랜치, 디렉터리, 파일 기록 및 첨부된 데이터를 시각적으로 보기
  • commit 및 저장소 활동 기록의 RSS 또는 Atom 피드 생성
  • commit, 파일, 변경 사항 및 다른 점 검색

이것을 열려면, 당신의 저장소 안에서 git instaweb을 실행하기만 하면 되며, 브라우저에서 http://localhost:1234를 로드해야 합니다. 만약 Lighttpd가 설치되어 있지 않은 경우 -d 플래그를 사용하여 대체 웹 서버를 지정할 수 있습니다. 다른 옵션은 플래그(포트의 경우 -p, 브라우저의 경우 -b)를 통해 구성하거나 git 설정의 [instaweb]블록 아래에서 구성할 수 있습니다.

GUI 기반 git 앱을 열 수 있는 git gui 명령도 있습니다.

Git Notes

git notes를 사용하여 commit에 추가 정보를 첨부

때로는 변경 사항, 메시지, 날짜-시간 및 작성자 정보 이외의 추가 데이터를 git commit에 첨부해야 합니다.

메모는 .git/refs/notes에 저장되며 commit 객체 데이터와는 별개이므로 언제든지 SHA-1 해시를 변경하지 않고 commit과 관련된 메모를 수정할 수 있습니다.

git log, git GUI 앱 또는 git notes show 명령어를 사용하여 메모를 볼 수 있습니다. 일부 git 호스트는 commit을 표시할 때 메모도 함께 표시합니다. (GH는 더 이상 노트를 표시하지 않습니다.)

Git Bisect

git bisect를 사용하면 이진 검색을 사용하여 버그를 유발한 commit을 찾을 수 있습니다.

이것은 가장 강력하면서도 사용하기 쉬운 git 명령 중 하나입니다. bisect는 디버깅에 있어서 절대적인 생명의 은인입니다. bisect를 시작하면 commit을 판별할 수 있도록 해주는데, commit이 good(버그 없음) 또는 bad(버그 발견)를 알려주면 버그를 유발한 가장 초기 commit으로 범위를 좁혀나갈 수 있습니다.

시작하려면 git bisect start를 실행한 다음, git bisect good <commit-hash>를 사용하여 버그가 없는 좋은 commit을 전달하고 git bisect bad <optional-hash>를 사용하여 버그가 있는 나쁜 commit(기본값은 현재 commit)을 전달합니다. 그럼 좋은 commit과 나쁜 commit 중간의 commit으로 checkout 되고, 이때 또 git bisect good 또는 git bisect bad 중 하나로 버그가 존재하는지 지정합니다. 버그가 도입된 commit을 찾을 때까지 이 프로세스를 반복하여 나쁜 commit과 좋은 commit의 중간에 있는 commit을 확인합니다. git bisect reset을 사용하면 언제든지 취소할 수 있습니다.

다시 보기, commit 보기, 건너뛰기 등 bisect 명령어에는 훨씬 더 많은 기능이 있으므로 다음에 디버깅할 때 문서를 확인해 보는 것이 좋습니다.

Git Grep

git grep을 사용하여 저장소에서 코드, 파일, commit 또는 기타 항목 검색할 수 있습니다.

git 프로젝트 내에서 문자열을 검색해야 하는 경우가 있으셨나요? git grep을 사용하면 어떠한 문자열 또는 정규식을 통해 프로젝트 전체와 브랜치를 걸쳐 Ctrl + F보다 강력하고 쉽게 검색할 수 있습니다.

git grep <regexp> <ref>

이 명령어에는 검색 범위를 좁히거나 결과 형식을 지정할 수 있는 다양한 옵션이 포함되어 있습니다. 예를 들어, 파일 이름만 반환하려면 -l 사용, 반환할 파일당 일치 항목 수를 지정하려면 -c 사용, 조건과 일치하는 결과를 제외하려면 -e 사용, --and로 여러 조건을 지정, 그리고 줄 번호로 검색하려면 -n을 사용합니다.

git grep은 정규식과 호환되므로 검색하는 문자열을 훨씬 더 발전시킬 수 있습니다.
또한 git grep 'console.log' *.js와 같이 파일 확장자를 지정하여, 자바스크립트 파일 내의 모든 console.log를 표시할 수 있습니다.

두 번째 매개 변수는 참조이며 브랜치 이름, commit, commit 범위 또는 기타 항목이 될 수 있습니다. 예를 들어 git grep "foo" HEAD~1은 이전 commit을 검색합니다.

Git Archive

git archive를 사용하여 전체 저장소를 단일 파일로 결합할 수 있습니다.

저장소를 공유하거나 백업할 때는 단일 파일로 저장하는 것이 좋습니다. git archive를 사용하면 모든 저장소 기록이 포함되므로 쉽게 원래 형태로 압축을 풀 수 있습니다. 또한 이 명령어에는 많은 추가 옵션이 포함되어 있어 아카이브에 포함할 파일과 포함하지 않을 파일을 사용자 정의할 수 있습니다.

git archive --format=tar --output=./my-archive HEAD

Git Submodules

git submodule을 사용하여 다른 저장소를 자신의 저장소로 가져옵니다.

git의 submodules을 사용하면 하나의 저장소를 다른 저장소에 마운트할 수 있으며, 일반적으로 코어 종속성 또는 컴포넌트를 별도의 저장소로 분할하는 데 사용됩니다. 자세한 내용은 이 게시물을 참조하세요.

다음 명령을 실행하면 모듈을 지정된 위치로 pull하고 저장소가 복제될 때 항상 다운로드되도록 .gitmodules 파일도 생성합니다. --recursive 플래그를 사용하면 저장소를 복제할 때 하위 모듈을 포함합니다.

git submodule add https://github.com/<user>/<repo> <path/to/save/at>

유사한 작업을 수행하지만 메타데이터 파일이 필요하지 않은 git subtree도 있습니다.

Git Bug Report

git bugreport를 사용하여 git 및 시스템 정보를 포함한 버그 티켓 작성할 수 있습니다.

이 명령어는 시스템 정보를 캡처한 다음 표준 버그 템플릿(재현 단계, 실제 + 예상 출력 등)을 엽니다. 완성된 파일은 필요한 모든 정보가 캡처된 매우 완전한 버그 보고서여야 합니다.

필요한 모든 데이터가 포함되어 있는지 확인하므로 오픈 소스 패키지의 관리자가 사용자(개발자)에게 버그 보고서를 제출하도록 요청하는 경우에 매우 편리합니다.

코어 git 시스템에 버그 리포트를 제출하는 경우, git diagnostic 명령어를 실행한 다음 여기에서 문제를 제기할 수도 있습니다.

Git Fsck

git fsck를 사용하여 모든 객체를 확인하거나 연결할 수 없는 객체를 복구합니다.

자주 필요한 것은 아니지만 git에 의해 저장된 객체를 확인해야 할 수도 있습니다. 이 때 fsck(또는 File System ChecK)를 통해서 객체 데이터베이스를 테스트하고 모든 객체의 SHA-1 ID를 검증하고 연결을 확인합니다.

또한 다른 명령과 달리 .git/objects의 모든 항목이 포함되기 때문에 --unreachable 플래그와 함께 사용하여 명명된 참조에서 더 이상 연결할 수 없는 객체를 찾을 수 있습니다.

Git Stripspace

git stripspace를 사용하여 주어진 파일 내의 공백 형식 지정할 수 있습니다.

가장 좋은 방법은 줄 끝에 후행 공백을 피하고 여러 개의 빈 줄이 연속되지 않도록 하며, 입력의 시작과 끝에서 빈 줄을 피하고 각 파일을 새 줄로 끝내는 것입니다. prettier와 같이 이 작업을 자동으로 수행하는 언어별 도구가 많이 있지만 Git에도 이 기능이 내장되어 있습니다.

이것은 메타데이터(commit 메시지, 태그, 브랜치 설명 등)를 위한 것이지만 파일에 파이프를 연결한 다음 응답을 다시 파일에 파이프(|)를 연결하는 경우에도 작동합니다. 예를 들어, cat ./path-to-file.txt | git stripspace 또는 git stripspace < dirty-file.txt > clean-file.txt

또한 --strip-comments를 함께 사용하여 주석을 제거하거나 --comment-lines를 함께 사용하여 줄을 주석 처리할 수도 있습니다.

Git Diff

git diff를 사용하면 두 코드 간의 차이점을 비교할 수 있습니다.

git diff를 실행하여 마지막 commit 이후의 모든 변경 사항을 표시하거나 git diff <commit-sha>를 사용하여 2개의 commit 또는 1개의 commit을 HEAD와 비교할 수 있다는 것을 알고 있을 것입니다. 하지만 diff 명령으로 할 수 있는 것은 훨씬 더 많습니다.

또한 diff file-1.txt file-2.txt를 사용하여 임의의 두 파일을 비교하는 데 사용할 수도 있기 때문에 더 이상 diffchecker.com를 방문하지 않아도 됩니다!

또는 git diff branch1..branch2를 사용하여 2개의 브랜치 또는 참조를 서로 비교합니다.

이중 점(..)은 공백과 동일하며 diff 입력이 브랜치의 끝이어야 함을 나타내지만, 트리플 점(...)을 사용하여 첫 번째 파라미터를 두 diff 입력 사이에 공유된 공통 조상 commit의 ref로 변환할 수도 있습니다. 이것은 매우 유용합니다! 브랜치 간에 단일 파일만 비교하려면 파일 이름을 세 번째 인수로 전달하면 됩니다.

지정된 날짜 범위 내에서 변경된 모든 내용을 확인하기 위해 git diff HEAD@{7.day.ago} HEAD@{0}(지난 주)를 사용합니다. 이것은 파일 이름, 브랜치 이름, 특정 commit 또는 기타 참조와 쌍을 이룰 수 있습니다.

commit 범위를 비교하기 위한 간단한 인터페이스를 제공하는 git range-diff 명령어도 있습니다.

git diff 툴에는 자신의 diff checker를 사용하는 옵션뿐만 아니라 훨씬 더 많은 것이 있으므로 문서를 확인하는 것을 추천합니다.

Git Hooks

주어진 get 작업이 발생할 때 명령을 실행하거나 스크립트를 실행하는 데 hooks를 사용 합니다.

Hooks를 사용하면 거의 모든 것을 자동화할 수 있습니다. 예를 들어 표준이 충족되는지 확인(commit 메시지, 브랜치 이름, 패치 크기), 코드 품질(테스트, 린트), commit에 부가 정보 추가(사용자, 장치, 티켓 ID), 이벤트 기록 또는 파이프라인 실행을 위해 webhook 호출 등이 있습니다.

commit, rebase, merge, push, update, applypatch 등과 같은 대부분의 git 이벤트에 사용할 수 있는 사전 및 사후 hook이 있습니다.

hook은 git config core.hooksPath를 사용하여 다른 위치에 구성하지 않는 한 .git/hooks에 저장되며 git hook 명령어로 테스트할 수 있습니다. 이것은 쉘 파일일 뿐이므로 모든 명령을 실행하는 데 사용할 수 있습니다.

hook은 원격 저장소로 push되지 않으므로 팀 전체에서 hook을 공유하고 관리하려면 lefthook 또는 husky와 같은 hook manager를 사용해야 합니다. hook을 더 쉽게 관리할 수 있는 여러 타사 도구도 있습니다. overcommit을 권장 합니다.

hook은 --no-verify플래그를 사용하여 항상 건너뛸 수 있으므로 특히 보안과 관련된 모든 경우에 hook에만 전적으로 의존하지 마십시오.

Git Blame

git blame은 특정 수정 사항 및 라인에 대한 작성자 정보를 표시하는 데 사용합니다.

누가 특정 코드 라인을 작성했는지 빠르게 찾아줍니다.(이 버그에 대한 책임이 있는 동료가 누구인지!) 뿐만아니라, 이것은 변경된 시점을 확인하고 해당 commit 및 관련 메타데이터를 검사하는 데도 유용합니다.

예를 들어 index.rs의 400~420행에 대한 작성자 및 commit 정보를 보려면 다음을 실행합니다.

git blame -L 400,420 index.rs

Git LFS

git lfs를 사용하여 대용량 파일을 저장할 때 저장소가 다운되지 않도록 하세요.

종종 프로젝트에 데이터베이스, 바이너리 에셋, 아카이브 또는 미디어 파일과 같은 더 큰 파일이 포함되어 git 워크플로우가 느려지고 사용 한도에 달하게 됩니다. 대용량 파일 스토리지는 이러한 대용량 자산을 다른 곳에 저장하는 동시에 git으로 추적할 수 있고 동일한 액세스 제어/권한을 유지할 수 있도록 지원합니다. LFS는 이러한 큰 파일을 git 내에서 추적되는 텍스트 포인터로 대체하여 작동합니다.

git lfs track <file glob>을 통해 실행할 수 있고, .gitattributes 파일이 업데이트됩니다. 확장자(예: *.psd), 디렉토리 또는 개별적으로 파일을 지정할 수 있습니다. 추적하고 있는 LFS 파일 목록을 보기 위해 git lfs ls-files를 실행 중입니다.

Git GC

git gc를 사용하여 저장소 최적화할 수 있습니다.

시간이 지남에 따라 git 저장소에는 다양한 유형의 가비지가 축적되어 디스크 공간을 차지하고 작업 속도를 늦춥니다. 이곳이 내장된 가비지 컬렉터가 필요한 곳입니다. git gc를 실행하면 git prune을 포함하는 고립되고 액세스할 수 없는 commit, 파일 수정 사항 및 저장된 git 객체를 압축할 뿐만 아니라 ref 압축, reflog 가지치기, revere 메타데이터 또는 오래된 워킹 트리 및 인덱스 업데이트와 같은 오래된 것과 같은 기타 일반적인 하우스 키핑 작업을 수행 합니다.

--aggressive 플래그를 추가하면 저장소를 적극적으로 최적화 하여 기존 델타를 버리고 다시 계산합니다. 이 작업은 실행하는 데 훨씬 더 오랜 시간이 걸리지만 큰 저장소가 있는 경우에는 필요할 수 있습니다.

Git Show

git show를 사용하여 모든 git 객체를 쉽게 검사할 수 있습니다.

블롭, 트리, 태그 또는 commit 객체를 쉽게 읽을 수 있는 형태로 출력합니다. 사용하려면 git show <object>를 실행하세요. 더욱 명확한 출력을 위해 --pretty 플래그를 추가할 수도 있지만 --format을 사용하여 출력을 사용자 정의할 수 있는 다른 옵션이 많이 있으므로 이 명령은 필요한 것을 정확하게 표시하는 데 매우 강력할 수 있습니다.

브랜치를 전환하지 않고 다른 브랜치의 파일을 미리 보는 것은 매우 유용합니다. 그냥 git show branch:file을 실행하세요.

Git Describe

git describe는 commit에서 연결할 수 있는 최신 태그를 찾고 읽을 수 있는 이름을 지정하는 데 사용합니다.

git describe를 실행하면 마지막 태그 이름과 현재 commit을 결합한 문자열을 생성하여 만든 사람이 읽을 수 있는 문자열이 표시됩니다. 특정 태그를 전달할 수도 있습니다.

--all 플래그를 추가하지 않는 한 이것이 작동하려면 태그를 생성해야 합니다. Git describe는 기본적으로 주석이 달린 태그만 사용하므로 경량 태그도 사용하려면 --tags 플래그를 지정해야 합니다.

Git Tag

git tag를 사용하여 저장소 기록의 특정 지점에 태그 지정할 수 있습니다.

릴리즈 버전을 나타내는 데 가장 일반적으로 사용되는 저장소 기록의 특정 중요 지점에 태그를 지정할 수 있으면 종종 유용합니다. 태그를 생성하는 것은 git tag <tagname>만큼 간단하거나 git tag -a v4.2.0 <commit sha>로 기록 commit에 태그를 지정할 수 있습니다. commit과 마찬가지로 -m을 사용하여 태그 옆에 메시지를 포함할 수 있습니다.

git push origin <tagname>을 사용하여 태그를 원격으로 push하는 것을 잊지 마세요. 모든 태그를 나열하려면 git tag를 실행하고 와일드카드 검색을 하려면 -l을 사용하세요. 그런 다음 git checkout <tagname>을 사용하여 특정 태그로 checkout할 수 있습니다.

Git Reflog

git reflog를 사용하여 저장소에서 수행한 모든 업데이트를 나열합니다.

Git은 참조 로그 또는 "reflogs"라는 메커니즘을 사용하여 브랜치 끝에 대한 업데이트를 추적합니다. clone, pull, push, commit, checkout 및 merge를 포함한 다양한 이벤트가 추적됩니다. 많은 명령에서 ref를 매개 변수로 사용하므로 이벤트 참조를 찾을 수 있는 것이 유용한 경우가 많습니다. HEAD의 최근 이벤트를 보려면 git reflog를 실행하세요.

reflog는 손실된 commit을 복구하는 데 매우 유용합니다. Git은 rebase 또는 commit 수정과 같은 것을 통해 히스토리를 다시 작성한다 해도 실제로 손실되는 것이 없습니다. Reflog를 사용하면 브랜치나 태그에서 참조하지 않더라도 commit으로 돌아갈 수 있습니다.

기본적으로 reflog는 HEAD(현재 분기)를 사용하지만 모든 ref에서 reflog를 실행할 수 있습니다. 예를 들어, git reflog show <branch name>을 표시하거나 git reflog stash를 사용하여 숨겨진 변경 사항을 확인합니다. 또는 git reflog show --all을 사용하여 모든 참조를 표시합니다.

Git Log

git log를 commit 목록을 보는 데 사용할 수 있습니다.

현재 브랜치에서 최근 commit 목록을 보기 위해 git log를 실행하는 데 이미 익숙할 것입니다. 하지만 git log로 할 수 있는 일이 몇 가지 더 있습니다.

git log --graph --decorate --oneline를 사용하면 ref 포인터와 함께 깔끔한 commit 그래프가 표시됩니다.

또한 다양한 매개변수를 기반으로 로그를 필터링할 수 있어야 하는 경우가 종종 있습니다. 가장 유용한 매개변수는 다음과 같습니다.

  • git log --search="<anything>" - 특정 코드 변경에 대한 로그 검색
  • git log --author="<pattern>" - 특정 작성자에 대한 로그만 표시
  • git log --grep="<pattern>" - 검색어 또는 정규식을 사용하여 로그 필터링
  • git log <since>..<until> - 두 참조 간의 모든 commit 표시
  • git log -- <file> - 특정 파일에 대한 모든 commit 표시

또는 git shortlog를 실행해 요약된 commit 목록을 볼 수 있습니다.

Git Cherry Pick

git cherry-pick은 참조로 지정된 commit을 선택하고 작업중인 HEAD에 추가하는 데 사용합니다.

다른 곳에서 현재 브랜치로 특정 commit을 가져와야 하는 경우가 있습니다. 이는 핫픽스 적용, 변경 실행 취소, 손실된 commit 복원 및 특정 팀 협업 설정에 매우 유용할 수 있습니다. 다만, 로그에 중복 commit이 발생할 수 있으므로 전통적인 병합이 더 나은 경우가 많습니다.

사용법은 간단합니다. 그냥 git cherry-pick <commit-hash>를 실행하세요. 이렇게 하면 지정된 commit이 현재 브랜치로 pull 됩니다.

Git Switch

git switch 사용

브랜치 간 이동은 우리가 자주 하는 작업입니다. 이 switch 명령어는 git checkout의 단순화된 버전과 같으며 브랜치 간에 생성하고 탐색하는 데 사용할 수 있지만 checkout과 달리 브랜치 간에 이동할 때 수정된 파일을 복사하지 않습니다.

checkout -b와 유사하게 switch 명령어를 사용하여 -c 플래그를 추가하여 새 브랜치를 생성하고 git switch -c <new branch>와 같이 해당 브랜치로 이동할 수 있습니다. git switch -를 실행하면 실험적으로 변경한 사항이 모두 삭제되고 이전 브랜치로 돌아갑니다.

Git Standup

git standup은 git commit을 기반으로 마지막 근무일에 수행한 작업을 기억하는 데 사용합니다.

이것은 대부분의 git 클라이언트에 포함되어 있지 않기 때문에 마지막에 넣었지만, 시스템 패키지 관리자를 사용하거나 1줄 curl 스크립트를 사용하거나 소스에서 빌드하여 쉽게 설치할 수 있습니다.

당신의 상사가 당신에게 어제 일에 대한 업데이트를 제공하기 위해 매일 스탠드업을 요구하지만 당신이 실제로 무엇을 했는지 결코 기억할 수 없다면 - 이것은 당신을 위한 것입니다! 주어진 시간 프레임에서 수행된 모든 작업을 멋진 형식의 목록으로 표시해줍니다. 사용법은 간단합니다. 그냥 git standup을 실행하거나 여러 옵션을 사용하여 표시할 데이터(작성자, 기간, 분기 등)를 지정합니다.

Bonus

Git은 유용한 작업을 수행하는 추가 명령을 추가하기 위해 추가 기능으로 쉽게 확장할 수 있습니다. 가장 완벽한 확장 기능 중 하나는 @tjgit-extras입니다. 일반적인 git 작업을 자동화하기 위한 70개 이상의 추가 명령어를 제공합니다.

더 유용한 git 애드온 목록은 stevemao/awesome-git-addons를 참조하세요.

GitHub 저장소로 작업하는 경우 GitHub CLI를 사용하면 CLI에서 일반적인 작업(PR 관리, 이슈, 코드 리뷰 등)을 수행할 수 있습니다.

profile
FrontEnd Developer

3개의 댓글

comment-user-thumbnail
2023년 1월 4일

Your content helped me a lot to take my doubts

답글 달기
comment-user-thumbnail
2023년 1월 6일

오.. 재밌고 유용한 기능이 많네요!! 좋은 정보 감사합니다 ㅎㅎ

답글 달기
comment-user-thumbnail
6일 전

These git commands help me to post my project on an online platform. I will hire someone to write a paper for me so that I can easily recall these commands and implement in my project.

답글 달기