4

Edit: beware, this is a confused question. It starts with some wrong assumptions and figures that out, one edit after the other.


I got two branches (master and feature) that diverged.

master  - C1 - C3
            \
feature      C2 - C4 - C5

C2 and C4 are just dirty commits with temporary code, that I don't want to have into the final merge/rebase of the two branches.

I usually perform a:

git checkout master
git cherry-pick C5 (last commit from the feature branch)

But this time I have C3 that conflicts and I cannot pick the commit.

What I tried is rebasing C3 into the feature branch, so to not have conflicts when cherry-picking.

git checkout feature
git rebase master

Now I got this

master  - C1 - C3
                \
feature          C2 - C4 - C5

Seems fine, but if I try to cherry-pick again onto master I still get conflicts (on some empty space I removed from some files).
A posteriori: can't workaround git conflicts. Rebase does no magic on there.

Git is telling me to resolve the conflicts, to add the files, and commit. I can solve the conflicts manually, but don't want to commit them just as a conflict resolution.

I want to avoid commits in my history about something that is not related directly to implementations. I would not even know what to write as commit message.

  • Why I still get conflicts after the rebase? (A posteriori: because rebase just moves copies of commits, has no power to resolve conflicts)
  • And how can I get C5 to be merged/cherry-picked to master without additional commits? (A posteriori: by solving the conflict in a previous commit)

I usually prefer to cherry-pick cause I can avoid the 'useless' merge commit and have just commits regarding code changes. Then after that I delete the branch, after a while I'm sure I don't need it anymore.
(A posteriori: practically, a rebase workflow)

[[ EDIT ]]

The wierd behaviour is that C5 and C3 conflict on files that are not changed on C3.

Infact, all the detected conflicts are just empty on the master branch

<<<<<<< HEAD
=======
[ added code ..................... ]
[ .......... from ................ ]
[ ............... 'feature' branch ]
>>>>>>> 581g52d... "Commit message from 'feature' C5 "

What I need to 'solve' is just deleting the conflict tags from the conflicting files.

  • I don't get the reasons of the conflicts (A posteriori: the highlighted lines of code that were added in C5 581g52d are removed in C3; git cannot decide which change has priority and was intended to stay)
  • I would like to solve it manually and then merge/cherry-pick without having to create a new additional (merge) commits
    • cause the commit will just solve some conflicts with a branch that in the future will be deleted (A posteriori: this is not bad, as it gives a hint of the workflow; although in the rebase workflow I follow usually the sequence of commit appears like it was a single flow of work with no branches used)
    • when deleted the branch, that commit will have no sense/position in the repository history (A posteriori: see previous point)

[[ EDIT 2 ]]

Moreover, if I try to git cherry-pick master/C3 to feature I get:

no changes added to commit (use "git add" and/or "git commit -a") The previous cherry-pick is now empty, possibly due to conflict resolution.

I don't get why I have conflicts in the opposite direction (from feature to master)

[[ EDIT 3 - Retrying from the beginning! ]]

Here is what I tried too.

  • Made two copies of the master branch, with C3 as last commit, named: master_copy and repeat_feature

    • git checkout master / git branch master_copy / git branch repeat_feature
  • Cherry-picked every commit from the feature branch, until C5, into repeat_feature

    • git checkout repeat_feature / git cherry-pick C2^..C5 (from feature)
    • (I got NO CONFLICTS)
  • Tried to cherry-pick C5 into master_copy, from repeat_feature

    • remember that repeat_feature was started from C3 (so, if there were some conflict, those should be raised while cherry-picking from C2 to C5)
    • git checkout master_copy / git cherry-pick repeat_feature_C5

I still got the same conflicts!
(A posteriori: can't workaround it, don't avoid conflict resolution)

Even if I was starting from the same C3 commit (when cloned the branch to repeat_feature branch) and trying to cherry-pick to the same C3 commit (into master_copy)!

I totally don't get the point of what's happening and why I get these empty conflicts that prevent me from moving my feature to the master branch.

An expert's suggestion is needed here.

Kamafeather
  • 8,663
  • 14
  • 69
  • 99
  • 1
    You *will* get a merge conflict if you try to change code where the diff isn't clear. I'm not sure if that can specifically be avoided while cherry-picking as such. It's not about cherry-picking, it's about the code change. – gravetii Aug 18 '14 at 16:02
  • Yes it is a diff problem. What I don't get is that C5 and C3 conflict on a file that C3 is not changing (infact, all the detected conflicts are just empty on the master branch, and what I need to 'solve' is just deleting the conflict tags from the conflicting files). I'll update the question with this info. – Kamafeather Aug 18 '14 at 16:14
  • What I need anyway is just to solve the conflict but avoiding to commit these changes. I wonder if there is a way. – Kamafeather Aug 18 '14 at 16:15
  • 1
    No, you cannot resolve the conflicts without committing them, unless what you want to do is a force push, which isn't really a good idea. – gravetii Aug 18 '14 at 16:16
  • What about solve the conflicts into the *feature* branch (that anyway will be deleted in the future) and then cherry-pick the solving commit into the *master* branch, changing the commit message? I want to just finish as I just commited once on the *master* branch for adding the new feature. – Kamafeather Aug 18 '14 at 16:25
  • I also added details in the question. – Kamafeather Aug 18 '14 at 16:26
  • One more thing I don't understand is that if I try to do it, cherry-picking *master/C3* to *feature* it returns me that *"no changes added to commit (use "git add" and/or "git commit -a") The previous cherry-pick is now empty, possibly due to conflict resolution."*, without any conflict.. – Kamafeather Aug 18 '14 at 16:30
  • (1) do you have some sort of cr/lf conversion turned on? (What's in `core.eol`, `core.safecrlf`, `core.autocrlf`, and/or `.gitattributes` file(s)?) (2) `git cherry-pick` just applies a diff; what does `git show feature` show for commit C5, in the conflicting area? (3) you may want to set `merge.conflictstyle` to `diff3`, although that won't actually fix anything here, it may help you see what's going on. – torek Aug 18 '14 at 18:26
  • I don't have any of those settings specified, and no `.gitattributes` set. I use always the same editor and didn't change anything about CR/LF(s). `git show feature` shows me the *diff* relative to the previous commit (C4). Do I have to specify some additional thing to `git show`? – Kamafeather Aug 18 '14 at 18:45
  • What I meant was: if you include the relevant output from `git show` *and* the lines to which this diff is supposed to be applied by the `git cherry-pick` operation, we might be able to see why there is a conflict. (I tried a simple experiment and had no conflict, myself, so obviously was not constructing the problem correctly.) – torek Aug 18 '14 at 22:44
  • Ok, I guess everything is caused from my misunderstanding of `git cherry-pick`. I was erroneusly thinking that cherry-pick was applying a specific commit but also all the other changes it was inheriting from parent commits (so I was expecting that applying *C5* to *master* would have applyed also *C2* and *C4*). – Kamafeather Aug 19 '14 at 09:08
  • But `cherry-pick` doesn't work like that and is just applying the specific commit changes! Probably this is the root cause of my conflicts (even if they these conflicts are on all the files of the 'cherry-picked commit', even if these files have not been touched into the destination commit). – Kamafeather Aug 19 '14 at 09:17
  • Anyway I changed approach: I made a copy of *feature* branch, I 'compacted' all the branch commits into a single one (`git reset ` + `git add .` + `git commit`), and then I `cherry-pick` it into the master branch, applying al my changes with just one commit (as I wanted to do with *C5*, misinterpreting `git cherry-pick`). This way I get no conflicts at all (as I would expect to happen). Unfortunately I still cannot explain the logic causing the conflicts when cherry-picking just one commit (partial change from the *feature*). Don't know if you have some idea about that.. – Kamafeather Aug 19 '14 at 09:23

2 Answers2

2

I finished to change approach:

  • I made a copy of _feature_branch_ (git checkout feature_branch/git checkout -b copy_feature_branch);
  • I 'compacted' all the branch commits into a single one
    • first: I come back to the parent commit of the branch: git reset <branch_parent_commit>
    • second: I re-add all the changes with git add ., and then commit with git commit
    • finally I cherry-picked this commit into the master branch, applying al my changes from the feature_branch with just one commit (as I wanted to do with C5, misinterpreting git cherry-pick). git checkout master/git cherry-pick <last-commit-of-copy_feature_branch>)

This way I get no conflicts at all (as I would expect to happen) and I obtain to have just one commit that introduces all the changes (or anyway a 'packet' of changes) from the feature_branch. I made a copy of my feature branch so I can have for a while the full sequence of WIP commits, that could be useful to have for a while (for testing, apply fixes, see the history of the changes for the specific feature). Instead of deleting the branch I usually rename it with git branch -m <current_name> FINISHED_<current_name> and keep it until I'm not sure I want to delete it.

It is not a wonderful workflow but actually it's working for me, waiting to find a better way to accomplish my needs.

Unfortunately I still cannot explain the specific logic causing the conflicts when cherry-picking just one last commit (partial change from the feature). I know that I was doing wrong, but don't know how that conflict on those specific file-parts was coming out.

Kamafeather
  • 8,663
  • 14
  • 69
  • 99
  • **Beware:** the `git reset` (used to get all changes together, in the working/stage area) works only because of the [default reset behaviour](https://git-scm.com/docs/git-reset#Documentation/git-reset.txt-emgitresetemltmodegtltcommitgt). The priority is given by Git to maintaining the "current" status of work (previous to the reset); otherwise some changes/conflicts might get lost in the process if using other `--mode`s. – Kamafeather Jul 26 '22 at 10:52
1

I want to avoid commits in my history about something that is not related directly to implementations.

As I read a plenty of answers on this topic on SO, I could say that most people advise against using unneccessary git cherry-pick.

Yes, cherry-pick is not for merging something, that've been developed trough a bunch of commits. It's for applying small changes from one branch to another for codelines that both branches have not changed in their other commits.

The main possiibility is to merge feature C5 state to master while avoiding some dirty C2 and C4 is to use squashing.

1. Using merge:

git checkout master
git merge --squash feature

2. Using rebase:

This could be done with interactive rebase:

git checkout feature
git rebase -i master

Then, you should change pick to squash for all commits besides one.

Also, start all of your temporary commit messages with squash! or fixup! word. Then you will be able to use autosquash (all temp commits will appear with this keyword on the list during rebase)

git checkout feature
HASH=`git merge-base --fork-point master`
git rebase -i $HASH --autosquash
Community
  • 1
  • 1
John_West
  • 2,239
  • 4
  • 24
  • 44