Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git merge with --squash while keeping log of every commit

Initial scenario:

A (master)
 \
 B - C  - D (development)

What I want after merge --squash:

A     -     E (master/development)
 \         /
 B - C - D 

On branch master, git log would be

commit E
    Squashed commit of the following:
    commit D
    commit C
    commit B
commit A

Keep developing on branch development:

A     -     E (master)
 \         / \         
 B - C - D    F - G - H (development)

Merge with squash again:

A     -     E     -     I(master/development)
 \         / \         /
 B - C - D    F - G - H

On branch master, git log would be

commit I
    Squashed commit of the following:
    commit H
    commit G
    commit F
commit E
    Squashed commit of the following:
    commit D
    commit C
    commit B
commit A

On branch development, git log would be

Commit I
Commit H
Commit G
Commit F
Commit E
Commit D
Commit C
Commit B
Commit A

I would like to merge with commits squashed on master while keeping every commit on development.

I have no idea how to implement that. My problem is that I don't know how to make D point to E in the first merge, and I will include B,C,D,E,F,G,H instead of F,G,H only.

like image 328
Zizheng Wu Avatar asked Oct 17 '15 20:10

Zizheng Wu


1 Answers

You can't get the log result you want with the structure you showed (git log --merges master will sort of do it). The structure that will give you the log you want defeats the point. And, in the end, this is a self-defeating way to work with Git.


The desire is to be able to run git log master and only see the squashed commits. This won't work. Git doesn't know that some commits are intended for master and some are for development. Let's look at the proposed structure.

A     -     E     -     I [master] [development]
 \         / \         /
 B - C - D    F - G - H

At this point, master and development point to the same commit. As far as Git history is concerned they are identical. A branch is nothing more than a label pointing at a commit. Commits don't remember what branch they were committed to. git log master and git log development will produce the same logs showing all commits from A to I. The E and I squashed commit logs will be redundant.

You can get what you want with git log --merges master (or development) to show only merge commits, but that will show any merge commits, even those done as part of development. So it doesn't really work.

This whole idea is unnecessarily complicated, read on.


To get the log result you want, you'd have break the relationship between the two branches like this.

A     -     E     -     I [master]
 \                   
 B - C - D - F - G - H [development]

Which you can make work somehow, but there's no point. git log master contains all the same log messages so it will be just as long as git log development, but they'll be smashed together. You can't use git log master to do code archaeology (ie. "why was this line written this way") because the changes are all smashed together into one diff making it harder to associate a line of change with a particular commit message. Since the history of master and development is disassociated, there's no way to ensure everything in development made it into master, or vice versa (for example, hot fixes to master).

git log master provides less information than git log development and it's harder to understand. master has no association with development and loses all the benefits of keeping the merge history. There's no point in maintaining this complicated setup.


Instead, use git merge --no-ff to merge feature branches (not one continuous "development" branch) and keep the branch history for easy archaeology.

              G - J [feature/tacos]
             /
A     -     E     -     K [master]
 \         / \         /
 B - C - D    F - H - I

E and K are normal merge commits produce by git merge --no-ff. There is no continuous development branch, that is handled by feature branches. Feature branches are single use and deleted once merged. The information about feature branches is preserved in the merge commit and git merge --no-ff guarantees the branch structure is preserved. feature/tacos is a feature branch to work on tacos that has not yet been merged.

git log --graph --decorate master will show the complete history of master, with the merge commits showing when features ended, plus lines illustrating the branch history. A GUI Git history tool such as GitX is another way to read the history as a graph.

In the end, Git history is a graph. If you learn how to work with that graph life with Git will be much easier. If you try to make Git history linear, like a big stack of pancakes, you're defeating the point of Git and creating extra work for yourself and everyone else.

like image 200
Schwern Avatar answered Oct 04 '22 16:10

Schwern