Reputation: 2684
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:
featureA
off of master
/tools/my-tool
from branch dev
into featureA
Upvotes: 38
Views: 41321
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
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
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
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
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
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