4 ms·
I have never understood cherry-pick for this very reason. This helps, but I'm still confused. > The git cherry-pick <oid> command creates a new commit with an
by recursive 6y ago
I have never understood cherry-pick for this very reason. This helps, but I'm still confused.
> The git cherry-pick <oid> command creates a new commit with an identical diff to <oid> whose parent is the current commit.
How can two diffs ever be considered equivalent when they include a changed file that had different starting contents? Can they?
- stolee 6y agoIf I have a 100-line file and on 'main' it changes near the top, but in my 'topic' branch it changes near the bottom, then I can cherry-pick 'topic' onto 'main' and Git will resolve the diff correctly. The resulting diff or patch would only change in the line numbers for the context of the diff. This is of course a very simple example. You might hit a conflict in your "git cherry-pick" command which gives you an opportunity to resolve the unexpected diff issue in an appropriate way, which ends up with a different diff than before.
- recursive 6y agoI kind of intuitively get it, but that doesn't really seem well defined. I'm always a little bit spooked that `cherry-pick` will cleanly apply when it really shouldn't have. It's not clear to me under which circumstances it automatically resolves.
- tsimionescu 6y agoYou're right to be spooked about that, but you're wrong if you think only cherry-pick has this problem. In fact, all git commands can and sometimes will cleanly apply and subtly mess your files (git merge, git pull, git rebase, git apply, git stash apply etc). The definition of how changes are applied actually has nothing to do with git itself, and everything to do with the diff algorithm you choose (of course, you normally use a built-in one, but I believe you can customize it if you really want). In general, the default Git diff algorithm, like all text-based diff algorithms, can have problems with structured data, such as removing closed parens or significant white-space. Naturally, it can also be problematic if you have declarations that must be a unique in a file, but that can occur in different places. The Java or Go `package` statements are safe, since they must occur at the beginning of a file, so if they are different between the 2 files they are likely to be caught. But if two people have added a top-level function called `foo` , but they added it in different places in the file with different params, it's pretty likely that the diff algorithm will not see any conflict and will duplicate both lines. Cherry pick is in fact one of the places I would normally worry least about this, since it is usually done for limited sized commits. However, when merging a feature branch into master, the potential for errors goes up, and so does the work required to catch such errors during the review.
- recursive 6y agoThank you. In all my (extensive) commentary in this topic, I feel this is the first response that addresses the root of my confusion in a way I can understand. Sincerely, this is helpful.
- tsimionescu 6y agoGlad to hear that! Rarely have I actually felt that a comment I wrote actually made a difference.
- ninkendo 6y agoYou don’t even need to think about diff algorithms to see why a cherry-pick, merge, etc may not do what you want. If in my branch, I rename oldFunc to newFunc in file A, and change file B to replace the call to oldFunc with newFunc; and in your branch, you add a new call to oldFunc in file C... the code will break when we merge our branches. Our changes would both pass tests independently, but would break when we merge them. No file-level diff algorithm would detect a “conflict” here. Diff algorithms only help with saying “are two branches trying to edit the same lines of code”, but the answer to that question is never enough to tell you whether two changes logically will apply cleanly to one another.
- pmeunier 6y ago> If I have a 100-line file and on 'main' it changes near the top, but in my 'topic' branch it changes near the bottom, then I can cherry-pick 'topic' onto 'main' and Git will resolve the diff correctly. That is not true: sometimes Git will take the new lines from "topic" and merge them into the new lines from "main", see https://pijul.org/manual/why_pijul.html https://pijul.org/manual/why_pijul.html > You might hit a conflict in your "git cherry-pick" command which gives you an opportunity to resolve the unexpected diff issue in an appropriate way, which ends up with a different diff than before. Sometimes when you cherry-pick, you might not even hit a "true" conflict, but if you forgot to run "rerere", you might simply hit a previously solved conflict again.
- MaxBarraclough 6y agoYou're right that the commit produced by the cherry-pick operation won't be identical to the commit being cherry-picked. It's the diffs that are identical, not the final result. It's analogous to how the difference between 5 and 15 is equal to the difference between 105 and 115.
- recursive 6y agoThat doesn't help. The result of subtraction is defined to be a number. The result of a diff is... a nebulously defined concept that somehow describes the changes. It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded.
- MaxBarraclough 6y ago> The result of subtraction is defined to be a number. A diff shows the difference between two commits (i.e. snapshots). Perhaps a better math analogy: one point can be subtracted from another to give a vector. > It's not clearly (to me) defined which parts of the files are considered to part of the diff and which parts are to be excluded. You're right that it's not precisely defined in that way, but there's a good reason for this. If you move the top line of a file to the bottom, should the diff tool show you that one line was deleted and one new line was added (i.e. that one line having been moved), or should it show all the other lines in the file as having been deleted and re-added in a different place? Both are valid interpretations of the difference between the two snapshots, but of course a real-life diff tool will show the former, as that's what's helpful to the user.
- recursive 6y agoI'm glad that real-life diff tools work in ways that they deem to be useful. But they don't always produce the most sensible result. In fact different algorithms produce different diff visualizations for the same input. I'm just a little uncomfortable with a feature that uses diffs for purposes other than display for humans, since they don't seem to be consistently defined.
- vmchale 6y ago> How can two diffs ever be considered equivalent when they include a changed file that had different starting contents? Can they? In darcs, patches commute. It works nicely sometimes!
- aidos 6y agoI find it easiest to think in terms of diffs as patches. It’s just a bunch of search and update commands. Sure, there’s some hairiness around files moving or whatever, but for me, a cherry pick is just getting a patch file and applying it in the appropriate place. It doesn’t care about the file it’s being applied to, it just needs to find similar content in the file so it can apply itself.
- zokier 6y agoYeah, git cherry-pick is basically just git diff | git apply. And rebase is just cherry-picking many commits.
- aidos 6y agoExactly. And the other day I did exactly that with piping diff through apply so I had more control over conflicts I was hitting. Suspect all the years in svn just make it easier for me to think of it that way rather than some magical operation.