특정 분기에 대해서만 커밋을 얻는 Git 로그


214

특정 지점의 일부인 모든 커밋을 나열하고 싶습니다.

다음과 같이 지점의 모든 커밋뿐만 아니라 부모 (마스터)의 커밋도 모두 나열합니다.

git log mybranch

내가 찾은 다른 옵션은 마스터가 도달 할 수있는 커밋을 제외하고 원하는 것을 제공하지만 다른 지점 이름을 알 필요가 없도록하고 싶습니다.

git log mybranch --not master

나는을 사용하려고 git for-each-ref했지만 mybranch도 나열하므로 실제로는 모두 제외합니다.

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

최신 정보:

나는 얼마 전에 찾은 새로운 옵션을 테스트 중이며 지금까지 이것이 내가 찾던 것일 수 있습니다.

git log --walk-reflogs mybranch

업데이트 (2013-02-13T15 : 08) :

--walk-reflogs 옵션은 좋지만, reflog에 대한 만료가 있는지 확인했습니다 (기본값 90 일, gc.reflogExpire ).

나는 내가 찾고있는 대답을 찾았다 고 생각합니다.

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

사용 가능한 분기 목록에서 현재 분기를 제거하고 해당 목록을 사용하여 로그에서 제외합니다. 이렇게하면 mybranch 만 도달 하는 커밋 만 얻습니다 .



이미 그 질문도 보았지만 같은 것은 아니었다
dimirc

2
그것이 당신이 원하는 것입니까? "업스트림에없는 내 지점에있는 것"또는 "마스터에없는 내 지점에있는 것"이라는 목표를 염두에 두는 것이 좋습니다. 또한 git은 가지 치기가 빠르지 만 분기가 많을수록 더 비쌉니다. bzr의 "missing"명령 후에 "git missing"이라고 부르는 스크립트가 있습니다. github.com/jszakmeister/etc/blob/master/git-addons/git-missing에서 찾을 수 있습니다 .
존 Szakmeister

1
사실은 제외 그래서 "마스터"항상 가지 습관, 후받을 훅이 필요
dimirc을

예, StarPinkER가 언급 한 사본은 나를 위해 잘 작동했습니다 : git log $ (git merge-base HEAD branch) .. branch
charo

답변:


165

당신이 사용해야하는 것에서 cherry:

git cherry -v develop mybranch

이것은 mybranch 내에 포함되어 있지만 개발 되지 않은 모든 커밋을 보여줍니다 . 마지막 옵션 ( mybranch )을 생략 하면 대신 현재 분기가 비교됩니다.

VonC가 지적했듯이, 당신은 항상 지점을 다른 지점과 비교하고 있으므로 지점을 알고 비교할 지점을 선택하십시오.


4
이것은 내가 필요로 한 것이지만, 더 직관적 인 명령이 있어야합니다 (Git 세계에서도).
세스

12
git cherry -v master현재 분기와 마스터 분기를 비교할 수도 있습니다 .
Pithikos 2016 년

2
자식 체리를 사용할 때의 위험은 커밋이 파일 차이가 분 기간에 일치하는 경우에만 일치한다는 것입니다. 하나의 브랜치와 다른 브랜치의 차이점을 다르게 만드는 병합이 수행되면 git cherry는 다른 커밋으로 간주합니다.
Ben

이것은 단지 나에게 준다 fatal: Unknown commit mybranch.
매트 아놀드

1
@MattArnold 당신은 텍스트 "develop"와 "mybranch"를 당신의 저장소에 존재하는 브랜치로 변경해야합니다
Smilie

40

그러나 다른 지점 이름을 알아야 할 필요는 없습니다.

나는 이것이 가능하지 않다고 생각한다 : Git의 브랜치는 " git diff does not show show "에 설명 된 것처럼 항상 다른 커밋 또는 적어도 다른 커밋을 기반으로한다 .

여기에 이미지 설명을 입력하십시오

올바른 커밋을 표시하려면 로그에 대한 참조 점이 필요합니다.

" GIT – 어디에서 분기 했습니까? " 에서 언급 한대로 :

분기는 단순히 DAG의 특정 커밋에 대한 포인터입니다.

따라서 git log master..mybranch하나의 대답 이라도 여전히 mybranch기반으로하는 myotherbranch경우 자체 기반으로 너무 많은 커밋을 표시 합니다 master.

해당 참조 (지점의 원점)를 찾으려면 커밋을 구문 분석하고 다음과 같이 커밋을 확인하십시오.


26

마침내 OP가 원하는 것을 수행하는 방법을 찾았습니다. 다음과 같이 간단합니다.

git log --graph [branchname]

이 명령은 제공된 분기에서 도달 가능한 모든 커밋을 그래프 형식으로 표시합니다. 그러나 *커밋 라인의 첫 번째 문자 인 커밋 그래프를 보면 해당 브랜치의 모든 커밋을 쉽게 필터링 할 수 있습니다 .

예를 들어 git log --graph master아래에서 cakephp GitHub 리포지토리 의 발췌 부분을 살펴 보겠습니다 .

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <lorenzo@users.noreply.github.com>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <mark@mark-story.com>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <mark@mark-story.com>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <mark@mark-story.com>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <jadbitar@mac.com>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

당신 만 커밋을 볼 수 있듯이 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4c3f45e811e4b49fe27624b57c3eb8f4721a4323b*에있는 첫 번째 문자를 라인을 커밋합니다. 이 커밋은 마스터 브랜치에서 온 것이고 다른 4 개의 커밋은 다른 브랜치에서 온 것입니다.


11

다음 쉘 명령은 원하는 작업을 수행해야합니다.

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

경고

이 경우 mybranch체크 아웃, 위의 명령이 작동하지 않습니다. 이는 커밋에 mybranch도달 할 수 HEAD있기 때문에 Git은 커밋을 고유 한 것으로 간주하지 않습니다 mybranch. mybranch체크 아웃 할 때 작동하게하려면 다음에 대한 제외도 추가해야합니다 HEAD.

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

그러나를 체크 아웃 하지 않으면 제외 HEAD하지 않아야합니다 mybranch. 그렇지 않으면 독점이 아닌 커밋이 표시 될 위험이 mybranch있습니다.

마찬가지로 origin/mybranch로컬 mybranch브랜치에 해당 하는 원격 브랜치가있는 경우 이를 제외해야합니다.

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

그리고 원격 브랜치가 원격 리포지토리의 기본 브랜치 인 경우 (보통은 true origin/master), 제외 origin/HEAD해야합니다.

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

당신이있는 경우 분기 체크 아웃, 그리고 거기에 원격 지점이다, 그리고 원격 지점은 다음 많이 제외한 결국, 원격 저장소에 대한 기본값입니다

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

설명

git rev-list명령은 주어진 개정을 수행하고 발견 된 SHA1 식별자를 덤프하는 저수준 (배관) 명령입니다. git logSHA1 (로그 메시지, 작성자 이름, 타임 스탬프 없음, "팬시"항목 없음) 만 표시한다는 점 을 제외하고 는 동등한 것으로 생각하십시오 .

--no-walk옵션, 이름에서 알 수 있듯이, 방지 git rev-list조상 체인을 걸어에서. 따라서 입력 git rev-list --no-walk mybranch하면 mybranch분기 의 팁 커밋 식별자 인 하나의 SHA1 식별자 만 인쇄됩니다 .

--exclude=refs/heads/mybranch --all인수 알 git rev-list을 제외하고 각 기준에서 시작합니다 refs/heads/mybranch.

git rev-list --no-walk --exclude=refs/heads/mybranch --all따라서을 실행 하면 Git은을 제외한 각 심판의 팁 커밋의 SHA1 식별자를 인쇄합니다 refs/heads/mybranch. 이 커밋과 그 조상은 관심 이 없는 커밋입니다.이 커밋은보고 싶지 않습니다 .

다른 커밋은 우리의 출력을 수집, 그래서보고 싶은 것들 git rev-list --no-walk --exclude=refs/heads/mybranch --all과 모든 그러나 그 커밋과 그들의 조상을 보여 힘내을 말한다.

--no-walk인수는 큰 저장소에 필요한 (작은 저장소에 대한 최적화입니다) : 그것은, 힘내 인쇄 할 것없이, 쉘 수집해야합니다 (메모리에 저장) 많은 사람들이 필요 이상으로 식별자를 커밋합니다. 저장소가 크면 수집 된 커밋 수가 쉘의 명령 줄 인수 제한을 쉽게 초과 할 수 있습니다.

힘내 버그?

나는 다음이 작동 할 것으로 예상했다.

git log --all --not --exclude=refs/heads/mybranch --all

그러나 그렇지 않습니다. 나는 이것이 Git의 버그라고 생각하지만 의도적 일 수 있습니다.


좋은 설명입니다. +1
VonC

5
나는 Mercurial의 방법을 알고 싶었습니다 hg log -b <branch>. 사람들이 왜 자식이 비우호적이라고 말하는지 이해하지 못합니다. / s
weberc2

git log --all --not --exclude=refs/heads/mybranch --all작동 하지 않는지 모르겠지만 git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --allHEAD와 원점을 제외하는 것과 동일한 경고가 있습니다.
Ben C

8

빠른 답변 :

git log $(git merge-base master b2)..HEAD

의 말을하자:

  1. 당신은 마스터 지점 을 가지고

  2. 몇 가지 커밋을 수행하십시오.

  3. b2 라는 브랜치를 만들었습니다.

  4. git log -n1; 커밋 ID는 b2와 master 간의 병합 기준입니다.

  5. B2 에서 몇 가지 커밋 수행

  6. git log b2 및 master의 로그 기록을 표시합니다

  7. 커밋 범위를 사용하십시오. 개념에 익숙하지 않은 경우 Google에 초대하거나 overflow-it

    실제 상황에서는 예를 들어

    git log commitID_FOO..comitID_BAR
    

    ".."는 log 명령의 범위 연산자입니다.

    즉, 간단한 형식으로 commitID_FOO보다 최신의 모든 로그를 제공하십시오.

  8. 병합 기반 4 번을보십시오.

    그래서 : git log COMMITID_mergeBASE..HEAD당신에게 차이를 보여줄 것입니다

  9. Git은 이런 식으로 병합 기반을 검색 할 수 있습니다

    git merge-base b2 master
    
  10. 마지막으로 다음을 수행 할 수 있습니다.

    git log $(git merge-base master b2)..HEAD
    

4

다음과 같이 시도해보십시오.

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

또는 Git 사용자 매뉴얼레시피에서 빌리기 :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )

+1. 나는 당신의 지점의 기원을 찾기 위해 커밋을 파싱해야한다고 대답했습니다.
VonC

log --walk-reflogs를 사용 했습니까? 이 옵션에 대해 읽고 있으며 지금까지 필요한 결과를 제공하고 있습니다 (여전히 테스트)
dimirc

@dimirc Reflogs는 모두 다른 짐승입니다. 일반적으로 복구 목적으로 시간이 지남에 따라 지점을 기록합니다. 나는 당신이 당신의 post-receive hook에서 무엇을하고 있는지 잘 모르겠지만, 만약 당신이 그것을 설명한다면, 사람들은 당신의 문제에 대해 더 현명한 답변을 줄 수있을 것입니다.
존 Szakmeister

모든 커밋 메시지를 파싱 / 확인해야합니다. 내가 다루고 싶은 경우는 누군가가 마스터에서 여러 커밋을 푸시하고 여러 커밋으로 새 분기를 만드는 경우입니다. 수신 후 후크는 마스터 및 새 분기와 같이 refs / branches에 대해 수행 된 변경 사항을 확인해야합니다. 마스터에서 커밋 될 수 있기 때문에 커밋 메시지를 두 번 구문 분석하지 않도록 새 분기의 경계를 알아야합니다.
dimirc

1
괜찮아. 그런 다음 위에서 설명한 위의 접근 방식이 실제로 원하는 것이라고 생각합니다. reflog를 사용하면 일정 시간이 지나면 항목이 떨어질 것이므로 두통이 발생할 수 있다고 생각합니다. 당신 git show-ref --tags도 사용을보고 싶을 수도 있습니다.
존 Szakmeister

4
git rev-list --exclude=master --branches --no-walk

아닌 모든 지점의 팁을 나열합니다 master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

master다른 지점의 기록에없는 모든 기록을의 기록 에 나열합니다 .

시퀀싱은 커밋 선택을 위해 필터 파이프 라인을 설정하는 옵션에 중요하므로 --branches적용 할 제외 패턴 --no-walk을 따라야하며 커밋을 제공하는 필터를 따라야합니다.


4

현재 분기에 커밋을 출력합니다. 인수가 전달되면 해시 만 출력됩니다.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
  
  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 
  
  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
  
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi

1
이것은 약 100 개의 관련없는 로그 메시지를 생성했습니다.
Arlie Stephens

안녕하세요 @ArlieStephens-시도했지만 여전히 효과가 있습니까? 위의 도움말과 더 많은 오류 메시지를 추가했습니다. 어떻게되는지 알려주세요!
Brad Parks

흥미 롭군 지금 코드를 살펴보면 내가 관심있는 브랜치가 마스터에서 벗어났다고 가정하는 것만 큼 간단하다고 생각합니다. 현재 코드를 사용하여 부모 분기를 명시 적으로 지정할 수 있습니다. (IIRC, 내 개발 지점은 마스터가 아닌 릴리스 지점에서 나왔습니다.)
Arlie Stephens

@ArlieStephens-예, 기능이 바뀌지 않았다고 생각합니다 .... 로컬 테스트 후에 한 번 더 업데이트하고 문서를 좀 더 정확하게 만들었습니다. 그러나 나는 didnt 한의 문서 그것은
브래드 공원

3

다음 명령을 사용하고 있습니다.

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

또는

git log --no-merges --graph --oneline --decorate master..<mybranch>

1

이 방법은 비교적 쉽다는 것을 알았습니다.

지점으로 결제

  1. 운영

    git rev-list --simplify-by-decoration -2 HEAD
    

이것은 두 개의 SHA 만 제공합니다.

1) 지점의 마지막 커밋 [C1]

2) 지점의 첫 번째 커밋에 부모를 커밋 [C2]

  1. 이제 실행

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

여기에서 C1과 C2는 첫 번째 명령을 실행할 때 얻을 수있는 두 개의 문자열입니다. 두 번째 명령에서이 값을 <>없이 두십시오.

이것은 브랜치 내에서 파일 변경 이력 목록을 제공합니다.


질문의 처음 세 줄을 읽으면 저자가이 정확한 명령을 나열하고 왜 이것이 원하는 명령이 아닌지 설명합니다.
black_fm

아 @ black_fm 나는 대답을 약간 변경했다. 유용하다고 생각되면 투표 할 수 있습니다. :)
Mustkeem K

0

제 상황에서는 Git Flow와 GitHub를 사용하고 있습니다. 이 작업을 수행하기 위해 필요한 것은 다음과 같습니다. 기능 분기를 GitHub의 개발 분기와 비교하십시오.

기능 브랜치에 대한 커밋 만 표시됩니다.

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

https://github.com/your_repo/compare/develop...feature_branch_name


"풀 요청이 어떻게 생겼는지 확인하고 싶습니다"라는 상황에 처할 때 가장 좋은 해결책은 종종 무시 git하고 대신 GitHub를 사용하여 풀 요청을하거나 분기를 비교하는 것입니다.
pkamb
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.