How do I merge from another git branch, excepting some commits, and have sane/easily queried history?

Short version: I’ve got a master branch, which people are working on and committing to. Then I’ve got a branch off of master, call it foo which people are also working on and committing to. Periodically, I want to bring over some, but not all, of the changes from foo back to master. I would like some way for the history of master to be query-able for the presence and absence of commits from foo. This appears problematic. How do I do this?

Long version: Create an example git repo like this:

  • Git always ask passphrase for key
  • “Git for Windows has stopped working” on Windws 7
  • Gitting with a team
  • git fetch remote branch and remote ref
  • Working with python off of a FAT32 filesystem
  • GitHub network graph representing wrong first parent after merge
  • cd /tmp && mkdir gitrepo && cd gitrepo/ && git init
    echo "Something shared" > myFile.txt && git add myFile.txt && git commit -m "Added myFile.txt to master"
    git checkout -b foo master
    echo "Something else shared" > anotherFile.txt && git add anotherFile.txt && git commit -m "Added anotherFile.txt to foo"
    echo "Something specific to foo" > foochange.txt && git add foochange.txt && git commit -m "Added foochange.txt to foo"
    echo "Something else shared again" > yetAnotherFile.txt && git add yetAnotherFile.txt && git commit -m "Added yetAnotherFile.txt to foo"
    git checkout master
    echo "Something specific to master" > masterchange.txt && git add masterchange.txt && git commit -m "Added masterchange.txt to master"
    echo "Specific to master" > masterchange.txt && git add masterchange.txt && git commit -m "Added masterchange.txt on master"
    

    (All discussion from here forward assumes we’re on master)

    Now we’ve got the situation where foo is two commits behind master and has three commits of it’s own. At this point I want to bring back the first and third commits from foo to master but NOT the second.

    The fundamental issue is that the parent of the commit at the head of foo is the commit that I don’t want to merge, but since a commit’s parents are part of that commit’s hash there’s no way to preserve the hash of the commit at the head of foo without also creating a situation where git branch --contains foo^ is true for master.

    For instance, if I did git merge foo it would merge all the commits from foo to master. After doing that I would be able to say git branch --contains foo^ and it would say that both foo and master contain that commit. I tried then doing a git revert foo^ but git branch --contains foo^ still reports that master contains foo^.

    If I git cherry-pick foo foo^^ the two relevant revisions, then I have the changes from those two revisions’ diffs from foo applied in master, but git branch --contains foo^ says that only branch foo contains that commit.

    What I’m trying to achieve here is some way to query the history (without manually correlating hashes stored as text in commit messages) so I can be able to see which commits have and haven’t been merged into master. As mentioned, I know of several ways to get the state of master to be equivalent to what I want (cherry-pick, merge+revert, format-patch/am, diff/patch, etc.) what I’m looking for is some way to query the history for the information I need. I get that git branch --contains will probably not ever work in the way I want it to, but if there’s some alternate way to query the history, that I haven’t thought of, I’m all ears.

    Anyone have any ideas?

  • Is Pushing Feature Branches to Origin Good Practice?
  • how to know which pod spec file your cocoapod install is pointing to
  • Performing merge of two very different branches complicated by need to fast-forward merge-commit
  • Few questions with GIT, possible to have custom .gitignore? Read only access?
  • How to secure the git repo on a live server
  • What's the purpose of the colon in this git repository url?
  • One Solution collect form web for “How do I merge from another git branch, excepting some commits, and have sane/easily queried history?”

    I think git-cherry is the command you are looking for.

    git cherry -v master foo
    

    This shows commits in foo that have not (yet) been merged into master.

    $ git cherry -v master foo
    + 1cffcfb1d061d308e8d33c262e30282a26b195cb Added anotherFile.txt to foo
    + fe0599190a6953c970cd3f94e18ff0c282e89e2c Added foochange.txt to foo
    + 1b548eb45ff50e59f3522ee63edd0c177e842645 Added yetAnotherFile.txt to foo
    
    $ git cherry-pick 1cffcfb1d061d308e8d33c262e30282a26b195cb
    ...
    
    $ git cherry-pick 1b548eb45ff50e59f3522ee63edd0c177e842645
    ...
    
    $ git cherry -v master foo
    - 1cffcfb1d061d308e8d33c262e30282a26b195cb Added anotherFile.txt to foo
    + fe0599190a6953c970cd3f94e18ff0c282e89e2c Added foochange.txt to foo
    - 1b548eb45ff50e59f3522ee63edd0c177e842645 Added yetAnotherFile.txt to foo
    

    From the manual:

    The ones that have equivalent change already in the upstream branch
    are prefixed with a minus (-) sign, and those that only exist in the
    head branch are prefixed with a plus (+) symbol:

    Git Baby is a git and github fan, let's start git clone.