source

어떻게 모든 깃 커밋을 하나로 뭉치나요?

nicesource 2023. 6. 18. 16:06
반응형

어떻게 모든 깃 커밋을 하나로 뭉치나요?

전체 리포지토리를 첫 번째 커밋으로 압축하려면 어떻게 해야 합니까?

첫 번째 커밋을 기준으로 다시 설정할 수 있지만, 그러면 커밋이 2개 남습니다.첫 번째 커밋 전에 커밋을 참조할 수 있는 방법이 있습니까?

git 1.6.2 기준으로 다음을 사용할 수 있습니다.git rebase --root -i

커밋을 각합니다.picksquash.

라이너 하나(Bash/Zsh용)

스쿼시-모두 커밋 권한을 만들 수 있습니다.HEAD기본 재배치 없이 그냥 실행:

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

참고: 이를 위해서는 Windows의 bash/zsh 또는 Git Bash와 같은 POSIX 호환 셸이 필요합니다.

에서 별칭 ~/.gitconfig

[alias]
  squash-all = "!f(){ git reset $(git commit-tree HEAD^{tree} \"$@\");};f"

그러면 그냥 실행:

참고: git commit 명령처럼 표준 입력에서 커밋 메시지를 제공하거나 -F/ 옵션을 통해 제공합니다.git-commit-tree 설명서를 참조하십시오.

또는 다음 명령을 사용하여 별칭을 생성할 수 있습니다.

git config --global alias.squash-all '!f(){ git reset $(git commit-tree HEAD^{tree} "$@");};f'

설명하라.

  1. 단일커생을 통해 git commit-tree

    무엇을git commit-tree HEAD^{tree} -m "A new start"다음을 수행합니다.

    제공된 트리 개체를 기반으로 새 커밋 개체를 만들고 stdout에서 새 커밋 개체 ID를 내보냅니다.-m 또는 -F 옵션이 제공되지 않는 한 로그 메시지는 표준 입력에서 읽힙니다.

    그표은라는 HEAD^{tree}에해 트는개나타다니냅에 해당하는 .HEAD즉, 트리-개체 및 커밋-개체참조하십시오.

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

    그리고나서git reset현재 분기를 새로 만든 커밋 개체로 재설정하기만 하면 됩니다.

    이렇게 하면 작업 공간에 아무것도 닿지 않으며, 기본 재배치/파쇄가 필요하지 않으므로 작업 속도가 매우 빠릅니다.그리고 필요한 시간은 저장소 크기나 기록 깊이와 무관합니다.


변동:프로젝트 템플릿에서 새 레포

이것은 템플릿/archtype/seed/skeleton으로 다른 리포지토리를 사용하여 새 프로젝트에서 "초기 커밋"을 만드는 데 유용합니다.예:

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템플릿 repo의 기록을 초기 커밋으로 축소합니다.

모든 커밋을 루트 커밋으로 압축하는 것을 원하는 경우,

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: 소프트 리셋

커밋 또 다 효 율 적 션 은 또 혼 소 는 프 재 정 설 을 사 하 는 니 입 것 다 용 트 른 합 해 에 밋 대 커 인 루 솔 트 루 ▁reset ▁to ▁commit ▁or ▁the ▁root ▁mixed ▁soft ▁a ▁another ▁use ▁is 또 ▁solution ▁efficient ▁to ▁simply 다 니 른 것<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

설명서:

가장 쉬운 방법은 현재 작업 복사본의 상태로 새 리포지토리를 만드는 것입니다.이 모든 커밋 , 모든밋커메유면먼다있수니습수행할저려지하를 할 수 .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
echo "message" | git commit-tree HEAD^{tree}

이렇게 하면 HEAD 트리와 분리된 커밋이 생성되고 stdout에 이름(SHA-1)이 출력됩니다.그럼 거기서 지점을 재설정하면 됩니다.

git reset SHA-1

단일 단계에서 위의 작업을 수행하려면:

git reset $(git commit-tree HEAD^{tree} -m "Initial commit.")

다른 사람에게 도움이 될 경우를 대비해 이렇게 하게 되었습니다.

이러한 작업에는 항상 위험이 따르며 시작하기 전에 저장 분기를 만드는 것도 나쁘지 않습니다.

로깅으로 시작

git log --oneline

첫 번째 커밋, SHA 복사로 스크롤

git reset --soft <#sha#>

를 바꿉니다.<#sha#>와 함께 SHA를 합니다.

git status

것이하고, 실행하십시오.git add -A

git commit --amend

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

이제 이 분기를 강제로 누르면 해당 분기가 덮어쓰게 됩니다.

이식편을 사용하는 것에 대해 읽은 적은 있지만 별로 조사하지 않았습니다.

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

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

입니다.update-ref현재 분기를 삭제합니다.

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

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

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

6개 단어의 한 줄로:

git checkout --orphan new_root_branch  &&  git commit

백업 생성

git branch backup

지정된 커밋으로 재설정

git reset --soft <#root>

그런 다음 모든 파일을 스테이징에 추가합니다.

git add .

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

git commit --amend --no-edit

재포오할 커밋이 지워진 새 분기 푸시

git push -f

커밋을 .git rebase --interactive이제 당신은 두 번의 약속을 남겼습니다.다음 중 하나를 읽으십시오.

이를 위해 로컬 git 저장소를 첫 번째 커밋 해시태그로 재설정하여 커밋 이후의 모든 변경 사항이 스테이징되지 않도록 한 다음 --amend 옵션을 사용하여 커밋할 수 있습니다.

git reset your-first-commit-hashtag
git add .
git commit --amend

그런 다음 필요한 경우 첫 번째 커밋 이름을 편집하고 파일을 저장합니다.

분기에 3개의 커밋이 있으며 이미 원격 분기로 푸시되었다고 가정합니다.

예:

git log -4

다음과 같은 결과를 표시합니다.

<your_third_commit_sha>
<your_second_commit_sha>
<your_first_commit_sha>
<master_branch_commit_sha - your branch created from master>

마지막 세 번의 커밋을 한 번의 커밋으로 밀어넣고 원격 분기로 밀어넣으려고 합니다.단계는 다음과 같습니다.

git reset --soft <master_branch_commit_sha>

이제 모든 커밋 변경 사항이 통합되었지만 커밋되지 않았습니다.확인 방법:

git status

다음 메시지를 사용하여 모든 변경 사항 커밋:

git commit -m 'specify details'

원격 분기에 단일 커밋 강제 푸시:

git push -f

그라프트를 사용하여 스쿼시하기

.git/info/grafts 커밋 .

git log 그 하겠습니다.

''로 합니다.git filter-branch

저는 보통 다음과 같이 합니다.

  • 모든 것이 커밋되었는지 확인하고, 문제가 발생할 경우 최신 커밋 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

제게는 다음과 같이 작동했습니다.총 4개의 커밋이 있었고 대화형 리베이스를 사용했습니다.

git rebase -i HEAD~3

첫 번째 커밋이 남아 있고 최근 커밋을 3개 가져갔습니다.

다음에 나타나는 편집기에 고정되어 있는 경우 다음과 같이 표시됩니다.

pick fda59df commit 1
pick x536897 commit 2
pick c01a668 commit 3

당신은 먼저 약속을 하고 다른 사람들을 그 위에 뭉개야 합니다.당신이 가져야 할 것은:

pick fda59df commit 1
squash x536897 commit 2
squash c01a668 commit 3

이 경우 INSERT 키를 사용하여 '삽입' 및 '편집' 모드를 변경합니다.

하려면 편기를종면사용려료를 합니다.:wq커서가 이러한 커밋 라인 사이에 있거나 다른 곳에 있으면 ESC를 누르고 다시 시도하십시오.

결과적으로 저는 두 가지 커밋을 가졌습니다. 첫 번째 커밋은 남아 있었고 두 번째 커밋은 "이것은 세 가지 커밋의 조합입니다."라는 메시지가 있는 커밋이었습니다.

자세한 내용은 여기에서 확인하십시오. https://makandracards.com/makandra/527-squash-several-git-commits-into-a-single-commit

예를 들어 06부터 10까지 이러한 커밋이 있다고 가정합니다.

06번 커밋 게시물을 단일 커밋 ID에 결합하려고 합니다.

commit 10
commit 09  
commit 08  
commit 07  
commit 06

Git Reset 소프트를 실행할 수 있습니다.

git reset --soft "06"

그런 다음 다음 다음 명령을 실행하여 변경 내용을 원격 분기에 푸시합니다.

git push origin HEAD --force

이제 이전에 수행한 모든 커밋을 로컬 변경사항으로 사용할 수 있어야 하며 이러한 커밋을 하나의 커밋으로 결합할 수 있습니다.

이제 새로운 커밋 구조는 다음과 같습니다.

commit <new_commit_containing_all_7_8_9_10>
commit 06

HEAD^{tree}에서 다른 명령을 시도했지만 zsh에서 다음 오류가 발생했습니다.

zsh: no matches found: HEAD^{tree}

ohmyzsh가 확장을 처리하는 방법이었습니다. 자세한 내용은 이 문제를 참조하십시오. https://github.com/ohmyzsh/ohmyzsh/issues/449

가장 쉬운 해결 방법은 다음 명령을 실행하는 것입니다.

unsetopt nomatch

이 답변은 위의 두 가지 경우(투표를 통해 투표해 주십시오) 하나의 커밋(부모 없음 기록)을 만드는 것 외에도 해당 커밋의 모든 커밋 데이터를 유지하고 싶다고 가정할 때 개선됩니다.

  • 작성자(이름 및 이메일)
  • 작성일자
  • 커미셔너(이름 및 이메일)
  • 약정일자
  • 커밋 로그 메시지

물론 신규/단일 커밋의 커밋-SHA는 변경될 것입니다. 새로운 (비) 기록을 나타내므로 부모 없는/루트 커밋이 되기 때문입니다.

은 이은읽로할수있다니습기것다▁reading니있습▁this수▁be▁by▁done▁can할이를 읽음으로써 할 수 있습니다.git log하는 것도 하고요.git commit-tree다음에서 단일 커밋을 생성한다고 가정합니다.master 지점에서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
')

이것이 저에게 가장 효과적이었습니다.

git rebase -X ours -i master

이렇게 하면 피쳐 분기가 마스터보다 선호되므로 어려운 병합 편집을 피할 수 있습니다.분기가 마스터와 최신 상태여야 합니다.

ours
           This resolves any number of heads, but the resulting tree of the merge is always that of the current
           branch head, effectively ignoring all changes from all other branches. It is meant to be used to
           supersede old development history of side branches. Note that this is different from the -Xours
           option to the recursive merge strategy.

일반적으로 Git 저장소에서 템플릿을 복원할 때 트리 전체를 스퀴즈하여 기록을 더 깨끗하게 하고 법적 준수를 보장합니다.내 워크플로우는 다음과 같습니다.

git clone https://git.invalid/my-awesome-template.git my-awesome-foo
cd !$
git branch -M master my-awesome-template/master
git checkout --orphan master
git rm -rf /
git commit --allow-empty --allow-empty-message -m 'Initial commit'
git merge --squash --allow-unrelated-histories my-awesome-template/master
git commit
git branch -D my-awesome-template/master
# you can now `drop' that "Initial commit":
git rebase -i --root

이렇게 하면 전체 기록이 하나의 큰 커밋 메시지로 압축됩니다.

이 특정 예에서는 다음을 수행합니다.

  • master인 지점입니다.
  • my-awesome-template/master입니다.

여기에 제안된 솔루션에 문제가 있었기 때문에, 기능 분기의 모든 커밋을 하나로 압축하는 매우 간단한 솔루션을 공유하고자 합니다.

git merge origin/master && git reset --soft origin/master

앞의 merge cmd는 커밋할 때 마스터의 최근 변경 사항이 머리에 남지 않도록 보장합니다.그런 다음 변경 사항을 커밋하고 수행합니다.git push -f

다음 명령을 수행하여 모든 커밋을 하나로 압축합니다.

모든 답변이 훌륭하지만 간단한 명령으로 다른 접근 방식을 적용하고 싶습니다.

git clone --depth 1 <remote-url> .
git commit --amend -m <commit message you want>
git push --force

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

반응형