Git의 다른 지점에서 선택적으로 병합하거나 변경 사항을 선택하는 방법은 무엇입니까? 현재 실험적인 개발 분기가있는

두 개의 병렬이지만 현재 실험적인 개발 분기가있는 새 프로젝트에서 git을 사용하고 있습니다.

  • master: 기존 코드베이스 및 일반적으로 확신하는 몇 가지 모드 가져 오기
  • exp1: 실험 지점 # 1
  • exp2: 실험 지점 # 2

exp1그리고 exp2두 개의 매우 다른 건축 방법을 나타냅니다. 더 나아갈 때까지 어느 쪽이 작동하는지 알 방법이 없습니다. 한 브랜치에서 진행하면서 다른 브랜치에 유용한 편집 내용이 있고 그 지점 만 병합하려고합니다.

다른 모든 것을 남겨두고 한 개발 지점에서 다른 개발 지점으로 선택적 변경 사항을 병합하는 가장 좋은 방법은 무엇입니까?

내가 고려한 접근법 :

  1. git merge --no-commit 브랜치 사이에서 공통적으로 만들고 싶지 않은 많은 편집 내용을 수동으로 언 스테이징했습니다.

  2. 공통 파일을 임시 디렉토리로 git checkout수동 복사 한 후 다른 분기로 이동 한 다음 임시 디렉토리에서 작업 트리로 수동 복사를 더 수동으로 복사합니다.

  3. 위의 변형. exp지금 지점을 포기하고 실험을 위해 두 개의 추가 로컬 저장소를 사용하십시오. 이렇게하면 파일을 수동으로 훨씬 간단하게 복사 할 수 있습니다.

이 세 가지 방법 모두 지루하고 오류가 발생하기 쉬운 것 같습니다. 더 나은 접근 방식이 있기를 바랍니다. git-merge더 선택적인 필터 경로 매개 변수와 유사한 것 입니다.



답변

cherry-pick 명령을 사용하여 한 분기에서 개별 커밋을 가져옵니다.

원하는 변경 사항이 개별 커밋에없는 경우 여기에 표시된 방법을 사용 하여 커밋을 개별 커밋으로 분할하십시오 . 대략적으로 말하면 git rebase -i원래 커밋을 편집하고 git reset HEAD^변경 사항을 선택적으로 되 돌린 다음 git commit해당 비트를 기록에서 새 커밋으로 커밋하는 데 사용됩니다.

Red Hat Magazine 에는 또 다른 멋진 방법이 있습니다. 여기서는 다른 변경 사항을 개별 파일로 분할하려는 경우 (이 페이지에서 “분할”검색) 덩어리의 일부만 추가 git add --patch하거나 git add --interactive추가 할 수 있습니다.

변경 사항을 나누면 원하는 항목 만 체리 픽 선택할 수 있습니다.


답변

위에서 언급 한 것과 똑같은 문제가있었습니다. 그러나 나는 대답을 설명하는 것이 더 명확 하다는 것을 알았습니다 .

요약:

  • 병합하려는 지점에서 경로를 확인하십시오.

    $ git checkout source_branch -- <paths>...
    

    힌트 : --링크 된 게시물에서 볼 수있는 것처럼 작동하지 않습니다 .

  • 또는 덩어리를 선택적으로 병합

    $ git checkout -p source_branch -- <paths>...
    

    또는 reset을 사용하고 옵션을 추가하십시오 -p.

    $ git reset <paths>...
    $ git add -p <paths>...
    
  • 마지막으로 커밋

    $ git commit -m "'Merge' these changes"
    

답변

한 지점에서 다른 지점으로 파일을 선택적으로 병합하려면 다음을 실행하십시오.

git merge --no-ff --no-commit branchX

branchX현재 브랜치로 병합하려는 브랜치가 어디에 있습니까 ?

--no-commit옵션은 실제로 커밋하지 않고 Git에 의해 병합 된 파일을 준비합니다. 이렇게하면 병합 된 파일을 수정할 수 있지만 원하는대로 커밋 할 수 있습니다.

파일 병합 방법에 따라 다음과 같은 네 가지 경우가 있습니다.

1) 당신은 진정한 합병을 원합니다.

이 경우 Git이 자동으로 병합 한 방식으로 병합 된 파일을 수락 한 다음 커밋합니다.

2) 병합하고 싶지 않은 파일이 있습니다.

예를 들어, 현재 분기에 버전을 유지하고 병합하려는 분기의 버전을 무시하려고합니다.

현재 분기에서 버전을 선택하려면 다음을 실행하십시오.

git checkout HEAD file1

이것은 file1현재 브랜치에서 버전을 검색하고 file1Git에 의해 자동 병합 된 것을 덮어 씁니다 .

3) branchX의 버전을 원할 경우 (진정한 병합이 아님).

운영:

git checkout branchX file1

이것은 Git에 의해 자동 병합 된 file1in branchX및 덮어 쓰기 버전을 검색합니다 file1.

4) 마지막 경우는에서 특정 병합 만 선택하려는 경우입니다 file1.

이 경우 수정 된 내용을 file1직접 편집 하고 원하는 버전으로 업데이트 file1한 다음 커밋 할 수 있습니다.

Git이 파일을 자동으로 병합 할 수 없으면 파일을 ” 병합되지 않은 ” 것으로보고 하고 충돌을 수동으로 해결해야하는 사본을 생성합니다.


예제를 통해 더 자세히 설명하기 위해 branchX현재 브랜치 로 병합하고 싶다고 가정 해 봅시다 .

git merge --no-ff --no-commit branchX

그런 다음 git status명령을 실행하여 수정 된 파일의 상태를보십시오.

예를 들면 다음과 같습니다.

git status

# On branch master
# Changes to be committed:
#
#       modified:   file1
#       modified:   file2
#       modified:   file3
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      file4
#

어디에서 file1, file2그리고 file3성공적으로 자동 합병이 자식 파일입니다.

이것이 의미하는 것은 masterbranchX세 파일 모두에 대한 변경 사항이 충돌없이 함께 결합되었다는 것입니다.

git diff --cached; 를 실행하여 병합이 수행 된 방식을 검사 할 수 있습니다 .

git diff --cached file1
git diff --cached file2
git diff --cached file3

병합이 바람직하지 않은 것을 발견하면

  1. 파일을 직접 편집하십시오
  2. 저장
  3. git commit

병합하지 않고 file1현재 분기에서 버전을 유지하려는 경우

운영

git checkout HEAD file1

병합하지 않고 file2버전 만 원하는 경우branchX

운영

git checkout branchX file2

당신이 원하는 경우 file3자동으로 병합 할, 아무것도하지 않습니다.

Git은 이미이 시점에서 병합했습니다.

file4위의 Git 병합 실패입니다. 이는 동일한 라인에서 발생하는 두 가지 모두에 변경이 있음을 의미합니다. 여기서 충돌을 수동으로 해결해야합니다. 파일을 직접 편집하거나 원하는 브랜치에서 버전에 대한 체크 아웃 명령을 실행하여 병합 된 내용을 버릴 수 있습니다 file4.

마지막으로 잊지 마세요 git commit.


답변

위의 접근 방식이 마음에 들지 않습니다. cherry-pick을 사용하면 단일 변경을 선택하는 것이 좋지만 일부 변경을 제외하고 모든 변경을 가져 오려면 고통입니다. 여기 내 접근 방식이 있습니다.

--interactivegit merge에 전달할 수있는 인수 는 없습니다 .

대안은 다음과 같습니다.

‘feature’브랜치에 일부 변경 사항이 있고 일부를 전부는 아니지만 부주의하게 ‘마스터’로 가져 오려고합니다 (즉, 각각 체리 선택하고 커밋하고 싶지는 않습니다)

git checkout feature
git checkout -b temp
git rebase -i master

# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change

# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

git checkout master
git pull . temp
git branch -d temp

따라서 쉘 스크립트로 래핑하고 master를 $ to로 변경하고 기능을 $ from으로 변경하면 좋습니다.

#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp

답변

갈 다른 방법이 있습니다.

git checkout -p

그것은 사이의 혼합 git checkout이며 git add -p정확히 당신이 찾고있는 것일 수 있습니다.

   -p, --patch
       Interactively select hunks in the difference between the <tree-ish>
       (or the index, if unspecified) and the working tree. The chosen
       hunks are then applied in reverse to the working tree (and if a
       <tree-ish> was specified, the index).

       This means that you can use git checkout -p to selectively discard
       edits from your current working tree. See the “Interactive Mode”
       section of git-add(1) to learn how to operate the --patch mode.

답변

이러한 답변 중 일부는 꽤 좋지만 실제로는 실제로 지점의 특정 파일을 선택하는 OP의 원래 제약 조건에 아무도 대답하지 않은 것 같습니다. 이 솔루션은 그렇게하지만 파일이 많은 경우 지루할 수 있습니다.

당신이이 말을하자 master, exp1exp2지점. 각 실험 분기에서 하나의 파일을 마스터로 병합하려고합니다. 나는 이런 식으로 할 것입니다 :

git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# save these files as a stash
git stash
# merge stash with master
git merge stash

이렇게하면 원하는 각 파일에 대한 파일 내 차이점이 제공됩니다. 더 이상 없습니다. 그 이하도 아닙니다. 버전마다 파일이 완전히 다른 경우 유용합니다. 필자의 경우 앱을 Rails 2에서 Rails 3으로 변경하는 것이 좋습니다.

편집 : 파일을 병합하지만 스마트 병합을 수행합니다. 파일 내 diff 정보를 얻는 데이 방법을 사용하는 방법을 알 수 없었습니다 (아마도 여전히 큰 차이가있을 것입니다.이 -s recursive -X ignore-all-space옵션 을 사용하지 않으면 공백과 같은 성가신 작은 것들이 다시 병합됩니다 )


답변

1800 INFORMATION의 답변이 완전히 맞습니다. git noob으로서, “git cherry-pick 사용”은 인터넷에서 조금 더 파지 않고 이것을 알아 내기에 충분하지 않았으므로 다른 사람이있는 경우 더 자세한 가이드를 게시 할 것이라고 생각했습니다. 비슷한 보트.

내 유스 케이스는 다른 사람의 github 브랜치에서 내 자신의 변경 사항을 선택적으로 가져오고 싶었습니다. 변경 사항이있는 로컬 지점이 이미있는 경우 2 단계와 5-7 단계 만 수행하면됩니다.

  1. 가져올 변경 사항을 사용하여 로컬 브랜치를 작성하십시오 (작성되지 않은 경우).

    $ git branch mybranch <base branch>

  2. 그것으로 전환하십시오.

    $ git checkout mybranch

  3. 상대방의 계정에서 원하는 변경 사항을 풀다운하십시오. 아직 원격으로 추가하지 않으려는 경우.

    $ git remote add repos-w-changes <git url>

  4. 지점에서 모든 것을 끌어 내십시오.

    $ git pull repos-w-changes branch-i-want

  5. 커밋 로그를보고 원하는 변경 사항을 확인하십시오.

    $ git log

  6. 변경 사항을 가져 오려는 지점으로 다시 전환하십시오.

    $ git checkout originalbranch

  7. 체리는 해시로 커밋을 하나씩 선택합니다.

    $ git cherry-pick -x hash-of-commit

모자 팁 : http://www.sourcemage.org/Git_Guide