daleyjem
daleyjem

Reputation: 2684

git cherry-pick or merge specific directory from another branch

I've seen different posts on StackOverflow that explain cherry picking a bit, but the comments in their code aren't very specific as to what's a branch and what's a directory. Example git checkout A -- X Y doesn't tell me much.

Basically I want this:

Upvotes: 38

Views: 41321

Answers (6)

akaihola
akaihola

Reputation: 26844

For anyone needing to also exclude some files or directories when moving commits from a repo to another, be aware that you can use Sean Dunlap's recipe and add exclusion rules. So the reverse of his example, to include everything but the tools/mytool directory, would be:

git format-patch -k --stdout \
  master...featureA \
  -- . ':!tools/mytool' \
  | git am -3 -k

The . after -- first includes everything in the repository. ':!tools/mytool' then excludes that one directory (you can also use the long form ':(exclude)tools/mytool').

(Thanks to Nikita Kouevda for the tip in this Reddit comment.)

See also: Git <pathspec> documentation for :(exclude) and :!

Upvotes: 2

Sean Dunlap
Sean Dunlap

Reputation: 631

Here is the right way to cherry-pick commits from another branch for one folder:

git format-patch -k --stdout master...featureA -- tools/mytool | git am -3 -k

This will apply the patches to the "tools/mytool" files only, in order.

If you have a merge conflict on any commit, it will pause for you to fix it. git am --continue will resume where it left off.

See also Git documentation for:

Upvotes: 53

funerr
funerr

Reputation: 8176

You can use git checkout <from_branch> -- <files_to_bring>.
I'd do this: git checkout dev -- tools/my-tool

Explanation: this tells git to replace/copy files from the branch dev and the path tools/my-tool to your current branch.

Upvotes: 16

Fehr
Fehr

Reputation: 544

Jason Rudolph does a great job of summarising this scenario, and the accepted solution in this post:

https://jasonrudolph.com/blog/2009/02/25/git-tip-how-to-merge-specific-files-from-another-branch/

This is a good old question, and the above answers did a great job of answering it, but since I recently came across the issue, and his article stated it so concisely I thought I'd share it here.

Upvotes: 1

Ian
Ian

Reputation: 11850

To answer the original question about how to cherry-pick some directories (as commits instead of a brute-force checkout), this is possible. Imagine that featureA has diverged from master and you want to bring over the tools/my-tool commits.

Assuming that you never made any commits that contain both stuff from /tools/my-tool and stuff from other directories

This will get you the list of commits to master in tools/my-tool (that are not already in featureA), in reverse-chronological order:

git log --no-merges featureA...master tools/my-tool

To say it another way:

git log --no-merges source_branch...dest_branch my/firstpath my/secondpath [...]

To get just the commits you need in chronological order, you need to first reverse the order of the input lines (such as with tail -r or tac), then isolate the column for the commit hash (such as with cut):

git log --format=oneline --no-merges featureA...master tools/my-tool \
    | tail -r \
    | cut -d " " -f 1

And to do the whole operation at once, do this:

git cherry-pick $(git log --format=oneline --no-merges featureA...master tools/my-tool | tail -r | cut -d " " -f 1)

Upvotes: 36

VonC
VonC

Reputation: 1329112

Note:

  • git cherry-pick is about applying a full commit (or commits) to another branch. There is no notion of "path".
  • git checkout is about updating the working tree (and HEAD if no path is specified, effectively switching branches)

    git checkout [-p|--patch] [<tree-ish>] [--] <pathspec>...
    

When <paths> or --patch are given, git checkout does not switch branches.
It updates the named paths in the working tree from the index file or from a named <tree-ish> (most often a commit). The <tree-ish> argument can be used to specify a specific tree-ish (i.e. commit, tag or tree) to update the index for the given paths before updating the working tree.

Your git checkout dev -- tools/my-tool updates a specific path, but it isn't a "merge" or a "git cherry-pick".

Upvotes: 19

Related Questions