git reset --soft의 실제 사용?


136

나는 한 달 이상 git과 함께 일 해왔다. 실제로 어제 처음으로 리셋을 사용했지만 소프트 리셋은 여전히 ​​나에게 의미가 없습니다.

소프트 리셋을 사용하여 인덱스 또는 작업 디렉토리를 변경하지 않고 커밋을 편집 할 수 있음을 이해 git commit --amend합니다.

이 두 명령이 실제로 동일 합니까 ( reset --softvs commit --amend)? 실용적인 용어로 하나를 사용해야하는 이유는 무엇입니까? 더 중요한 것은 reset --soft커밋을 수정하는 것 외에 다른 용도 가 있습니까?

답변:


110

git reset이동 HEAD에 관한 것이며, 일반적으로 분기 참조 입니다.
질문 : 워킹 트리와 인덱스는 어떻습니까?
함께 사용하면 --soft, 이동 HEAD, 가장 자주 분기 심판 업데이트 만HEAD .
이것은 다음과 다릅니다 commit --amend.

  • 새로운 커밋을 만들지 않습니다.
  • 실제로 HEAD를 모든 커밋으로 옮길 수 있습니다 ( 현재 커밋을 다시 실행하면서 HEAD를 움직이지 않는 것과 관련 commit --amend이 있습니다 )

이 결합 예제를 찾았습니다.

  • 고전적인 합병
  • 서브 트리 병합

커밋 병합은 모두 하나로 통합됩니다 (두 개 이상의 브랜치가 병합되어 있기 때문에 문어).

Tomas "wereHamster"Carnecky"Subtree Octopus merge"기사 에서 다음과 같이 설명합니다 .

  • 하나의 프로젝트를 다른 프로젝트의 서브 디렉토리에 병합 한 후 서브 프로젝트를 최신 상태로 유지하려는 경우 서브 트리 병합 전략을 사용할 수 있습니다. git 서브 모듈의 대안입니다.
  • 문어 병합 전략을 사용하여 세 개 이상의 분기를 병합 할 수 있습니다. 일반적인 전략은 두 개의 브랜치 만 병합 할 수 있으며 그보다 더 많이 병합하려고하면 git은 자동으로 낙지 전략으로 넘어갑니다.

문제는 하나의 전략 만 선택할 수 있다는 것입니다. 그러나 전체 저장소가 원자 적으로 새로운 버전으로 업데이트되는 깨끗한 기록을 얻기 위해 두 가지를 결합하고 싶었습니다.

나는 슈퍼 projectA프로젝트, 그것을 호출 하고 서브 프로젝트를 가지고 있는데 projectB, 나는 서브 디렉토리에 병합했다 projectA.

(하위 트리 병합 부분입니다)

또한 몇 가지 로컬 커밋을 유지하고 있습니다.
ProjectA정기적으로 업데이트되며 projectB며칠 또는 몇 주마다 새 버전이 있으며 일반적으로의 특정 버전에 따라 다릅니다 projectA.

나는 두 프로젝트를 업데이트하기로 결정했을 때, 나는 단지에서 잡아 당기지 마십시오 projectAprojectB 그로 전체 프로젝트의 원자 갱신해야 무엇을위한 두 개의 커밋을 만들 것입니다 .
대신에, 나는 하나의 병합하는 콤바인 커밋 만들고 projectA, projectB내 지역 커밋 .
여기서 까다로운 부분은 이것이 문어 병합 (세 개의 머리) 이지만 projectB하위 트리 전략과 병합되어야한다는 것 입니다. 그래서 이것이 내가하는 일입니다.

# Merge projectA with the default strategy:
git merge projectA/master

# Merge projectB with the subtree strategy:
git merge -s subtree projectB/master

여기에 저자는 사용 reset --hardread-tree처음 두 병합은 작업 트리와 인덱스에 한 일을 복원하지 않고 곳입니다 reset --soft도움이 될 수 있습니다
나는 그 두 병합 다시 실행하는 방법을 일했다, 즉, 내 작업 트리와 인덱스입니다 괜찮지 만 그 두 커밋을 기록하지 않아도됩니까?

# Move the HEAD, and just the HEAD, two commits back!
git reset --soft HEAD@{2}

이제 Tomas의 솔루션을 다시 시작할 수 있습니다.

# Pretend that we just did an octopus merge with three heads:
echo $(git rev-parse projectA/master) > .git/MERGE_HEAD
echo $(git rev-parse projectB/master) >> .git/MERGE_HEAD

# And finally do the commit:
git commit

따라서 매번 :

  • 당신은 당신이 끝내는 것에 만족합니다 (작업 트리 및 색인 측면에서)
  • 당신은 거기에 도착한 모든 커밋에 만족 하지 않습니다 .

git reset --soft 답입니다.


8
스스로 참고 git reset --soft: stackoverflow.com/questions/6869705/…
VonC

3
잘못된 브랜치를 약속 한 경우에도 유용합니다. 모든 변경 사항은 준비 영역으로 돌아가서 올바른 지점을 체크 아웃하는 동안 함께 이동합니다.
smoebody

44

유스 케이스-일련의 로컬 커밋 결합

"죄송합니다.이 세 가지 커밋은 하나 일 수 있습니다."

따라서 마지막 3 개 (또는 무엇이든) 커밋을 취소하십시오 (색인이나 작업 디렉토리에 영향을 미치지 않고). 그런 다음 모든 변경 사항을 하나로 커밋하십시오.

예 :

> git add -A; git commit -m "Start here."
> git add -A; git commit -m "One"
> git add -A; git commit -m "Two"
> git add -A' git commit -m "Three"
> git log --oneline --graph -4 --decorate

> * da883dc (HEAD, master) Three
> * 92d3eb7 Two
> * c6e82d3 One
> * e1e8042 Start here.

> git reset --soft HEAD~3
> git log --oneline --graph -1 --decorate

> * e1e8042 Start here.

이제 모든 변경 사항이 유지되고 하나로 커밋 할 수 있습니다.

질문에 대한 짧은 답변

이 두 명령이 실제로 동일 합니까 ( reset --softvs commit --amend)?

  • 아니.

실용적인 용어로 하나를 사용해야하는 이유는 무엇입니까?

  • commit --amend 가장 최근의 커밋에서 파일을 추가하거나 메시지를 변경합니다.
  • reset --soft <commit> 여러 순차 커밋을 새로운 커밋으로 결합합니다.

더 중요한 것은 reset --soft커밋을 수정하는 것 외에 다른 용도 가 있습니까?

  • 다른 답변보기 :)

2
에 대한 다른 답변을 참조하십시오 "있는 다른 어떤 용도로도 reset --soft개정 차별화를 A는 커밋 - 아니오"
안토니 Hatchkins

마지막 의견에 대한 답변-부분적으로 동의했지만 단일 커밋 을 수정하는 것이 너무 구체적 이라고 말하고 싶습니다 . 예를 들어, 기능이 작성되면 모든 것을 스쿼시하고 검토 자에게 더 유용한 새로운 커밋을 개척 할 수 있습니다. 소프트 리셋 (plain 포함 git reset)은 (a) 기록을 다시 쓰려고 할 때, (b) 이전 커밋에 신경 쓰지 않으므로 (대화식 rebase의 까다로운 것을 피할 수 있음) (c) 변경하려는 커밋이 둘 이상 있어야합니다 (그렇지 않으면 commit --amend더 간단합니다).
johncip

18

나는 그것을 마지막 커밋 보다 더 수정하기 위해 사용합니다 .

커밋 A에서 실수를 한 다음 커밋 B를 만들었다 고 가정 해 봅시다. 이제 B 만 수정할 수 있습니다. 따라서 git reset --soft HEAD^^A를 수정하고 다시 커밋 한 다음 B를 다시 커밋합니다.

물론, 그것은 큰 커밋에 매우 편리하지는 않지만 어쨌든 큰 커밋을해서는 안됩니다 ;-)


3
git commit --fixup HEAD^^ git rebase --autosquash HEAD~X잘 작동합니다.
Niklas

3
git rebase --interactive HEAD^^커밋 A와 B를 모두 편집 하도록 선택합니다 . 이렇게하면 A와 B의 커밋 메시지가 유지됩니다 (필요한 경우에도 여전히 커밋 메시지를 수정할 수 있음).
Paul Pladijs

2
A로 재설정 한 후 B를 어떻게 커밋합니까?
northben

1
아마 적은 작업의 또 다른 방법은 다음이 B의 해쉬를 저지 얻을, 당신의 자식 로그를 확인하고 git reset A, 확인하고 변경 내용을 추가 git commit --amend, git cherry-pick <B-commit-hash>.
naught101

15

또 다른 잠재적 인 사용은 숨김에 대한 대안입니다 (일부 사람들이 싫어하는 예 : https://codingkilledthecat.wordpress.com/2012/04/27/git-stash-pop-considered-harmful/ 참조 ).

예를 들어, 지점에서 작업 중이고 마스터에서 긴급하게 무언가를 수정해야하는 경우 다음을 수행 할 수 있습니다.

git commit -am "In progress."

그런 다음 마스터를 확인하고 수정하십시오. 완료되면 지점으로 돌아가서

git reset --soft HEAD~1

내가 그만 둔 곳에서 계속 일하기 위해서


3
업데이트 (지금은 git을 더 잘 이해하고 있음) : --soft변경 사항을 즉시 준비하는 데 신경 쓰지 않는 한 실제로 여기에서는 불필요합니다. 나는 이제 git reset HEAD~이것을 할 때 사용 합니다. 만약 내가 내가 가지를 전환해야하고, 그런 식으로 유지하고자 할 때 약간의 변화는 내가 할, 개최 git commit -m "staged changes"후, git commit -am "unstaged changes"나중에, git reset HEAD~다음에 git reset --soft HEAD~완전히 작동 상태를 복원 할 수 있습니다. 솔직히 말해서 나는이 두 가지를 훨씬 덜한다. git-worktree:)
deltacrux

7

git reset --soft인덱스 및 작업 트리에서 변경 한 내용의 부모로 사용하려는 버전을 변경하는 데 사용할 수 있습니다 . 이것이 유용한 경우는 드 rare니다. 때로는 작업 트리에서 변경 한 내용이 다른 브랜치에 속해야한다고 결정할 수도 있습니다. 또는 이것을 여러 커밋을 하나로 축소하는 간단한 방법으로 사용할 수 있습니다 (스쿼시 / 접기와 유사).

실용적인 예는 VonC의이 답변을 참조하십시오. Git에서 처음 두 커밋을 스쿼시 하시겠습니까?


그것은 내가 전에 찾지 못했던 좋은 질문입니다. 그러나 reset soft를 사용하여 다른 브랜치에 변경 사항을 적용하는 방법을 볼 수 있는지 잘 모르겠습니다. 그래서 지점을 체크 아웃 한 다음 사용 git reset --soft anotherBranch하고 커밋합니까? 하지만 당신은 정말 ckeckout 분기를 변경하지 않는, 그래서 당신은 저지 할 지점 하거나 anotherBranch ?
AJJ

이 작업을 수행하는 경우 git checkout을 사용하지 않는 것이 중요합니다. HEAD가 가리키는 개정을 조작하는 방법으로 git reset --soft를 생각하십시오.
Johannes Rudolph

7

다른 컴퓨터에서 작업을 계속하려는 경우 한 가지 가능한 사용법이 있습니다. 다음과 같이 작동합니다.

  1. 숨김 같은 이름으로 새 지점을 체크 아웃하십시오.

    git checkout -b <branchname>_stash
    
  2. 은신처를 밀어 올리십시오.

    git push -u origin <branchname>_stash
    
  3. 다른 기계로 전환하십시오.

  4. 줄기와 기존 가지를 모두 아래로 당깁니다.

    git checkout <branchname>_stash; git checkout <branchname>
    
  5. 기존 지사에 있어야합니다. 숨김 지점에서 변경 사항을 병합하고

    git merge <branchname>_stash
    
  6. 병합하기 전에 기존 지점을 1로 소프트 재설정

    git reset --soft HEAD^
    
  7. 숨김 분기를 제거하고

    git branch -d <branchname>_stash
    
  8. 또한 스 태쉬 브랜치를 원점에서 제거하십시오.

    git push origin :<branchname>_stash
    
  9. 변경 사항을 정상적으로 보관 한 것처럼 계속 작업하십시오.

나는 미래에 GitHub와 공동으로 생각합니다. 이 "원격 숨김"기능을 더 적은 단계로 제공해야합니다.


2
첫 번째 컴퓨터의 첫 번째 숨김 및 팝업이 완전히 필요하지 않다는 것을 지적하고 싶습니다. 더티 작업 복사본에서 직접 새 분기를 만들고 커밋 한 다음 변경 사항을 원격으로 푸시하면됩니다.

7

한 가지 실용적인 용도는 로컬 리포지토리에 이미 커밋 한 경우 (예 : git commit -m) git reset --soft HEAD ~ 1 을 수행하여 마지막 커밋을 되돌릴 수 있습니다.

또한 지식에 대한, 다음을 수행하여 준비를 취소 할 수 있습니다. (즉, 자식 추가로) 이미 변경 사항을 개최 당신이 경우 자식 재설정을 HEAD를 --mixed 또는 내가 일반적으로도 바로 사용했습니다git reset

마지막으로, git reset --hard는 로컬 변경을 포함하여 모든 것을 지 웁니다 . ~ after head는 상단에서 몇 개의 커밋을하는지 알려줍니다.


1
git reset --soft HEAD ~1나주는 fatal: Cannot do soft reset with paths.내가 우리가 될 수 있도록 HEAD 후 공간을 제거 할 필요가 있다고 생각git reset --soft HEAD~1
앤드류 LOHR

6

' git reset --soft <sha1>' 를 사용하는 가장 큰 이유 HEAD는 베어 리포 로 이동 하는 것입니다.

--mixed또는 --hard옵션 을 사용 하려고하면 존재하지 않는 트리 및 / 또는 색인을 수정하고 작업하려고하므로 오류가 발생합니다.

참고 : Bare Repo에서 직접 수행해야합니다.

참고 : 베어 리포지토리에서 재설정하려는 분기가 활성 분기인지 확인해야합니다. 그렇지 않은 경우 리포지토리 에 직접 액세스 할 때 베어 리포지토리에서 활성 분기를 업데이트하는 방법에 대한 VonC의 답변 을 따르십시오 .


1
이전 답변 ( stackoverflow.com/questions/4624881/… ) 에서 언급했듯이 베어 리포지토리 (여기에서 언급 한)에 직접 액세스 할 때 적용됩니다. 그래도 +1입니다.
VonC

@VonC 예, 절대적으로 정확하며 메모를 추가해 주셔서 감사합니다! 재설정이 repo에서 직접 수행되었다고 가정하기 때문에 계속 추가하는 것을 잊어 버렸습니다. 또한 베어 리포지토리에서 재설정하려는 지점이 활성 지점이라고 가정합니다. 분기가 활성 분기가 아닌 경우 베어 리포지토리의 활성 분기를 업데이트하는 방법에 대한 답변 ( stackoverflow.com/questions/3301956/… ) 별로 업데이트해야합니다 . 활성 분기 정보로 답변을 업데이트하겠습니다. 다시 감사합니다 !!!
Hazok

2

SourceTree는 원하는 비트를 준비하기 위해 매우 편리한 인터페이스를 갖춘 git GUI입니다. 적절한 개정을 수정하기 위해 원격으로 유사한 것은 없습니다.

따라서이 시나리오 git reset --soft HEAD~1보다 훨씬 유용합니다 commit --amend. 커밋을 취소하고 모든 변경 사항을 준비 영역으로 되돌리고 SourceTree를 사용하여 스테이지 비트 조정을 다시 시작할 수 있습니다.

실제로 commit --amend두 가지 중 더 중복 된 명령 인 것처럼 보이지만 git은 git이며 약간 다른 작업을 수행하는 유사한 명령에서 벗어나지 않습니다.


1

이 스레드의 답변을 정말로 좋아 git reset --soft하지만 그럼에도 불구하고 약간 다르지만 매우 실용적인 시나리오에 사용합니다.

마지막 커밋 후 변경 사항 (스테이지 및 비 스테이지)을 보여주는 좋은 diff 도구가있는 IDE를 개발에 사용합니다. 이제 대부분의 작업에는 여러 커밋이 포함됩니다. 예를 들어 특정 작업을 완료하기 위해 5 개의 커밋을 수행한다고 가정 해 보겠습니다. 1-5의 모든 증분 커밋 동안 IDE에서 diff 도구를 사용하여 마지막 커밋의 변경 사항을 확인합니다. 커밋하기 전에 변경 사항을 검토하는 것이 매우 유용한 방법입니다.

그러나 내 작업이 끝나면 모든 변경 사항을 함께보고 (첫 번째 커밋 이전) 풀 요청을하기 전에 자체 코드 검토를 수행하려면 이전 커밋의 변경 사항 (커밋 후) 만 볼 수 있습니다 4) 현재 작업의 모든 커밋에서 변경되지는 않습니다.

그래서 나는 git reset --soft HEAD~44 개의 커밋을 다시 사용 합니다. 이를 통해 모든 변경 사항을 함께 볼 수 있습니다. 변경 사항을 확신하면 변경 내용 git reset HEAD@{1}을 원격으로 자신있게 푸시 할 수 있습니다 .


1
... 다음을 수행 git add --patch하고 git commit(가) 당신이 모두를 함께 무엇을하고 있는지 알고 있다면 당신이 구축 한 것 시리즈를 저지 구축 반복. 첫 번째 커밋은 책상 위의 메모 나 메모의 첫 초안과 같으며 출판이 아닌 생각을 정리하기 위해 존재합니다.
jthill

이봐, 난 네가 제안한 것을 얻지 못했다.
스완 키 코더

1
git reset @{1}첫 번째 초안 시리즈를 복원 하는 대신 git add -p및 에서 게시 시리즈를 만들 수 있습니다 git commit.
jthill

네 맞습니다. 또 다른 방법은 업스트림 / 마스터를 기반으로 커밋을 커밋하는 것입니다 (보통 내가 따르는 방법).
스완 키 코더

1

또 다른 사용 사례는 풀 요청에서 다른 지점을 다른 지점으로 교체하려는 경우입니다.

다음 버전으로 개발 중이며 다음과 같습니다.

  • 기능 B 제거

  • 기능 D 추가

이 과정에서 기능 B에 대해 추가 된 핫픽스를 개발하십시오.

개발을 다음으로 병합 할 수는 있지만 때로는 혼란 스러울 수 있지만 git reset --soft origin/develop변경 사항을 커밋하고 사용하여 분기를 충돌없이 병합하고 변경 사항을 유지할 수 있습니다.

그것은 git reset --soft편리한 명령임이 밝혀졌습니다 . 개인적으로 그것을 사용하여 "WIP"와 같은 "완료된 작업"이없는 커밋을 스쿼시하므로 풀 요청을 열면 모든 커밋을 이해할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.