문제

이 질문은 이미 여기에 답이 있습니다.

와 함께 git rebase --interactive <commit> 커밋을 하나의 커밋으로 스쿼시 할 수 있습니다.

초기 커밋에 스쿼시를하고 싶지 않다면 그것은 모두 훌륭합니다. 그것은 불가능한 것 같습니다.

그것을 달성 할 방법이 있습니까?


적당히 관련 :

관련 질문에서, 나는 첫 번째 커밋에 대해 스쿼시의 필요성, 즉 두 번째 커밋으로 만들기 위해 다른 접근 방식을 생각해 냈습니다.

관심이 있다면 : GIT : 커밋을 첫 번째로 삽입하여 다른 모든 것을 바꾸는 방법은 무엇입니까?

도움이 되었습니까?

해결책

2012 년 7 월 업데이트 (GIT 1.7.12+)

이제 모든 커밋을 루트까지 리베이스하고 두 번째 커밋을 선택할 수 있습니다. Y 첫 번째로 찌그러 뜨립니다 X.

git rebase -i --root master

pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip

이 명령은 이제 "이끄는 모든 역사를 다시 작성하는 데 사용될 수 있습니다."$tip"루트 커밋으로 내려갑니다.

보다 GitHub에서 DF5DF20C1308F936EA542C86DF1E9C6974168472를 커밋하십시오 ~에서 Chris Webb (arachsys).


원래 답변 (2009 년 2 월)

나는 당신이 SO 질문에서 다른 레시피를 찾을 것이라고 믿습니다. "Git 저장소의 처음 두 커밋을 어떻게 결합합니까?"

찰스 베일리 거기에서 가장 많이 제공됩니다 자세한 답변, 커밋은 전체 트리임을 상기시켜줍니다 (이전 상태와는 다릅니다).
그리고 여기서 오래된 커밋 ( "초기 커밋")과 새로운 커밋 (스쿼시 결과)은 공통 조상이 없습니다.
그것은 당신이 할 수 없다는 것을 의미합니다 "commit --amend"새로운 최초의 커밋에 대한 커밋은 새로운 이니셜에 대한 Rebase에 대해 이전의 초기 커밋의 역사를 커밋합니다 (많은 충돌).

(마지막 문장은 더 이상 사실이 아닙니다 git rebase -i --root <aBranch>)

오히려 (와 함께 A 원래 "초기 커밋"및 B 이후의 커밋은 초기 커밋에 문제가 필요했습니다.)

  1. 우리가 초기 커밋 (Detach Head)을 형성하고자한다는 마지막 커밋으로 돌아갑니다.

    git checkout <sha1_for_B>
    
  2. 분기 포인터를 초기 커밋으로 재설정하지만 색인과 작업 트리를 그대로 두십시오.

    git reset --soft <sha1_for_A>
    
  3. 'b'에서 나무를 사용하여 초기 트리를 수정하십시오.

    git commit --amend
    
  4. 이 새로운 초기 커밋을 일시적으로 태그하십시오 (또는 새로운 Commit SHA1을 수동으로 기억할 수 있음) :

    git tag tmp
    
  5. 원래 브랜치로 돌아갑니다 (이 예제의 마스터를 가정) :

    git checkout master
    
  6. B 이후의 모든 커밋을 새로운 초기 커밋으로 재생합니다.

    git rebase --onto tmp <sha1_for_B>
    
  7. 임시 태그 제거 :

    git tag -d tmp
    

그렇게하면 "rebase --onto"병합 역사이기 때문에 합병 중에 갈등을 도입하지 않습니다. 이후에 마지막 커밋 (B) 초기에 스쿼시 될 것입니다 ( A) 에게 tmp (스쿼시 된 새로운 초기 커밋을 나타냅니다) : 사소한 빠른 포워드 합병.

그것은 "A-B", 그러나 또한"A-...-...-...-B"(수많은 커밋이 이런 식으로 초기에 스쿼시 될 수 있습니다)

다른 팁

나는 Vonc의 스크립트를 재 작업하여 모든 것을 자동으로 수행하고 아무것도 요구하지 않습니다. 당신은 그것을 두 개의 커밋 sha1을 주면 "스쿼시 히스토리 (squashed history)"라는 커밋으로 그들 사이의 모든 것을 스쿼시 할 것입니다.

#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2

# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1

# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"

# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`

# go back to the original branch (assume master for this example)
git checkout master

# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2

그 가치가있는 것에 대해, 나는 항상 "No-OP"첫 커밋을 만들어이 문제를 피합니다. 저장소의 유일한 것은 빈 .gitignore입니다.

https://github.com/darwinawardwinner/git-custom-commands/blob/master/bin/git-myinit

그렇게하면 첫 번째 커밋을 엉망으로 만드는 이유는 없습니다.

단순히 모든 커밋을 단일의 초기 커밋으로 스쿼시하려면 저장소를 재설정하고 첫 번째 커밋을 수정하십시오.

git reset hash-of-first-commit
git add -A
git commit --amend

Git Reset은 작업 트리를 그대로 유지하므로 모든 것이 여전히 존재합니다. 따라서 git add 명령을 사용하여 파일을 추가하고 이러한 변경 사항에 대한 첫 번째 커밋을 수정하십시오. Rebase와 비교할 때 -i는 git 주석을 병합 할 수있는 능력을 잃을 것입니다.

이것은 두 번째로 첫 번째로 커밋 될 것입니다.

A-B-C-... -> AB-C-...

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = <sha1ofA> ];
    then
        skip_commit "$@";
    else
        git commit-tree "$@";
    fi
' HEAD

AB에 대한 커밋 메시지는 B에서 가져옵니다 (A에서 선호하지만).

Uwe Kleine-König의 답변과 같은 영향을 미치지 만 비 초기 A에서도 효과가 있습니다.

첫 번째와 두 번째 커밋을 쪼개면 첫 번째 커밋이 다시 작성됩니다. 첫 번째 커밋을 기반으로 한 지점이 둘 이상인 경우 해당 지점을 차단합니다.

다음 예를 고려하십시오.

a---b---HEAD
 \
  \
   '---d

A와 B를 새로운 커밋 "AB"에 스쿼시하면 대부분의 경우에는 두 개의 별개의 나무가 발생하여 대부분의 경우에는 바람직하지 않습니다. git-merge 그리고 git-rebase 두 가지에서 더 이상 작동하지 않습니다.

ab---HEAD

a---d

당신이 정말로 이것을 원한다면, 그것은 할 수 있습니다. 살펴보십시오 git-filter-branch 역사 재 작성을위한 강력한 (그리고 위험한) 도구.

이를 위해 git 필터 브랜치를 사용할 수 있습니다. 예를 들어

git filter-branch --parent-filter \
'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'

이로 인해 AB-C는 A의 커밋 로그를 버립니다.

Rebase Interactive를 사용하여 원격으로 밀기 전에 마지막 두 커밋을 수정할 수 있습니다.

git rebase HEAD^^ -i

더 쉬운 방법이 있습니다. 당신이 있다고 가정 해 봅시다 master 나뭇가지

모든 커밋 이력을 제거 할 새로운 고아 지점을 만듭니다.

$ git checkout --orphan new_branch

초기 커밋 메시지 추가 :

$ git commit -a

오래된 무너진 마스터 브랜치를 제거하십시오.

$ git branch -D master

현재 지점의 이름을 바꿉니다 new_branch 에게 master:

$ git branch -m master
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top