git에서 처음 두 커밋을 스쿼시? [복제하다
-
11-09-2019 - |
문제
이 질문은 이미 여기에 답이 있습니다.
와 함께 git rebase --interactive <commit>
커밋을 하나의 커밋으로 스쿼시 할 수 있습니다.
초기 커밋에 스쿼시를하고 싶지 않다면 그것은 모두 훌륭합니다. 그것은 불가능한 것 같습니다.
그것을 달성 할 방법이 있습니까?
적당히 관련 :
관련 질문에서, 나는 첫 번째 커밋에 대해 스쿼시의 필요성, 즉 두 번째 커밋으로 만들기 위해 다른 접근 방식을 생각해 냈습니다.
해결책
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
이후의 커밋은 초기 커밋에 문제가 필요했습니다.)
우리가 초기 커밋 (Detach Head)을 형성하고자한다는 마지막 커밋으로 돌아갑니다.
git checkout <sha1_for_B>
분기 포인터를 초기 커밋으로 재설정하지만 색인과 작업 트리를 그대로 두십시오.
git reset --soft <sha1_for_A>
'b'에서 나무를 사용하여 초기 트리를 수정하십시오.
git commit --amend
이 새로운 초기 커밋을 일시적으로 태그하십시오 (또는 새로운 Commit SHA1을 수동으로 기억할 수 있음) :
git tag tmp
원래 브랜치로 돌아갑니다 (이 예제의 마스터를 가정) :
git checkout master
B 이후의 모든 커밋을 새로운 초기 커밋으로 재생합니다.
git rebase --onto tmp <sha1_for_B>
임시 태그 제거 :
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