모든 심각한 Github 저장소는 왜 커밋을 단일 커밋으로 스쿼시하기를 원합니까?
나는 git log가 거기에 있다고 생각했기 때문에 모든 기록을 검사하고 어떤 변화가 어디서 발생했는지 정확하게 볼 수 있지만 그것을 스쿼시하면 기록에서 꺼내어 하나의 커밋으로 묶습니다. 요점이 뭐야?
이것은 또한 "미리 커밋하고 자주 저지르는"진언에 위배되는 것으로 보인다.
모든 심각한 Github 저장소는 왜 커밋을 단일 커밋으로 스쿼시하기를 원합니까?
나는 git log가 거기에 있다고 생각했기 때문에 모든 기록을 검사하고 어떤 변화가 어디서 발생했는지 정확하게 볼 수 있지만 그것을 스쿼시하면 기록에서 꺼내어 하나의 커밋으로 묶습니다. 요점이 뭐야?
이것은 또한 "미리 커밋하고 자주 저지르는"진언에 위배되는 것으로 보인다.
답변:
따라서 변경 사항과 그 이유를 명확하고 쉽게 문서화하는 명확하고 간결한 git history가 있습니다.
예를 들어, 일반적인 'unsquashed'git 로그는 다음과 같습니다.
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
787g8fgf78... hotfix for #5849564648
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
엉망이야!
메시지에 약간의 추가 초점을 둔 좀 더 신중하게 관리되고 병합 된 git 로그는 다음과 같습니다.
7hgf8978g9... 8483948393 Added new slideshow feature
787g8fgf78... 5849564648 Hotfix for android display issue
9080gf6567... 6589685988 Implemented pop-up to select language
나는 커밋을 스 쿼싱하는 요점을 일반적으로 볼 수 있으며 동일한 원칙이 요청을 가져 오는 데 적용된다- 역사의 가독성. 이미 수백 또는 수천 개의 커밋이있는 커밋 로그에 추가 할 수 있으며,이를 통해 증가하는 기록을 짧고 간결하게 유지할 수 있습니다.
일찍 그리고 자주 커밋하고 싶습니다. 여러 가지 이유로 모범 사례입니다. 나는 이것이 종종 git을 사용하여 작업하고 도움이되는 작업 포인트를 제공하는 "wip"(진행중인 작업) 또는 "part A done"또는 "typo, minor fix"인 커밋을 자주 보게합니다. 작업을 진행하면서 다음 코드가 작동하지 않으면 다시 돌아갈 수 있습니다. 그러나 나는 마지막 git history의 일부로 그 역사를 필요로하지 않거나 원하지 않기 때문에 커밋을 스쿼시 할 수 있습니다. 그러나 개발 브랜치 대 마스터에서 이것이 의미하는 바는 아래 참고 사항을 참조하십시오.
별개의 작업 단계를 나타내는 주요 이정표가있는 경우 기능 / 태스크 / 버그 당 둘 이상의 커밋을 갖는 것이 좋습니다. 그러나 이것은 종종 개발중인 티켓이 '너무 크다'는 사실을 강조 할 수 있습니다.
8754390gf87... Implement feature switches
"1 작품"인 것 같습니다. 그들은 존재하거나 존재하지 않습니다! 그것을 깨는 것이 의미가없는 것 같습니다. 그러나 경험에 따르면 (조직 규모와 복잡성에 따라)보다 세분화 된 경로가 될 수 있습니다.
fgfd7897899... Add field to database, add indexes and a trigger for the dw group
9458947548g... Add 'backend' code in controller for when id is passed in url.
6256ac24426... Add 'backend' code to make field available for views.
402c476edf6... Add feature to UI
작은 조각은 더 쉬운 코드 검토, 더 쉬운 단위 테스트, 더 나은 qa 기회, 단일 책임 원칙에 대한 더 나은 조정 등을 의미합니다.
실제로 그러한 과즙을 언제해야 하는가를 위해 기본적으로 자체 워크 플로가있는 두 가지 단계가 있습니다.
개발하는 동안 '초기 및 자주'그리고 빠른 '일회용'메시지를 커밋합니다. 예를 들어 wip에서 스쿼시 및 할 일 메시지 커밋과 같이 때때로 스쿼시를 원할 수도 있습니다. 브랜치 내에서 개발 단계에서 수행 한 고유 한 단계를 나타내는 여러 커밋을 유지하는 것이 좋습니다. 당신이하기로 선택한 대부분의 과즙은이 기능 지점 안에 있어야하며, 개발되는 동안 그리고 합병하기 전에이 기능 지점에 있어야합니다.
메인 라인 브랜치에 추가 할 때 커밋은 기존 메인 라인 히스토리에 따라 간결하고 올바르게 형식화되기를 원합니다. 여기에는 예와 같이 티켓 추적기 시스템 ID (예 : JIRA)가 포함될 수 있습니다. 스 쿼싱은 마스터에서 여러 가지 커밋을 '롤업'하지 않는 한 실제로 적용되지 않습니다. 일반적으로 당신은하지 않습니다.
--no-ff
마스터로 병합 할 때 사용 하면 병합에 하나의 커밋을 사용하고 분기 (히스토리)의 기록도 보존합니다. 일부 조직에서는 이것이 최선의 방법이라고 생각합니다. 자세한 내용은 https://stackoverflow.com/q/9069061/631619 를 참조하십시오. 또한 커밋이 HEAD 상단 (최근에 완료된 경우)에서 최신 커밋이 git log
되는 실제적인 효과를 볼 수 있습니다. 날짜 및 기타 커밋에 따라 기록에서 더 아래로 내려갑니다.--no-ff
--no-ff
PR을 당기는 사람은 커밋 "추가 된 기능 X"의 순 효과에 관심을 갖기 때문에 "기본 템플릿, 버그 수정 함수 X, 함수 Y 추가, 주석의 오타 수정, 조정 된 데이터 스케일링 매개 변수, 해시 맵보다 성능이 향상됩니다. list "... 세부 사항 레벨
16 개의 커밋이 1 개의 "추가 된 기능 X, X를 사용하도록 Z를 리팩토링 한 것"이 아닌 2 개의 커밋으로 가장 잘 표현된다고 생각한다면 2 개의 커밋을 가진 pr을 제안하는 것이 좋을 것입니다. 그러나 제안하는 것이 가장 좋습니다. 이 경우 별도의 PR 2 개 (리포지토리가 여전히 단일 커밋 PR을 주장하는 경우)
이것은 레포지토리에서와 같이 "자신의 커밋과 커밋"에 반대하지 않으며, 개발하는 동안 여전히 세부적인 세부 사항을 가지므로 작업 손실 가능성이 최소화되며 다른 사람들이 검토 / 풀링 / 제안 할 수 있습니다 새로운 홍보가 개발되는 동안 홍보는 당신의 일에 위배됩니다.
내가 볼 수있는 주된 이유는 다음과 같습니다.
Merge pull request #123 from joebloggs/fix-snafoo
--first-parent
관점--first-parent
(이것은 Git 2.6.2에서만 수정되었으므로 GitHub가 그것을 가지고 있지 않은 것을 용서할 수 있습니다 유효한)따라서 위의 세 가지 상황을 모두 결합하면 스쿼시되지 않은 커밋이 GitHub UI에서보기 흉하게 병합되는 상황이 발생합니다.
숙취 된 커밋을 가진 당신의 역사는 다음과 같이 보일 것입니다
1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... Hotfix for android display issue
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... Implemented pop-up to select language
스쿼시 커밋이 없으면 역사는 다음과 같이 보일 것입니다.
1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... hotfix for #5849564648
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
PR 추적에 많은 커밋이있을 때 GitHub UI 사용으로 자신을 제한하면 변경 사항이 발생한 악몽이 될 수 있습니다 .
예를 들어, 파일 어딘가에서 널 포인터가 역 참조되는 것을 발견하여 "누가 언제, 언제? 어떤 릴리스 버전이 영향을 받습니까?"라고 말합니다. 그런 다음 GitHub UI에서 Blame보기로 돌아간 후 라인이 변경되었음을 알 수 있습니다.789fdfffdf
... "오, 잠깐만 요, 그 줄은 코드의 나머지 부분에 맞게 들여 쓰기가 바뀌 었습니다."이제 부모 커밋에서 해당 파일의 트리 상태로 이동하고 다시 방문해야합니다. 비난 페이지 ... 결국 당신은 커밋을 발견 ... 그것은 6 개월 전에 커밋 ... "오 **** 이것은 6 개월 동안 사용자에게 영향을 미칠 수 있습니다"당신은 말합니다 ... 아 그러나 그 커밋 실제로 풀 요청 (Pull Request)에 있었으며 어제 합병되었으며 아직 릴리스를 중단 한 사람은 없습니다. GitHub UI
이제 (대한 수정을 가지고 있으며, 슈퍼 멋진 2.6.2 망할 놈의 명령 줄을 사용하는 경우 우리는 이것이 어떻게 작동하는지 살펴 보자 git blame --first-parent
)
커밋 히스토리는
$ git log
1256556316... #423 Added new slideshow feature
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... #324 Hotfix for android display issue
787g8fgf78... hotfix for #5849564648
f56556316e... #28 Implemented pop-up to select language
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test
그러나 우리는 또한 할 수 있습니다
$ git log --first-parent
1256556316... #423 Added new slideshow feature
56556316ad... #324 Hotfix for android display issue
f56556316e... #28 Implemented pop-up to select language
(즉, Git CLI를 사용하면 케이크를 가지고 먹을 수도 있습니다)
이제 널 포인터 문제에 부딪쳤을 때 ... 잘 사용 git blame --first-parent -w dodgy-file.c
하면 간단한 공백 변경을 무시하고 널 포인터 역 참조가 마스터 브랜치에 도입 된 정확한 커밋이 즉시 제공됩니다.
물론 GitHub UI를 사용하여 병합을 수행하는 경우 git log --first-parent
병합 커밋 메시지의 첫 번째 줄을 강제로 적용하는 GitHub 덕분에 실제로 엉터리입니다.
1256556316... Merge pull request #423 from jrandom/add-slideshows
56556316ad... Merge pull request #324 from ahacker/fix-android-display
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
긴 이야기를 짧게 줄이려면 :
GitHub UI (2015 년 10 월)에는 풀 요청을 병합하는 방법, 커밋 기록을 표시하는 방법 및 비난 정보의 속성을 나타내는 방법에 대한 여러 가지 단점이 있습니다. GitHub UI에서 이러한 결함을 해킹하는 가장 좋은 방법은 병합하기 전에 커밋을 스쿼시하도록 요청하는 것입니다.
Git CLI에는 이러한 문제가 없으며보고자하는보기를 쉽게 선택할 수 있으므로 특정 변경이 그 이유 (발견되지 않은 커밋의 이력을보고)를 변경 한 이유를 발견 할 수 있습니다. 효과적으로 저지른 커밋을 참조하십시오.
커밋을 스쿼시하는 데 자주 인용되는 마지막 이유는 백 포트를 더 쉽게 만드는 것입니다. 백 포트에 커밋이 하나만있는 경우 (즉, 스쿼시 된 커밋) 체리 선택이 쉽습니다.
글쎄 당신이 git history를보고 있다면 git log --first-parent
병합 커밋을 체리 선택할 수 있습니다. -m N
옵션 을 지정해야하기 때문에 대부분의 사람들은 혼란스러운 체리 따기 병합 커밋을 얻습니다. 그러나 커밋을 얻은 경우 git log --first-parent
그것이 따라야 할 첫 번째 부모라는 것을 알고 있으므로git cherry-pick -m 1 ...
--first-parent
;-) 부수 커밋에 대한 논쟁에서 승리하기 위해 자신을
추가 된 기능 및 수정 된 버그에 대한 명확하고 간결한 이력을 보여주는이 스레드의 다른 답변에 표현 된 감정에 동의합니다. 그러나 귀하의 질문은 피했지만 명시 적으로 언급하지 않은 다른 측면을 다루고 싶습니다. git의 작업 방법 중 일부에 대한 행 아웃의 일부는 git을 사용하면 그러한 작업이 불가능한 다른 형태의 소스 제어를 사용한 후 git에 도입되었을 때 이상하게 보이는 기록을 다시 작성할 수 있다는 것입니다. 또한 이것은 소스 제어에 대해 커밋 / 체크인 된 후에는 커밋 이후에 어떤 변경이 있더라도 해당 상태로 되돌릴 수 있다는 일반적으로 허용되는 소스 제어 원칙에 위배됩니다. 당신이 당신의 질문에 암시하는 것처럼, 이것은 그러한 상황 중 하나입니다. git은 훌륭한 버전 관리 시스템이라고 생각합니다. 그러나 그것을 이해하기 위해서는 구현 세부 사항과 디자인 결정의 일부를 이해해야하며 결과적으로 학습 곡선이 가파 릅니다. git은 분산 버전 제어 시스템으로 고안되었으며 디자이너가 왜 git history를 스쿼시 커밋으로 다시 작성 해야하는지 설명하는 데 도움이됩니다.
git gc
참조되지 않은 객체를 삭제하기 위해 실행 된 경우 가 아니면 reflog를 사용하여 항상 이전 상태로 돌아갈 수 있습니다 .
관점 때문에 ... 가장 좋은 방법은 <<issue-management-system>>
가능한 경우 단일 문제당 단일 커밋을 갖는 것 입니다.
자신의 기능 브랜치 / 리포지토리에서 원하는만큼 커밋을 할 수는 있지만 현재 관점에서 수행하는 작업과 관련이있는 역사입니다 ... 그는 전체 팀 / 프로젝트 또는 응용 프로그램의 역사가 아닙니다. 몇 달 후부터 유지 될 전망 ...
따라서 일반적인 리포지토리 (이 예제는 develop 브랜치에 있음)에 버그 수정 또는 기능을 커밋 할 때마다 다음과 같이 수행 할 수있는 작업을 수행 할 수 있습니다.
# set your current branch , make a backup of it , caveat minute precision
curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr
# squash all your changes at once
git reset $(git merge-base develop $curr_branch)
# check the modified files to add
git status
# add the modified files dir by dir, or file by file or all as shown
git add --all
# check once again
git log --format='%h %ai %an %m%m %s' | less
# add the single message of your commit for the stuff you did
git commit -m "<<MY-ISSUE-ID>>: add my very important feature"
# check once again
git log --format='%h %ai %an %m%m %s' | less
# make a backup once again , use seconds precision if you were too fast ...
curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr
# compare the old backup with the new backup , should not have any differences
git diff <<old-backup>>..<<new-backup-branch>>
# you would have to git push force to your feature branch
git push --force