1031

I'm working with a git repository that needs a commit from another git repository that knows nothing of the first.

Typically I would cherry-pick using the HEAD@{x} in the reflog, but because this .git knows nothing of this reflog entry (different physical directory), how can I cherry-pick this, or can I?

I'm using git-svn. My first branch is using git-svn of the trunk of a Subversion repo, and the next branch is using git-svn on a Subversion branch.

halfer
  • 19,824
  • 17
  • 99
  • 186
gitcoder182
  • 10,321
  • 3
  • 15
  • 4

14 Answers14

1064

The answer, as given, is to use format-patch but since the question was how to cherry-pick from another folder, here is a piece of code to do just that:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

Explanation from Cong Ma comment Aug 28 '14

git format-patch command creates a patch from some_other_repo's commit specified by its SHA (-1 for one single commit alone). This patch is piped to git am, which applies the patch locally (-3 means trying the three-way merge if the patch fails to apply cleanly).

Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Robert Wahler
  • 12,350
  • 3
  • 19
  • 11
  • @BenLee thanks for the Rep! I appreciate it. I use my method rather than the accepted answer for related forks when there is a mix of licenses involved. I control keeping the code clean. – Robert Wahler Jul 24 '13 at 17:56
  • 37
    This is spot on, but it would be great if anyone could expand on this - a breakdown of exactly what's going on (especially with those flags) would be incredibly useful. – Nick F May 07 '14 at 17:56
  • 66
    @NickF, the `git format-patch` command creates a patch from `some_other_repo`'s commit specified by its SHA (`-1` for one single commit alone). This patch is piped to `git am`, which applies the patch locally (`-3` means trying the three-way merge if the patch fails to apply cleanly). Hope that explains. – Cong Ma Aug 28 '14 at 09:37
  • 3
    error: patch failed: somefile.cs:85 error: somefile.cs: patch does not apply Did you hand edit your patch? It does not apply to blobs recorded in its index. Cannot fall back to three-way merge. Patch failed at 0001 Added GUI parts. The copy of the patch that failed is found in: /.git/rebase-apply/patch When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". – Tom Nov 06 '15 at 18:36
  • Can a stash be specified in place of the "commit SHA"? In most git commands they are interchangeable, just want to confirm if that is true here as well. Especially since stashes are slightly different in that they have 2 parents (like merge commits). – Vicky Chijwani Jan 11 '16 at 13:47
  • 15
    @Tom try using `--ignore-whitespace`. Full command: `git --git-dir=..//.git format-patch -k -1 --stdout | git am -3 -k --ignore-whitespace` – Jake Graham Arnold Feb 03 '16 at 10:49
  • 1
    For me, `git show` works as an alternative to `git format-patch`. And `git apply` can be used instead of `git am`. Not sure why one would use one or the other. – donquixote Jun 15 '16 at 03:18
  • 2
    Oh I see. git am actually commits the patch, with the commit message. – donquixote Jun 15 '16 at 03:31
  • 1
    It seems that `git format-patch` accepts a `--relative=..` parameter, even though this is not documented in `man git format-patch`. This allows to create the patches from a subdirectory. – donquixote Jun 15 '16 at 03:38
  • 3
    The `-1` is not required when creating a patch from a series of commits like `git format-patch [..] aaa..bbb`. Here the `--relative=..` acts like a filter, so only the commits from this subdirectory are included in the patch. Similar to what one would otherwise do with `filter-branch`. – donquixote Jun 15 '16 at 03:41
  • 2
    There's been a lot of upvotes for this and comments saying this is the better answer. It worked for me, but I would like to know _why_ this is the better answer? What are it's advantages over the 'git remote' & cherry-pick approach? – BoomShadow Jul 09 '16 at 18:01
  • @RobertWahler Any way to do this straight from another repo's commit on GitHub via curl piping? I've played with some different flavors of your command and haven't figured it out yet! – Aegix Jul 22 '16 at 19:21
  • 10
    @BoomShadow Because it's way simpler. Adding the remote and fetching brings in all of the other repo's changes. This command line is a one-time action. – Jonathon Reinhart Jan 04 '17 at 15:05
  • The `-k` isn't necessary for this, and adds complexity to the answer. – Kelly Elton Apr 27 '18 at 18:13
  • Can this git-dir's physical location be on another server? I mean, is there a way to specify something like: `--git-dir=other_server:/path/to/repo/.git` ? – rodee Jul 02 '18 at 15:30
  • 2
    This only worked for me using `--ignore-whitespace` and it does not work on Windows at all. – Giovanni Bassi Jul 11 '18 at 16:31
  • 2
    This is not a generalized way. In my case, it turned out to be a 3-way merger. Refer this: https://stackoverflow.com/questions/16572024/get-error-message-fatal-sha1-information-is-lacking-or-useless-when-apply-a – Chirag Arora Aug 18 '19 at 10:26
  • Although this answer is simpler in theory, if you are cherry-picking one commit, you might find yourself wanting to cherry-pick more commits in the future. Adding another repo as a remote will make this a little bit easier in the future. – Devin Rhode Jul 12 '21 at 02:27
  • Thank you for saving me from committing that useful local fix that has no place in the repo, yet required from another repo. Just cherry picked it from the on disk repo, --ignore-whitespace is needed btw. Maybe add it to the answer? – GrumpyRodriguez Aug 20 '21 at 09:59
  • 1
    When `fatal: sha1 information is lacking or useless` error occurs, add `--reject` to last command (git am) and search repo for *.rej files. Those are unaplied changes. Apply them manually and use `git add` + `git am --continue` to proceed. See https://programmerall.com/article/9881500742/ – Lubo Nov 30 '21 at 14:17
934

You'll need to add the other repository as a remote, then fetch its changes. From there you see the commit and you can cherry-pick it.

Like that:

git remote add other https://example.link/repository.git
git fetch other

Now you have all the information to simply do git cherry-pick.

When done, you may want to remove the remote again, if you don't need it any more, with

git remote remove other

More info about working with remotes here: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
CharlesB
  • 86,532
  • 28
  • 194
  • 218
  • 1
    What if I'm using git-svn? my first branch is using git-svn of the trunk and the next is using the git-svn on a branch (thanks for the quick reply) – gitcoder182 Feb 25 '11 at 16:54
  • @gitcoder182: not sure since I never used git-svn, but it should work. – CharlesB Feb 25 '11 at 16:56
  • 1
    when you first clone the Subversion repository make sure you clone the _entire_ repository, not just the trunk. Also make sure you use the `--stdlayout` option of git-svn if you're using the standard trunk/branches/tags layout in Subversion. Then the Subversion branch will be a mere remote git branch. – wilhelmtell Feb 25 '11 at 17:05
  • 1
    Is it really necessary to add it as a remote !? – rapadura Mar 28 '12 at 18:48
  • 49
    If you're using Github, you can pull the patch by appending .patch to the commit URL, and then applying it with `git am < d821j8djd2dj812.patch`. Outside of GH, similar concepts could be done as referenced in the alternative answer below. – radicand May 12 '12 at 19:29
  • 2
    @radicand which answer below is the "alternative" one? Please link to it. –  Jul 13 '13 at 21:52
  • 7
    Detailed steps to cherry pick from another repo: https://coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository – T. Kim Nguyen Jul 19 '16 at 13:29
  • 3
    You don't really need to add the remote. fetching is enough. And `..//` is a perfectly fine uri, if you have the repo on your disk already. – geon Feb 07 '18 at 14:44
  • Then we can merge the "other" ( remote branch ) to current using \n ```git merge /``` e.g ```git merge other/master``` this merges the remote master to current master – src3369 Nov 12 '21 at 19:08
  • `git remote rm other` instead of `git remote remove other` – Andremoniy Dec 24 '21 at 22:22
  • 1
    After removing the remote, you may need to prune stale tags. Use `git fetch --prune --prune-tags` to achieve this. See https://stackoverflow.com/a/54297675/1355754 for details about pruning tags. – Claudio Dec 25 '21 at 18:45
  • Hi, is there anything wrong with leaving 2 repos linked in this way on my local machine, if I occassionally want to cherry-pick something? I certainly don't want to affect anyone else's repo. Is pushing safe while having the 2nd remote added? Thanks. – Dave Ludwig Jul 25 '22 at 19:18
  • Doesn't work. Got: `error: sha1 information is lacking or useless` and `error: could not build fake ancestor ` – Michał Dobi Dobrzański Dec 16 '22 at 13:14
  • @radicand please add your comment as a proper answer! – xeruf Jan 03 '23 at 11:36
  • 1
    CAUTION: this is very dangerous when both repo's have **git tags**. git fetch will fetch all references to tags in the other remote and if you use `git push --tags` later you are at risk of accidentally pushing all the tags from the other remote – webketje Jun 06 '23 at 14:44
202

Here's an example of the remote-fetch-merge.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Then you can:

git cherry-pick <first_commit>..<last_commit>

or you could even merge the whole branch(only if you really need to merge everything)

git merge projectB/master
Michael Freidgeim
  • 26,542
  • 16
  • 152
  • 170
Brian
  • 2,535
  • 2
  • 18
  • 13
  • 73
    `git merge projectB/master` ***is very, very wrong***, because you're not applying the changes from a single commit (like a cherry-pick would), you're actually merging in ***all changes*** in `projectB/master` that aren't contained in your own `master` branch. –  Jul 13 '13 at 23:12
  • 6
    It was my assumption that this was the original poster's intent. Otherwise, yes, this is not the right option for them. – Brian Jul 17 '13 at 14:32
  • 8
    This works brilliantly when the two repositories are related. – Ronny Ager-Wick Nov 25 '14 at 10:47
  • 3
    I have created a copy from a git repository (just for "playing around" without breaking the original repo) and to keep it up-to-date with its source, the answer from Brian is exactly what I needed, so, Cupcake, I have to say, it's not "wrong", but another use case. But it is nice from you to point out the potential disaster :D – ferrari2k Oct 21 '15 at 09:19
  • 11
    **IMO this needs to be the accepted solution.** In addition, if you want to delete the remote after you're done cherry-picking from it, use `git remote rm projectB`. Also use `git tag -d tag-name` to remove any tags fetched from the remote repo. The remote commits will no longer show in your history, and pruning will remove them from storage eventually. – ADTC Jul 15 '16 at 07:44
  • 2
    I read that since git 2.9 you have to use the `--allow-unrelated-histories`. Using this option worked for me. – Lloyd Dewolf Jan 14 '17 at 06:24
  • Unorthodox: copy files over and re-commit. Do this only if you are sure no changes would be discarded by overwriting. – reim May 29 '18 at 22:53
  • -n means no-commit [docs](https://git-scm.com/docs/git-cherry-pick#Documentation/git-cherry-pick.txt---no-commit) and I thing very important to see the changes before making a commit or merge – canbax Jul 12 '19 at 11:32
192

You can do it, but it requires two steps. Here's how:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Replace <remote-git-url> with the url or path to the repository you want cherry-pick from.

Replace <branch> with the branch or tag name you want to cherry-pick from the remote repository.

You can replace FETCH_HEAD with a git SHA from the branch.

Updated: modified based on @pkalinow's feedback.

halfer
  • 19,824
  • 17
  • 99
  • 186
docwhat
  • 11,435
  • 6
  • 55
  • 54
  • 13
    It works with a branch name, but not with SHA. If you want to cherry-pick a commit denoted by its hash, use this instead: `git fetch && git cherry-pick `. – pkalinow Jan 17 '14 at 16:38
  • Thanks. This was just what I needed to insert a number of commits from one repository to another, which I created for this purpose. – wojciii Aug 19 '14 at 12:16
  • This was exactly what I needed with many custom implementation of our code for different clients (who each have their own repositories/forks) we needed a way to get specific commits into our base/trunk. THANKS! – RedSands Oct 15 '16 at 18:57
  • 2
    This should be the accepted answer for a one-shot cherry pick across repos. I use it all the time when picking between repos that are already local, the remote URL is then just a local filesystem path. – Amedee Van Gasse Apr 29 '19 at 11:51
  • If you are mostly familiar with cherry-pick this is probably the simplest. You don't need to add the full remote (although you can, if you are going to do this a lot). Just fetch the branch you need to get a local reference (can be from another local directory, or remote URL), and then cherry-pick the commits. – Sly Gryphon Dec 01 '21 at 21:29
  • This is the way – Chris Perry Jan 27 '22 at 23:57
  • Will this leave any remains that should be removed after the cherry-picking has taken place? And how to do that? – pt1 Apr 26 '22 at 08:15
  • To get the remote url, use this command `git config --get remote.origin.url ` – mohammed_ayaz Nov 23 '22 at 12:09
68

Here are the steps to add a remote, fetch branches, and cherry-pick a commit

# Cloning our fork
$ git clone git@github.com:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Source: https://coderwall.com/p/sgpksw

sbonami
  • 1,892
  • 17
  • 33
jaredwilli
  • 11,762
  • 6
  • 42
  • 41
18

See How to create and apply a patch with Git. (From the wording of your question, I assumed that this other repository is for an entirely different codebase. If it's a repository for the same code base, you should add it as a remote as suggested by @CharlesB. Even if it is for another code base, I guess you could still add it as a remote, but you might not want to get the entire branch into your repository...)

Aasmund Eldhuset
  • 37,289
  • 4
  • 68
  • 81
13

You can do it in one line as following. Hope you are in git repository which need the cherry-picked change and you have checked out to correct branch.

git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [branch URL] [Branch to cherry-pick from] && git cherry-pick [commit ID]

iconoclast
  • 21,213
  • 15
  • 102
  • 138
Don Srinath
  • 1,565
  • 1
  • 21
  • 32
5

Yes. Fetch the repository and then cherry-pick from the remote branch.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
4

If the other repo is present on the same machine, you could achieve a similar effect as cherry-pick by applying a patch and then committing the original message. Here is an example:

$ git apply <(git -C "$PATH_TO_OTHER_REPO" show "$COMMIT_HASH")
$ MSG="$(git -C "$PATH_TO_OTHER_REPO" log -n 1 --pretty=format:'%s' "$COMMIT_HASH")"
$ git commit -m "$MSG"

I don't have to do it very often so I'm fine with this workflow. However, it should be fairly easy to compose a customized Git command for this and have it nicer and more automated.

Notice that the command inside <(...) can be anything that generates a valid patch for Git: git show, git diff, using wget or curl to fetch raw diff contents from a remote such as Github (so you can skip cloning), cat from a file... That line, by itself, is extremely useful.

Victor Schröder
  • 6,738
  • 2
  • 42
  • 45
3

Here is one easy to type out from memory, inspired by the comment of @radicand. It is dependent on the capabilities of the forge, but Github, Gitlab and Gitea definitely support it.

You append .patch to the commit URL and apply it via git am:

curl --location URL.patch | git am

--location makes it follow redirects, which can happen when e.g. copying a patch from a pull request

xeruf
  • 2,602
  • 1
  • 25
  • 48
2

Assuming A is the repo you want to cherry-pick from, and B is the one you want to cherry-pick to, you can do this by adding </path/to/repo/A/>/.git/objects to </path/to/repo/B>/.git/objects/info/alternates. Create this alternates files if it does not exist.

This will make repo B access all git objects from repo A, and will make cherry-pick work for you.

pranavk
  • 1,774
  • 3
  • 17
  • 25
2

For the case, that the commit has to be "cherry-picked" for some localized validations. It could also be, for same repository checkout, but with local commits (i.e. not pushed yet to server).

E.g.

  • repo1 similar to repo2
  • repo1 has branch b1 - HEAD progressed by 2 commits (including commit_x) locally.
  • repo2 has branch bb1 - required to cherry-pick commit_x.

For this,

$ cd repo2

repo2 $ git fetch <path_to_repo1>

repo2 $ git cherry-pick <commit_x>

In the above case, the commit_x will now be identifiable and picked up (by the aid of fetch).

parasrish
  • 3,864
  • 26
  • 32
0

My situation was that I have a bare repo that the team pushes to, and a clone of that sitting right next to it. This set of lines in a Makefile work correctly for me:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

By keeping the master of the bare repo up to date, we are able to cherry-pick a proposed change published to the bare repo. We also have a (more complicated) way to cherry-pick multiple braches for consolidated review and testing.

If "knows nothing" means "can't be used as a remote", then this doesn't help, but this SO question came up as I was googling around to come up with this workflow so I thought I'd contribute back.

  • -n means no-commit according to git [docs](https://git-scm.com/docs/git-cherry-pick#Documentation/git-cherry-pick.txt---no-commit) and I thing very important to see the changes before making a commit – canbax Jul 12 '19 at 11:30
0

If you want to cherry-pick multiple commits for a given file until you reach a given commit, then use the following.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Diomidis Spinellis
  • 18,734
  • 5
  • 61
  • 83