Getting a list of all children of a given commit

后端 未结 4 920

I\'d like to run git filter-branch on all children of a given commit. This doesn\'t seem to be an easy task, since there doesn\'t appear to be a way to tell

相关标签:
4条回答
  • 2020-12-03 06:32

    Show the ancestry paths to commit A from a set of others:

    git log--ancestry-path^Aothers

    Show all the unreachable commits in the repo:

    git fsck --unreachable --no-reflogs \
    | awk '$2 == "commit" {print $3}'

    Trace all descendants of commit A anywhere in the repo:

    git log --ancestry-path --graph --decorate --oneline ^A \
       --all $(git fsck --unreachable --no-reflogs | awk '$2=="commit" {print $3}')
    

    Show all references whose history includes a commit:

    git log --ancestry-path --graph --simplify-by-decoration --oneline --all ^A
    # and in case A might have a direct ref, add:
    git log --ancestry-path --graph --simplify-by-decoration --oneline A^!
    

    edit: correction: don't show unwanted commits when A itself has parents with other children.

    0 讨论(0)
  • 2020-12-03 06:36

    well, "--branches" or "--all" will include all branch tips, and then "--not A" will exclude A and all its ancestry. However, "--branches --not A" will include branches that don't include A, which I think is not what you need.

    There's no easy way to get everything you want, although you can work it out. This will list all the branches containing commit A:

    git for-each-ref refs/heads/* | while read rev type name; do
      git rev-list $rev | grep $(git rev-parse A) >/dev/null && echo $rev
    done
    

    then you need to list all the revisions reachable from any of those, but not A itself and any revisions back

    git rev-list $(git for-each-ref refs/heads/* | while read rev type name; do
          git rev-list $rev | grep $(git rev-parse A) >/dev/null && echo $rev
        done) --not A
    

    Note that I've only given this a very brief test :p But I think the fundamentals are sound.

    0 讨论(0)
  • 2020-12-03 06:44

    This seems to do it:

    $ for rev in $(git rev-list --branches); do
        git rev-list $rev \
          | grep $(git rev-parse base) &>/dev/null \
        && echo $rev;
      done \
      | xargs -L 1 git rev-list -n 1 --oneline
    f16fd151b374b2aeec8b9247489c518a6347d001 merged in the latest from the base branch
    564d795afb63eab4ffe758dbcd726ca8b790f9f6 spelling correction
    

    The last pipe section with xargs is just to show the commit messages for each of those commits.

    This lists the target commit in addition to its children, which is actually what I wanted. It's pretty durn slow though: it took over 3 seconds to run on a 40-commit repo. This is unsurprising since it's about as brute force as André the Giant. I guess a more elegant method would go through the rev-list for each ref and build a tree of the hashes of each commit linked to its children, then walk it starting at the target commit. But that's kind of complicated, so I was hoping that there was a git command for that :)

    I still need to figure out how to get this set of commits into filter-branch. I guess I can just grep the rev-list of $GIT_COMMIT from within my --tree-filter command.

    0 讨论(0)
  • 2020-12-03 06:47

    I did a alternative version. I don't know if its better or worse.

    getGitChildren(){
        git rev-list --all --parents | grep "^.\{40\}.*${1}.*" | awk '{print $1}' | xargs -I commit git log -1 --oneline commit | cat -
    }
    

    to be used like that:

    $ getGitChildren 2e9df93
    f210105376 feat(something): did that feature
    9a1632ca04 fix(dummy): fix something
    

    It just give the direct children list of a commit.

    0 讨论(0)
提交回复
热议问题