1

For example, consider the following directory:

one
two
three

And the directory has the following commit history and branches:

dev                           master
 |                              |
commit1 --> other commits --> commit-wanted

commit-wanted updates files two and three.

After checking out dev branch, I want the cherry-pick of commit-wanted to succeed only if other commits between commit1 and commit-wanted do not update two and three files.

Is it possible?

Jingguo Yao
  • 7,320
  • 6
  • 50
  • 63

2 Answers2

4

git cherry-pick does fail if there are merge conflicts (see example below), but if you want a more conservative check that fails even if the changes to the files can be merged you'll have to write one yourself.

Print a list of file names touched by a commit (See https://stackoverflow.com/a/424142/14516046):

git diff-tree --no-commit-id --name-only -r "$COMMIT"

Print a list of commits in a range (See https://stackoverflow.com/a/5953868/14516046):

git rev-list dev..master

Using these two commands you should be able to implement the check you want as a simple script. Writing the script is left as an exercise to the reader.

Example merge conflict:

$ git init
Initialized empty Git repository in /home/user/tmp/.git/
$ printf '1\n2\n' > foo.txt
$ git add .
$ git commit -m 'Add foo.txt'
[master (root-commit) f41e149] Add foo.txt
 1 file changed, 2 insertions(+)
 create mode 100644 foo.txt
$ printf '1\n2\n3\n' > foo.txt
$ git add .
$ git commit -m 'Append a line'
[master ce20740] Append a line
 1 file changed, 1 insertion(+)
$ printf '1\n2\n3\n4\n' > foo.txt
$ git add .
$ git commit -m 'Append another line'
[master 9738459] Append another line
 1 file changed, 1 insertion(+)
$ git checkout -b dev HEAD^^
Switched to a new branch 'dev'
$ git cherry-pick master || printf 'git cherry-pick returned nonzero status\n'
Auto-merging foo.txt
CONFLICT (content): Merge conflict in foo.txt
error: could not apply 9738459... Append another line
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'
git cherry-pick returned nonzero status
$ git cherry-pick --abort
Jingguo Yao
  • 7,320
  • 6
  • 50
  • 63
1

Actually you do not need git diff-tree, git rev-list already have what you need.

git rev-list dev..master^ -- two three

After -- you can specify files changed by target commits. So, this command returns all the commits between dev (excluded) and master (excluded) that modified two OR three.

Eventually, You can solve that by running a simple command from dev:

test -z $(git rev-list dev..master^ -- two three) && git cherry-pick master
Marco Luzzara
  • 5,540
  • 3
  • 16
  • 42