development

모든 자식 커밋을 하나로 스쿼시하는 방법은 무엇입니까?

big-blog 2020. 2. 20. 23:29
반응형

모든 자식 커밋을 하나로 스쿼시하는 방법은 무엇입니까?


전체 저장소를 첫 번째 커밋까지 어떻게 스쿼시합니까?

첫 번째 커밋에 리베이스 할 수는 있지만 2 개의 커밋이 남습니다. 첫 번째 커밋 전에 커밋을 참조하는 방법이 있습니까?


아마도 가장 쉬운 방법은 현재 작업 복사본의 상태로 새 저장소를 만드는 것입니다. 모든 커밋 메시지를 유지하려면 먼저 git log > original.log새 리포지토리에서 초기 커밋 메시지에 대한 커밋 메시지를 편집하고 편집하십시오.

rm -rf .git
git init
git add .
git commit

또는

git log > original.log
# edit original.log as desired
rm -rf .git
git init
git add .
git commit -F original.log

최신 버전의 git에서는을 사용할 수 있습니다 git rebase --root -i.

첫 번째 커밋을 제외한 각 커밋에 대해로 변경 pick하십시오 squash.


최신 정보

별칭을 만들었습니다 git squash-all.
사용법 예 : git squash-all "a brand new start".

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} -m \"${1:-A new start}\");};f"

주의 사항 : 주석을 제공해야합니다. 그렇지 않으면 기본 커밋 메시지 "A new start"가 사용됩니다.

또는 다음 명령으로 별명을 작성할 수 있습니다.

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} -m "${1:-A new start}");};f'

짧막 한 농담

git reset $(git commit-tree HEAD^{tree} -m "A new start")

참고 : 여기 " A new start"는 예일 뿐이며, 자신의 언어를 자유롭게 사용하십시오.

TL; DR

스쿼시 할 필요가 없으며 git commit-tree고아 커밋을 만들고 함께 사용하십시오.

설명

  1. 통해 단일 커밋을 만들 git commit-tree

    무엇입니까 git commit-tree HEAD^{tree} -m "A new start":

    제공된 트리 오브젝트를 기반으로 새 커미트 오브젝트를 작성하고 stdout에서 새 커미트 오브젝트 ID를 생성합니다. -m 또는 -F 옵션이 제공되지 않으면 표준 입력에서 로그 메시지를 읽습니다.

    표현식 HEAD^{tree}은에 해당하는 트리 개체 HEAD, 즉 현재 분기의 끝을 의미합니다. Tree-ObjectsCommit-Objects를 참조하십시오 .

  2. 현재 분기를 새로운 커밋으로 재설정

    그런 다음 git reset현재 분기를 새로 만든 커밋 개체로 재설정하십시오.

이런 식으로, 작업 공간의 어떤 것도 건드리지 않으며 리베이스 / 스쿼시가 필요하지 않아서 정말 빠릅니다. 그리고 필요한 시간은 저장소 크기 또는 기록 깊이와 관련이 없습니다.

변형 : 프로젝트 템플릿의 새로운 저장소

이것은 다른 저장소를 템플릿 / 아키 타입 / 시드 / 스켈레톤으로 사용하여 새 프로젝트에서 "초기 커밋"을 생성하는 데 유용합니다. 예를 들면 다음과 같습니다.

cd my-new-project
git init
git fetch --depth=1 -n https://github.com/toolbear/panda.git
git reset --hard $(git commit-tree FETCH_HEAD^{tree} -m "initial commit")

이렇게하면 템플릿 저장소를 원격 ( origin또는 기타) 으로 추가하지 않아도 되고 템플릿 저장소의 기록이 초기 커밋으로 축소됩니다.


당신이하고 싶은 모든 커밋을 루트 커밋으로 스쿼시하는 것입니다.

git rebase --interactive --root

리베이스 작업은 대화식 리베이스 편집기 커밋 목록을 생성하고 리베이스 자체를 실행하기 위해 매우 느리게 실행되기 때문에 많은 수의 커밋 (예 : 수백 개의 커밋)에는 비실용적입니다.

많은 커밋을 스쿼시 할 때 두 가지 더 빠르고 효율적인 솔루션은 다음과 같습니다.

대체 솔루션 # 1 : 고아 지점

현재 브랜치의 끝 (예 : 가장 최근의 커밋)에서 새 고아 브랜치를 만들 수 있습니다. 이 고아 브랜치는 완전히 새로운 커밋 히스토리 트리의 초기 루트 커밋을 형성하는데, 이는 커밋을 모두 스쿼시하는 것과 실질적으로 같습니다.

git checkout --orphan new-master master
git commit -m "Enter commit message for your new initial commit"

# Overwrite the old master branch reference with the new one
git branch -M new-master master

선적 서류 비치:

대체 솔루션 # 2 : 소프트 리셋

또 다른 효율적인 솔루션은 단순히 루트 커밋에 혼합 또는 소프트 재설정을 사용하는 것입니다 <root>.

git branch beforeReset

git reset --soft <root>
git commit --amend

# Verify that the new amended root is no different
# from the previous branch state
git diff beforeReset

선적 서류 비치:


echo "message" | git commit-tree HEAD^{tree}

HEAD 트리를 사용하여 고아 커밋을 만들고 stdout에 이름 (SHA-1)을 출력합니다. 그런 다음 지점을 재설정하십시오.

git reset SHA-1

다른 사람을 위해 작동하는 경우를 대비하여 내가 이렇게 한 방법은 다음과 같습니다.

이와 같은 일을 할 때는 항상 위험이 있으며 시작하기 전에 저장 브랜치를 만드는 것은 결코 나쁜 생각이 아닙니다.

로깅으로 시작

git log --oneline

첫 번째 커밋으로 스크롤하고 SHA를 복사하십시오.

git reset --soft <#sha#>

<#sha#>로그에서 복사 한 SHA로 교체

git status

모든 것이 녹색인지 확인하고 그렇지 않으면 실행 git add -A

git commit --amend

모든 현재 변경 사항을 현재 첫 커밋으로 수정

이제이 분기를 강제로 밀면 거기에있는 내용을 덮어 씁니다.


가장 쉬운 방법은 'plumbing'명령 update-ref을 사용하여 현재 분기를 삭제하는 것입니다.

git branch -D현재 분기 삭제를 중지하는 안전 밸브가 있으므로 사용할 수 없습니다 .

그러면 새로운 초기 커밋으로 시작할 수있는 '초기 커밋'상태로 돌아갑니다.

git update-ref -d refs/heads/master
git commit -m "New initial commit"

이식편 사용에 대한 내용을 읽었지만 많이 조사하지는 않았습니다.

어쨌든, 마지막 2 개의 커밋을 수동으로 다음과 같이 스쿼시 할 수 있습니다.

git reset HEAD~1
git add -A
git commit --amend

먼저을 사용하여 모든 커밋을 단일 커밋으로 스쿼시하십시오 git rebase --interactive. 이제 스쿼시를위한 두 가지 커밋이 남았습니다. 그렇게하려면


한 줄에 6 단어

git checkout --orphan new_root_branch  &&  git commit

이식편을 사용하여 스쿼시하려면

파일을 추가하고 .git/info/grafts루트가되고 싶은 커밋 해시를 넣으십시오.

git log 이제 그 커밋에서 시작합니다

'실제'실행되도록 git filter-branch


백업을 만들

git branch backup

지정된 커밋으로 재설정

git reset --soft <#root>

그런 다음 모든 파일을 준비에 추가

git add .

메시지를 업데이트하지 않고 커밋

git commit --amend --no-edit

뭉친 커밋으로 새 지사를 밀다

git push -f

이 답변 작성 외에 하나 (노 부모가 더-역사), 커밋 없다고 가정, (그들을 투표하십시오) 위의 몇 향상 또한 그의 커밋 커밋 모든 데이터를 유지하려면 없습니다 :

  • 저자 (이름 및 이메일)
  • 작성일
  • 커미터 (이름과 이메일)
  • 확정 된 날짜
  • 커밋 로그 메시지

물론 새로운 / 단일 커밋의 commit-SHA는 새로운 (비) 역사를 나타내며 부모가없는 / 루트 커밋이되기 때문에 변경 될 것입니다.

git log대한 일부 변수를 읽고 설정하면 git commit-tree됩니다. 위의 commit-data를 유지하면서 master새 브랜치에서 단일 commit을 작성한다고 가정하십시오 one-commit.

git checkout -b one-commit master ## create new branch to reset
git reset --hard \
$(eval "$(git log master -n1 --format='\
COMMIT_MESSAGE="%B" \
GIT_AUTHOR_NAME="%an" \
GIT_AUTHOR_EMAIL="%ae" \
GIT_AUTHOR_DATE="%ad" \
GIT_COMMITTER_NAME="%cn" \
GIT_COMMITTER_EMAIL="%ce" \
GIT_COMMITTER_DATE="%cd"')" 'git commit-tree master^{tree} <<COMMITMESSAGE
$COMMIT_MESSAGE
COMMITMESSAGE
')

나는 보통 다음과 같이합니다 :

  • 모든 것이 커밋되었는지 확인하고 문제가 발생할 경우 최신 커밋 ID를 기록하거나 백업으로 별도의 분기를 만듭니다.

  • git reset --soft `git rev-list --max-parents=0 --abbrev-commit HEAD`머리를 첫 커밋으로 재설정하기 위해 실행 하지만 인덱스는 변경하지 마십시오. 첫 번째 커밋 이후의 모든 변경 사항은 커밋 준비가되었습니다.

  • 실행 git commit --amend -m "initial commit"하여 커밋을 수정하는 최초의 커밋과 메시지를 저지하거나 기존의 커밋 메시지를 유지하려는 경우, 당신은 실행할 수 변경git commit --amend --no-edit

  • git push -f변경 사항을 강제로 실행

참고 URL : https://stackoverflow.com/questions/1657017/how-to-squash-all-git-commits-into-one



반응형