Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git merge feature branch WITHOUT any commit history

say I create a new feature branch and make bunch of commits to the feature branch. My colleague also makes some commit so the master branch. How do I merge my change onto the master branch but master branch show one single commit? I have tried merging, all commits show up and it shows that I branch out. I've tried rebasing, which doesn't show me branching out but still shows all my commits. Thanks in advance for your help.

like image 989
Monir Avatar asked May 11 '18 16:05

Monir


People also ask

How do I merge a branch without committing?

With --no-commit perform the merge and stop just before creating a merge commit, to give the user a chance to inspect and further tweak the merge result before committing. Note that fast-forward updates do not create a merge commit and therefore there is no way to stop those merges with --no-commit.

Does git merge keep history?

Merging. When you run git merge , your HEAD branch will generate a new commit, preserving the ancestry of each commit history.

Do you commit before you merge?

That is why committing first is a good idea. If you don't do it in that order, it will either merge fine (if the files you changed were not involved in any other commits that are being merged), or nothing will happen, and git will tell you that your merge can't be done.


2 Answers

Use git merge --squash (which forces you to also use git commit afterward).

Description

In Git, the commits are the history. You can't add commits without adding history, because these are the same thing. What you want, then, is to make a single commit that is not a merge commit that produces the same result as if you had made an actual merge commit.

There are multiple ways to do this, but the simplest one is to use git merge --squash. This command performs what I call the "verb part", to merge—to perform the action of merging—but instead of making a merge commit, which is the adjective or noun part of a typical git merge, it makes an ordinary, non-merge commit.

More precisely, it skips the final commit, forcing you to do it yourself, using git commit. The final commit, which you must make yourself like this, is an ordinary non-merge commit. If we draw the commits the way I like to, we start with this:

...--o--o--o   <-- mainline
      \
       o--o--o   <-- yourbranch

If you make a normal everyday merge using git checkout mainline; git merge yourbranch, the result is:

...--o--o--o---M   <-- mainline
      \       /
       o--o--o   <-- yourbranch

which is why your three commits are now added to the main-line branch: commit M, the new merge, has two parents, one of which is the original main-line and the other being your own branch. (Your three commits are now on both branches.)

If we use git merge --squash, however, we get this instead:

...--o--o--o---S   <-- mainline
      \
       o--o--o   <-- yourbranch

The contents associated with new commit S are exactly the same as the contents you would get by making commit M, but new commit S has only a single parent, so it does not associate your three commits into the main-line branch. You are now free to delete your branch in the future. When you do this, your three commits become impossible to find, and relatively soon, Git actually removes them entirely.1

Note that your branch does not go away on its own. The name yourbranch here keeps your original three commits alive. However, if you do more work on your branch, that's not very useful: once you've squash-merged (and committed), you should generally consider your branch "dead", and remove it once your squash-merge-commit S is reasonably solid. You might want to retain it for a while, though, in case S turns out to be bad and you or your group choose to revert S: in this case, you can fix up your own branch, and then re-do the git merge --squash later, using the updated version of yourbranch.


1Normally, Git tries hard to make sure that apparently-deleted commits stick around for at least a month or so. However, if you delete the branch name itself, the branch's reflog, which is one of the things that keeps the commits around, goes away as well. You now rely on your HEAD reflog. If you had the commits checked out in this repository, that will also keep the commits around for a month or so, but if not, it won't.

like image 198
torek Avatar answered Sep 22 '22 14:09

torek


How do I merge my change onto the master branch but master branch show one single commit?

This is somewhat ambiguous.

A normal merge does add a single new commit, but that new commits incorporates all the commits from the "other" branch into "this" branch's history - they all become "reachable" from this branch - so the default output of commands like git log shows all of those commits, as you've observed.

If the only requirement is to see the history without seeing the individual commits from the "other" branch, the simplest solution is to say

git log --first-parent

This allows you to condense the view of history without actually discarding any information. It can be useful if there might be a case down the road where you want the more fine-grained history of how the branch evolved - such as tracking down a bug. It also makes sure that if you do more work on the "other" branch, you're still able to merge those additional changes without a lot of unnecessary hassle.

In particular, the information that's retained could be particularly important if the "other" branch has been shared with other developers - which is the most common assumption if you've ever pushed the "other" branch.

But sometimes the individual commits are entirely useless from a historical standpoint, and the intent is to discard them entirely (along with the branch that comprises them). For example, maybe you commit regularly, no matter what state your code is in, inserting and removing debugging code as you go, storing states that don't build and pass tests, etc. There are reasons such a workflow might be used, and in that case, a squash merge (or an interactive rebase in which you squash individual commits) can be desirable to produce a "clean" history.

You can try to "have your cake and eat it to", but using a --squash merge to create a simplified history while still keeping the original branch around for a fine-grained history. But git will in that case lose track of the relationship between the histories, and this can easily lead to far more trouble than it's worth.

In the end it depends on the workflow you (and your team, if applicable) settle on. Just be aware of what you're doing and why, because on the surface it appears that you might be asking for a sledgehammer solution to a penny nail problem, and if so you should be aware of the collateral damage.

like image 34
Mark Adelsberger Avatar answered Sep 25 '22 14:09

Mark Adelsberger