2016-07-06 4 views
2

커밋이 많은 개발 지점이 있습니다. 이러한 커밋에는 "실제"변경 사항 (예 : 기능 추가)과 임시 변경 사항 (예 : 테스트 코드를 한 번에 추가 한 다음 나중에 커밋 할 때 제거)이 포함됩니다. 이 지점의 실제 변경 사항이 점차 마스터에 추가됩니다. 추가 할 때마다 새로운 마스터에 개발 된 브랜치를 리베이스합니다. 각주기마다 개발 분기와 마스터 간의 차이가 점점 작아지고 있습니다. 그러나 리베이스 된 개발 브랜치에는 원래의 모든 커밋이 포함됩니다. 이 커밋들 중 일부는 이제 제로 넷 효과를 갖습니다.자물쇠를 자동으로 제거하는 방법 Git에서 자신을 취소하는 방법

간단한 예 :이 시점에서

DEV_BRANCH 
    Commit ... 
    Commit D: Remove all test code from f.cpp 
    Commit ... 
    Commit C: Add new feature to f.cpp 
    Commit ... 
    Commit B: Add more test code to f.cpp 
    Commit A: Add some test code to f.cpp 
    Commit ... 
MASTER 
    Commit X: Add new feature to f.cpp 
    Commit ... 

, C 커밋에서 f.cpp로 변경은 마스터가 X를 저지 이미에서 하고, 결합 될 때 A + B + D을 범 변화가 없다 ~ f.cpp. 즉, 분기와 마스터 사이의 diff는 파일 f.cpp에 대해 아무것도 표시하지 않습니다.

(실제로, A는, B, C, D는뿐만 아니라 다른 파일에 대한 변경 사항을 포함 할 수있다 커밋합니다.)

는 자동적으로 하나 REBASE 동안 또는 다른 개발 브랜치에 커밋을 단순화 할 수있는 방법이 있나요 ? 상기 간단한 예에서

자동C 커밋 제거 (변화 이미 이제 "빈"따라서 마스터 병합) 또한, BD (결합 변화 없음) A 얻어 것이 가능 ?

더 복잡한 시나리오에서는 f.cpp가 다른 파일을 수정하는 경우에도 개발 분기의 커밋에서 파일 f.cpp에 대한 변경 사항을 자동으로 제거 할 수 있습니다 (단순화하기 위해). 그러나 커밋은 남겨 둡니다. 그것들이 다른 파일들에 대한 변경 사항들을 포함한다면 존재 하는가?

개발 분기의 모든 커밋에서 파일의 모든 변경 내용을 마스터의 파일과 동일하게 적용하면 개발 분기에서이 파일의 변경 내용을 제거 할 수 있습니까? (다른 효과가없는 파일에 대한 변경 사항을 다른 파일과 동기화해야 할 경우 부작용이 발생할 수 있음을 알고 있습니다. 그러나 체리를 사용하지 않아도 문제가되지는 않습니다. - 개발 지점의 중간 상태를 고르십시오.)

+0

@quetzalcoatl 네, 일반적으로이 어려운 문제가 있음을 깨닫는다. 그러나, 내 상황이 제한된 것, dev 분기 본질적으로 중간 상태가 필요하지 않습니다. 나는 마스터로부터 새로운 브랜치를 만들고 원래의 dev 브랜치에 있던 모든 변경된 파일을 복사하는 것으로 생각했다. 그러나, 이것은 하나 개의 새로운 덩어리가 커밋 만들고 that..after이-기능 위에 마스터를 저지하고-리베이스 (STABLE) - 온에 대한 –

+1

지금 생각 (나는 모든 실제적인 변경을 따기 일 오전까지 유용하도록) 모든 단위가 푼다 마스터 당신은 devel과 master 사이에'merge --squash --no-commit --no-ff'를 만들어서 devel에서 어떤 파일이 실제로 변경되었는지를 탐지 할 수 있습니다. 그러면 ** 변경 사항이 적용된 파일 목록이 제공됩니다. ** chg **라고 부르면 병합을 중단하고 HEAD downto master에서 devel history를'filter-branch' (removeemptycommits 포함)로 이동하고 각 커밋을 편집하고 파일을 제거합니다 ** ** chg **에 있지 않습니다. 그러면 변경 사항 만 올바르게 적용되고 오탐 (false positives)이 발생하게됩니다. 변경 사항과 변경 사항이 모두 되돌려 진 파일입니다. – quetzalcoatl

+0

그 부분은 낙관적 도움이 그래서 .. 약간의 청소를하지 쉽게 등 지수 복잡도/아니며, 대부분의 아마 bash는 스크립트로 구현 가능하다 ..하지만 가양를 해결하는 것은 원래의 문제로 단지 열심히 보인다 경우가 있지만, 일반적인 경우 – quetzalcoatl

답변

1

사람들은 의견에서 복잡성 문제를 해결했습니다.

문제가 너무 어렵 기 때문에 일반적으로 불가능합니다. 문제를 "비어 있음"(바로 앞에서 변경 한 내용이 없음)으로 정의하면 쉽습니다. 실제로 Git에 있습니다. rebase는 사용자가 --keep-empty을 요구하지 않는 한 이미이 작업을 수행합니다.

스테로이드와 같은 rebase와 비슷한 일종의 git filter-branch도 가능하지만 기본값은 반대입니다. --prune-empty을 지정하지 않으면 이러한 커밋을 유지합니다. 커밋 필터를 사용하는 경우 실제로 git commit-tree을 호출하기 전에 현재 트리를 이전 트리와 비교하는 git_commit_non_empty_tree을 사용하십시오.이 경우 git filter-branch은 아마도 원하는 것보다 무거울 것입니다.) 주석에서

, 당신이 쓴 :

나는 마스터에서 새로운 지점을 만들 이상 내 원래 dev에 지점에서 변경된 모든 파일을 복사하는 것으로 간주. 그러나, 이것은 하나 개의 새로운 덩어리가 커밋 생성하고 모든 단위 푼다

망할 놈이를 위해 설계되었습니다 (나는 모든 실제적인 변경을 따기 일 오전까지 유용있을 수 있습니다.) : 그냥 "분리"HEAD (git checkout --detach 또는 체크 아웃 원시 SHA-1 ID로) 원하는 임시 커밋을 만듭니다. 일단 명명 된 브랜치로 다시 전환하면, 임시 커밋은 HEAD reflog (도달 불가능한 커밋되지 않은 커밋의 경우 기본 30 일)로 보호되는 동안에 만 유지됩니다. (글쎄, 그들이 느슨한 물체라면, 그들은 14 일간의 유예 기간을 갖지만, 14는 30 이하가됩니다.)

당신은 커밋을하지 않아도됩니다. git diff (또는 git diff-tree) master의 끝에있는 트리와 dev_branch의 끝에있는 트리. 다른 말로하면, 완전한 소스 트리의 두 가지 형태는 이미 두 개의 개별 커밋 인 Git에 있습니다. 그들은 그들 사이에 (다른 커밋의) 내역이 있습니다. :

  o-------o <-- master 
     /
...--o--o 
     \ 
      o--o--o--o <-- dev_branch 

하지만 그로 인해 직접 비교할 수는 없습니다. 분리 된 HEAD 트릭이 일을하는 데 유용합니다 :

* 일부 다시 머리를 이동하는 git reset 또는 git checkout를 사용하여 그것을 좋아하지 않는 경우 다음 폐기 할 수있는, (실제로는 최선을 다하고 있습니다!) 커밋을 제안한다
  o-------o <-- master 
     /
...--o--o------*  <-- detached HEAD 
     \ 
      o--o--o--o <-- dev_branch 

다른 커밋 또는 분기 이름을 가리키는 것으로 되돌아갑니다.

실제로는 git rebase이 작동합니다. 즉, 새 분기가 커질 때 HEAD를 분리하고 새 분기가 완료 될 때까지 커밋을 추가 한 다음 분기 이름에서 화살표로 지우는 화살표를 지 웁니다. 원래 팁 - 가장 많이 커밋하고 화살표가 새로운 팁 - 대부분의 커밋을 가리키게합니다.)

+0

예, 정말로 비어있는 커밋은 (기본값으로) 리베이스하는 동안 보관되지 않았다고 생각합니다. 혹시 (http://stackoverflow.com/a/5324916/2325279에서 영감을 얻은 경우) 커밋 필터를 실행했습니다. 그것은 오랜 시간이 걸렸지 만 어떤 것도 단순화하지는 못했습니다. –

2

나는 속임수가 생성되는 방법을 고려하여 특정 사용 사례에 대해 상당히 간단한 해결책이 몇 개 있다고 생각합니다. 첫 번째 장소.

해결 방법 1 : 커밋의 소수에 대한 분기 나뭇 가지에

의 당신이 git rebase --interactive 모드로 표시 dev에서 커밋의 다음 세트를 가지고 있다고 가정 해 봅시다 : 이제

pick bf45b13 Add feature X 
pick b1f790f Cleanup feature X 
pick 40b299a Add feature Y 

당신이 벚꽃으로 결정 -master40b299a을 입력하십시오.

dev을 리베이스 할 때 새로운 커밋이 비어있는 것이 문제입니다. 향후 리베이스를 위해 git rebase -i master을 수행하는 것이 좋습니다. 체리에서 선택한 선을 삭제하고 원하는 커밋으로 만 남겨 둘 수 있습니다.

"자동으로"이 작업을 수행하려는 경우 자신의 git 스크립트를 사용하여 체리 선택 및 리베이스를 동시에 수행하여 dev에서 올바른 커밋을 제거하고 마스터에 추가 할 수 있습니다.당신이 git-transfer 같은 다음 스크립트 뭔가를 호출하고 어딘가 PATH에 추가하는 경우

, 당신은 git transfer dev master commit [...]로 호출 할 수 있습니다

#!/bin/bash 

usage() { 
    echo "Usage: git transfer from-branch to-branch commits [...]" 
    if [ -n "${1}" ] 
    then 
     echo 
     for line; do echo "${line}"; done 
    fi 
    exit 1 
} 

FROM="$(git rev-parse --abbrev-ref "${1}")" 
[ -z "${FROM}" ] && usage 'from-branch must be a valid branch name' || shift 
TO="$(git rev-parse --abbrev-ref "${1}")" 
[ -z "${TO}" ] && usage 'to-branch must be a valid branch name' || shift 

ORIGINAL="$(git rev-parse --abbrev-ref HEAD)" 

if [ "${ORIGINAL}" == "${TO}" ] 
then 
    echo "Already on branch ${TO}" 
else 
    echo "Switching from ${ORIGINAL} to ${TO}" 
    git checkout "${TO}" || exit 
fi 

while [ $# -gt 0 ] 
do 
    for COMMIT in "$(git rev-parse "${1}" | grep '^[^^]')" 
    do 
     echo "Moving ${COMMIT} to ${TO}" 
     git cherry-pick "${COMMIT}" 
     echo "Removing ${COMMIT} from ${FROM}" 
     EDITOR="sed -i '/^pick $(git rev-parse --short ${COMMIT})/ d'" git rebase -i "${TO}" "${FROM}" 
    done 
    shift 
done 

if [ "${ORIGINAL}" != "${TO}" ] 
then 
    echo "Switching back to ${ORIGINAL} from ${TO}" 
    git checkout "${ORIGINAL}" 
fi 

이 스크립트는 지점 "에서"입니다 그 이름을 받아 리베이스, 체리 따기로 될 것 "에서"지점의 이름 및 커밋의 목록, 그것은 (루프에 대한 또한이 answer)이 questionanswer에서 제안 된 아이디어에 크게 기반 등의 범위를 커밋 .

이 솔루션은 크게 갈라져있는 작은 커밋 번호 (대부분 한 번에 하나의)뿐만 아니라에 대한 지점에 적합합니다.

해결 방법 2 : 커밋의 큰 번호는 당신이 기술 사용의 경우 하나의 타임 라인

에, 당신은 정기적으로 너무 dev 효과적으로 앞서 마스터의 모든 시간, masterdev을 리베이스.

  1. 대화 형 REBASE를 시작
  2. 목록
  3. 전체 REBASE
  4. 이동 마스터의 시작 부분에 원하는 커밋 이동 : 대신 개인을 따기의 다음 번에 마스터에 커밋, 다음 할 마지막 커밋.

이 방법을 사용하면 중복되는 것을 방지 할 수 있으며 아마도 가장 간단한 방법입니다. dev은 지속적으로 리베이스되지만, master은이 접근 방식으로 만 빨리 감기합니다.

+0

커밋 순서를 바꾸는 것에 대한 생각이 마음에 든다. 불행히도, 내 지사에서 많은 혼합 된 커밋 때문에 이것은 나를 위해 작동하지 않습니다. –

+1

@ PetrVepřek. 왜 내가 이해하는지 모르겠다. 기본적으로 어쨌든 그 커밋 중 일부를 선택합니다. 선택의 일부로 rebase를하는 것이 더 중요합니까? –

+0

@ PetrVepřek :'내 지사에서 많은 혼합 된 커밋 때문에'- rebase 중에는 커밋을 재정렬하고 병합 (수정, 스쿼시 등) 할 수있을뿐만 아니라 편집 및 분할 할 수 있다는 것을 알고 있습니까? 분할 커밋은 하나의 파일 - 여기 - 하나의 파일 만 의미하는 것은 아니며 특정 청크/라인을 선택하거나 새로운 텍스트를 삽입하거나 중간에 커밋 할 수도 있습니다. 때로는 상당한 양의 (수동) 작업이지만, 종종 오래된 "uncareful"커밋을 정리 및/또는 재정렬하는 데 도움이됩니다. – quetzalcoatl