비대화 형으로 많은 커밋을 스쿼시하는 방법이 있습니까?


답변:


146

작업 트리가 깨끗한 지 확인한 다음

git reset --soft HEAD~3
git commit -m 'new commit message'

@wilhelmtell : 좋아요! 이제 "mysquash 3 'some message'"와 같은 git 별칭을 구성하여 한 줄로 줄일 수 있습니까?
Phillip

5
라인 수만 있다면 :git reset --soft HEAD~3 && git commit -m "my message"
KingCrunch 2011 년

7
@Phillip : git 별칭에 쉘 함수를 포함 할 수 있습니다. git config alias.mysquash '!f(){ git reset --soft HEAD~$1 && git commit ${2:+-m "$2"}; };f'. git mysquash 3 'some message'작동하지만, 나는 또한 그것을 조정 git musquash 3하여 -m 플래그를 완전히 생략 하여이 git commit경우 대화 형 UI를 얻을 수 있습니다.
Lily Ballard 2011 년

3
분명히 말하면 스쿼시와는 다릅니다. 스쿼시는 커밋 메시지도 병합합니다. 소프트 재설정을 수행하면 커밋의 모든 메시지가 손실됩니다. 당신은 스쿼시 시도를하려는 경우 stackoverflow.com/a/27697274/974186
르네 링크

1
@sebnukem-우리가 브랜치를 푸시하려고 할 때 원격이 강제 푸시를 거부하도록 구성되었습니다.
avmohan

30

개인적으로 Wilhelmtell의 솔루션을 좋아 합니다.

git reset --soft HEAD~3
git commit -m 'new commit message'

그러나 몇 가지 오류 검사로 별칭을 만들었습니다.

git squash 3 'my commit message'

(a) 스크립트를 코딩하고 (b) 오류 검사로 더 복잡한 작업을 수행하기 쉽도록 실제로 스크립트를 실행하는 별칭을 설정하는 것이 좋습니다. 아래는 스쿼시 작업을 수행하는 스크립트이고 그 아래는 git 별칭을 설정하는 스크립트입니다.

스쿼 싱용 스크립트 (squash.sh)

#!/bin/bash
#

#get number of commits to squash
squashCount=$1

#get the commit message
shift
commitMsg=$@

#regular expression to verify that squash number is an integer
regex='^[0-9]+$'

echo "---------------------------------"
echo "Will squash $squashCount commits"
echo "Commit message will be '$commitMsg'"

echo "...validating input"
if ! [[ $squashCount =~ $regex ]]
then
    echo "Squash count must be an integer."
elif [ -z "$commitMsg" ]
then
    echo "Invalid commit message.  Make sure string is not empty"
else
    echo "...input looks good"
    echo "...proceeding to squash"
    git reset --soft HEAD~$squashCount
    git commit -m "$commitMsg"
    echo "...done"
fi

echo
exit 0

그런 다음 squash.sh 스크립트를 git 별칭 에 연결하려면 다음 과 같이 git 별칭을 설정하는 다른 스크립트를 만듭니다 ( create_aliases.command 또는 create_aliases.sh ) :

#!/bin/sh
echo '-----------------------'
echo 'adding git aliases....'
echo '-----------------------'
echo
git config --global alias.squash "!bash -c 'bash <path to scripts directory>/squash.sh \$1 \$2' -"
#add your other git aliases setup here
#and here
#etc.
echo '------------------------------------'
echo 'here is your global gitconfig file:'
echo '------------------------------------'
more ~/.gitconfig
echo 
echo
echo '----------------'
echo 'end of script...'
echo '----------------'

4
또한 $PATHnamed에 넣을 수 git-squash.sh있으며 자동으로 별칭이 지정됩니다 git squash. 내가 알지 못하는 create-aiases.sh스크립트 를 사용할 이유가있는 경우를 대비하여 답변을 변경하지 않았습니다 .

저는 기본적으로 create_aliases.command 스크립트를 사용하므로 PM과 디자이너도 쉽게 설정할 수 있습니다. 스크립트를 두 번 클릭하면 모두 설정됩니다 (특히 저장소에 설정 스크립트가 있고 상대 경로가 알려져 있기 때문에). 그러면 터미널을 다시 시작할 필요도 없습니다.
n8tr 2014-06-12

1
나는 이것을 시도했고 그것은 내 커밋 메시지를 스쿼시 카운트로 읽고 정수가 아니기 때문에 실패합니다.
Minthos

1
해결책은 추가하는 것이 었습니다-/squash.sh \ $ 1 \ $ 2 '이후
Minthos

1
솔루션 아이디어가 마음에 들지만 위의 설명은 아직 솔루션에서 고려되지 않았습니다. 작은 따옴표와 큰 따옴표 사이에 마이너스 기호가 있어야합니다.
physicalattraction

10

wilhelmtell 의 답변에 추가하려면 소프트 재설정 HEAD~2한 다음 커밋을 수정하는 것이 편리합니다 HEAD~3.

git reset --soft HEAD~2
git commit --all --amend --no-edit    

이것은 모든 커밋을 커밋에 병합 HEAD~3하고 커밋 메시지를 사용합니다. 깨끗한 작업 트리에서 시작하십시오.


2
이것은 헤드로 이어지는 일련의 커밋을 스쿼시하고 첫 번째 커밋의 메시지를 사용하기 때문에 정답입니다. 비대화 형입니다.
Landon Kuhn

9

나는 다음을 사용했다 :

EDITOR="sed -i '2,/^$/s/^pick\b/s/'" git rebase -i <ref>

아주 잘 작동했습니다. "pick"으로 시작하는 줄이있는 커밋 로그를 만들려고하지 마십시오. :)


슬프게도 이것은 Windows에서 작동하지 않습니다. 여전히 대화 형 편집기를 사용하십시오.
abergmeier 2014

3

다음 명령을 사용하여 마지막 커밋 내에서 마지막 4 개 커밋을 스쿼시합니다.

git squash 4

별칭 사용 :

squash = !"f() { NL=$1; GIT_EDITOR=\"sed -i '2,$NL s/pick/squash/;/# This is the 2nd commit message:/,$ {d}'\"; git rebase -i HEAD~$NL; }; f"
sq = !git squash $1
sqpsf = !git squash $1 && git psf 

에서 https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig


여기서 사용되는 OS / 셸을 지정하지 않았습니다. 이 솔루션은 사람들이 사용하는 다른 모든 데스크톱에서 작동하지 않을 수 있습니다.
Rick-777

이를 위해 zsh을 | 네, 당신은 리눅스 / bash는 사용해야합니다
brauliobo

2

다음은 마지막 2 개의 커밋을 스쿼시하는 1 개의 라이너입니다. 이 예에서는 두 번째 마지막 커밋의 메시지가 유지됩니다. 원하는대로 메시지를 변경할 수 있습니다.

git commit -am "$(git log -1 --skip=1 --pretty=%B | xargs && git reset --soft HEAD~2)"

이 명령은이 명령에 대한 별칭을 만들고 대신 별칭을 사용하는 경우 매우 유용합니다.


1

브랜치가 마스터에서 분기 된 이후 모든 것을 스쿼시하려면 :

git reset --soft $(git merge-base --fork-point master) \
  && git commit --verbose --reedit-message=HEAD --reset-author

--reedit-message=HEAD쿼싱의 일부가 아닌 마지막 커밋 의 메시지를 사용합니다 . 이것은 당신이 원하는 것이 아닐 것입니다. 오히려의 메시지를 얻으려면 먼저 포함되어야 할 것을 약속 하거나, (1) 대체 HEAD당신은의 메시지, 또는 원하는 커밋의 해시 (2) (가) 먼저 포함되어야 커밋에 점프를 git commit --amend --reedit-message=HEAD. 이것이 조화로운 대답이하는 일입니다.
Maëlan

-1

당신은 꽤 가까워 질 수 있습니다

git rebase --onto HEAD ~ 4 HEAD ~ master

이것은 당신이 선형 역사를 가진 마스터라고 가정합니다. 중간 커밋을 버리기 때문에 스쿼시가 아닙니다. 커밋 메시지를 수정하려면 새 HEAD를 수정해야합니다.


감사합니다 Greg; 'discards'는 중간 커밋이 git gc에 의해 정리된다는 것을 의미합니까?
Phillip

@Phillip 예, 중간 커밋 HEAD~4은 상위 HEAD로 다시 작성되기 때문에 이전 HEAD와 마찬가지로 가비지가 됩니다.
Greg Bacon
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.