0

I want:

  • to work on develop and make all my changes there (or in other feature branches that are merged into develop)
  • to merge develop into master when I want to release (squashing all commits since the last time I did that)

But I'm getting merge conflicts when I merge develop into master.

Here's a small example of my workflow that reproduces what is a problem to me:

  1. Create empty repo, clone it

    bicou@dikkenek:/tmp$ mkdir repo.git
    bicou@dikkenek:/tmp$ cd repo.git/
    bicou@dikkenek:/tmp/repo.git$ git init --bare
    Initialized empty Git repository in /tmp/repo.git/
    bicou@dikkenek:/tmp/repo.git$ cd /tmp
    bicou@dikkenek:/tmp$ git clone repo.git repo
    Cloning into 'repo'...
    warning: You appear to have cloned an empty repository.
    done.
    bicou@dikkenek:/tmp$ cd repo
    
  2. Now make some commits to master:

    bicou@dikkenek:/tmp/repo$ echo 'blah blah blah' > readme
    bicou@dikkenek:/tmp/repo$ echo 'version: 1' >manifest
    bicou@dikkenek:/tmp/repo$ git add manifest readme 
    bicou@dikkenek:/tmp/repo$ git commit -m "initial commit"
    [master (root-commit) 5c7f827] initial commit
     2 files changed, 2 insertions(+)
     create mode 100644 manifest
     create mode 100644 readme
    
  3. Now branch off develop

    bicou@dikkenek:/tmp/repo$ git checkout -b develop
    Switched to a new branch 'develop'
    bicou@dikkenek:/tmp/repo$ echo "testing" >work
    bicou@dikkenek:/tmp/repo$ git add work
    bicou@dikkenek:/tmp/repo$ git commit -m "working on work"
    [develop f22b31b] working on work
     1 file changed, 1 insertion(+)
     create mode 100644 work
    bicou@dikkenek:/tmp/repo$ echo "more work" >>work 
    bicou@dikkenek:/tmp/repo$ git commit -am "still work"
    [develop 6a8981f] still work
     1 file changed, 1 insertion(+)
    
  4. Here is a modification of a file that's already tracked on master:

    bicou@dikkenek:/tmp/repo$ sed -i 's/version: 1/version: 2/' manifest 
    bicou@dikkenek:/tmp/repo$ git commit -am "version bump"
    [develop de2866b] version bump
     1 file changed, 1 insertion(+), 1 deletion(-)
    
  5. Back to master, merge all commits in develop and squash them:

    bicou@dikkenek:/tmp/repo$ git checkout master
    Switched to branch 'master'
    bicou@dikkenek:/tmp/repo$ git merge develop --squash 
    Updating 5c7f827..de2866b
    Fast-forward
    Squash commit -- not updating HEAD
     manifest | 2 +-
     work     | 2 ++
     2 files changed, 3 insertions(+), 1 deletion(-)
     create mode 100644 work
    bicou@dikkenek:/tmp/repo$ git commit 
    [master 04528f9] Squashed commit of the following:     version bump     still work     working on work
     2 files changed, 3 insertions(+), 1 deletion(-)
     create mode 100644 work
    
  6. Now back to work:

    bicou@dikkenek:/tmp/repo$ git checkout develop 
    Switched to branch 'develop'
    bicou@dikkenek:/tmp/repo$ echo "still working" >>work 
    bicou@dikkenek:/tmp/repo$ git commit -am "continued work"
    [develop 81e3d08] continued work
     1 file changed, 1 insertion(+)
    
  7. Then the change that in my opinion should be fine but will prove to break things:

    bicou@dikkenek:/tmp/repo$ sed -i 's/version: 2/version: 3/' manifest 
    bicou@dikkenek:/tmp/repo$ git commit -am "version bump"
    [develop 83b77fb] version bump
     1 file changed, 1 insertion(+), 1 deletion(-)
    
  8. Back to master, expecting a dumb merge that didn't happen:

    bicou@dikkenek:/tmp/repo$ git checkout master 
    Switched to branch 'master'
    bicou@dikkenek:/tmp/repo$ git merge develop --squash 
    Auto-merging work
    CONFLICT (add/add): Merge conflict in work
    Auto-merging manifest
    CONFLICT (content): Merge conflict in manifest
    Squash commit -- not updating HEAD
    Automatic merge failed; fix conflicts and then commit the result.
    
  9. Here's one conflict:

    bicou@dikkenek:/tmp/repo$ cat manifest 
    <<<<<<< HEAD
    version: 2
    =======
    version: 3
    >>>>>>> develop
    

So my questions/reflections:

  1. Why didn't it fast forward?
  2. I know I can force the merge with git merge develop --squash -s recursive -Xtheirs, but do I need to do that each time I will merge develop into master?
  3. Is my workflow wrong?
  4. After merging develop into master, should I merge back master into develop? Isn't that an infinite loop?
  5. Why did the merge in step 5 worked when the one in step 8 didn't? It's just a change of 1 -> 2 (OK) and then 2 -> 3 (KO). Should be fine for me!
  6. Is there any merge strategy or any other option that may get me to what I want?

Bonus question:
when squashing, git is nice enough to compile all the commit messages before committing the squash. But that contains all the commit messages since the branches forked (e.g. step 3 above).
How to get only the commit messages since the last time I merged develop into master? (e.g. step 5 above)

Note: merging using a temporary branch does what I want in terms of merging without conflicts, but it doesn't in the sense where I don't have all the commit messages squashed into one.

Benoit Duffez
  • 9,889
  • 11
  • 69
  • 114
  • At step 1? I don't know actually, I usually have the repo stored elsewhere and cloned over SSH, so I reproduced that. But that's not the point. – Benoit Duffez Jun 26 '17 at 23:08
  • 2
    [This may not seem like a duplicate](https://stackoverflow.com/q/39096500/1256452), and my answer is long, but you should read the entire answer and then consider whether you want to continue to use squash, which is not a merge. If you *do* want to keep using squash, you probably want to abandon each branch once it is squashed. (Toss the old one and start a new one, perhaps with the same name, even.) – torek Jun 26 '17 at 23:43
  • I had already read it. But the end of your comment hints at the problem here: I can't merge develop into master (squashing the commits) several times in a row without cleanly rebranching develop from master each time. (e.g toss the old one and start a new one, with possibly the same name). Which tells me that something is wrong, which is probably my workflow. :( – Benoit Duffez Jun 26 '17 at 23:45
  • 1
    The difference is that with a proper merge commit git has recorded that you have already merged in these changes. If you're doing a rebase/squash instead you apply the same changes again, the difference now is that you already have some of these changes in master, thus you get a conflict. In short, if you're not going to abandon the branch when you rebase/squash it, don't rebase/squash it. – Lasse V. Karlsen Jun 27 '17 at 06:59
  • Possible duplicate of [git \`merge --squash\` does not add "Merge" header to commit](https://stackoverflow.com/questions/39096500/git-merge-squash-does-not-add-merge-header-to-commit) – matt Jun 27 '17 at 07:13
  • Thanks all for all the information and links. My guess is that torek and Lasse nailed it: don't squash and reuse the branch. I have to question my workflow and find something that's clean in git and fits my needs. – Benoit Duffez Jun 27 '17 at 07:17
  • Thanks guys, I'm really grateful you took the time to read my question, parse it and help me out. Much appreciated! – Benoit Duffez Jun 27 '17 at 08:51

1 Answers1

0

As torek and Lasse pointed out in the comments, I made some wrong assumptions:

  • squashing the commits when merging doesn't create a merge commit. That was the main problem I guess
  • when squashing the commits during a merge, the expected behavior after that is to dump the branch that provided the commits
  • when working with two branches in parallel an merging one into the other on a regular basis, one shall create commit merges

All the information linked in the comments above helped a lot, but this answer particularly fits my needs.

What I wanted was:

  • work in parallel
  • merge, creating a merge commit (hence no squash)
  • have all the commit messages in the merge commit (instead of the dumb Merge branch xxx): this was solved using the prepare-commit-message hook

Here's the result of a dummy repo with exactly what I wanted for the workflow:

bicou@dikkenek:/tmp/repo$ git log --decorate --oneline --graph
*   182fb11 (HEAD, master) Merge details:
|\  
| * 1cdba95 (develop) version bump v4
| * d12d9ce work on v4 another feature
| * 70bb9f6 work on v4
* |   ee715de Merge details:
|\ \  
| |/  
| * 965356c work again on v3
| * 3f12856 work on dev v3
* |   37649d4 Merge branch 'develop'
|\ \  
| |/  
| * 0ef71dd work work on v2
| * 84b5069 continued work on v2
* |   5522eae Merge branch 'develop'
|\ \  
| |/  
| * b3e545e work again on develop
| * 0960273 work on develop 1
|/  
* 6515de5 initial commit

Each commit in master:

  • is a merge commit
  • the commit message is the list of the commit messages in develop since the last merge, and I can customize it in vim when running git commit.

(the Merge branch 'develop' commits were created before I used the hook, and the Merge details commits were created with the hook using the simple git m develop + git commit which is awesome)

If torek or Lasse want to post their own answer and get credit from it, they definitely should!

Benoit Duffez
  • 9,889
  • 11
  • 69
  • 114