0

I want to use next typical workflow:

  1. create new branch for feature, and checkout it
  2. do commits in feature branch
  3. checkout master
  4. merge with feature branch.
  5. push changes

It is very typical use case. However, there is one thing that anoying me - I dont want to show my branch commits to public. I just want to push only merge commit, without feature developing history.

One can propose to use git rebase with commits squashing. But in fact, such squashing is just workaround, not a real solution. I want to have all my commits localy, merge graph, for history purposes.

I want to get simmilar that I get with git svn dcommit - only merge commit is pushed onto the remote, but I see localy whole history of development, with feature commits, with two-parents merge node and appropriate merge graph.

John
  • 9
  • 1
  • 2
  • I'm not sure why you want your commits on the feature branch to be non-public. If it's because the history is "ugly" and filled with hacky work-in-progress commits, you can clean it up with `git rebase -i`. If it's because you want the history to appear totally linear, you can rebase the entire feature branch on top of master (plus optionally squash it into a single commit). There are good reasons *not* to do these things, but I think they're much cleaner than having two separate histories for the same project. – Tyler Jul 18 '11 at 02:59
  • Alternatively, if you really want to hide the history away from people, don't make your git repo public *at all*, just publish the source code of each new version as a downloadable tarball. – Tyler Jul 18 '11 at 03:00
  • I am working in corparate environment. I want to use frequent at my local repo during development process, to have very precise history. It also allows me to juggle with comment of local branches, make new branches from old commits, etc, etc. But I dont want push very small commits into corparate repo, because it will bloat it. Frequent commits will bother another team members. I asked how to do what I want, or tell me if it is impossible. But I did not ask me to read of morality, what is good and bad. I need just practical answer. – John Jul 18 '11 at 20:03
  • I wasn't preaching, I was trying to understand why you wanted to do this. Git is really good at keeping its repos small, so I wouldn't worry about "bloat" in terms of actual disk space on the server. If you mean that the logs on the server will get overly twisty, then I would say you should try to stick to one merge per branch, as I said on my comment on svick's answer, and use `git rebase -i` as I said above. Again, I'm really not trying to "lecture" you. This is just a weird use case and I'm trying to get to the underlying reasons behind it and try to help you find a workflow you can like. – Tyler Jul 18 '11 at 20:42
  • I am coming from svn world, where I didn't frequent commits. Actualy during developing some large feature, I did copies of changed files manualy. At git, I want to use very small commits, for example once per half-hour, or even more frequent. Such small commits are usefull during development process, they are like "save game". After sometime of development I may want to look for such history again. But for others they will be not usefull. And they will bloat repo in terms of history looking, especially if there are several trunk branches (release, development, etc). – John Jul 19 '11 at 18:50
  • I am not yet decide which git usage pattern I will use. That why I asked that question - if it is impossible, than I will correct my patterns, and for example will do less fequent, logically complete commits. – John Jul 19 '11 at 18:57
  • I think your desire to do small, frequent commits is good! That's part of what makes git great, it encourages that committing style. Why do you think that keeping those commits around might be helpful for you, but would never be helpful for anyone else? Most of the time, people will just get the latest revision from `master` and work from there, ignoring the history entirely. Then when they do want the history, they can get it. – Tyler Jul 19 '11 at 20:25

3 Answers3

0

You could try

git merge --squash <feature branch>

That will do everything you want with the exception of the branch's not actually being considered merged.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • yes, I know this solution, it is also workaround. What if I will continue feature development after artificial merge, and than try merge again? – John Jul 13 '11 at 21:59
  • Git should handle it fine. You just won't have really great history. – Ryan Stewart Jul 13 '11 at 22:17
  • Say what? Your requirement is that in the repo you push to, the individual commits not be seen in the history of master, but now you're saying you *do* want that. You can't have it both ways. You either have the commits in your history or not. – Ryan Stewart Jul 14 '11 at 01:08
  • Re-read my initial message: "with two-parents merge node and appropriate merge graph". Does your solution produce two-parents megre node in local repo? - no, so it is not acceptable. – John Jul 14 '11 at 07:40
0

If I understand you correctly, you want to have one commit (i.e. one SHA1), but you want it to look differently on your copy of the repository than on on the central copy.

Doing that is just impossible. Git was made so that this way impossible. If you know a SHA1 id of a commit in a repository, you can be sure that you know all its history.

But, there is one way to fake that: using grafts. This way, you can add a parent to a commit without actually modifying it. Although I'm not really sure this is a good idea.

svick
  • 236,525
  • 50
  • 385
  • 514
  • ok. looks like I want illegal thing in terms of git model. So, for me it is just git disadvatage. It is good, that I am using git with svn, and dont have same problem – John Jul 13 '11 at 22:32
  • As the result, using frequent commits in feature branches will bloat remote repo – John Jul 13 '11 at 22:36
  • 1
    @John, that's what's rebasing and squashing for. If you think some commits might be useful for you and you don't want to squash them, they might be useful for others too. And if you have a feature branch with a hundred commits, you don't have to squash it to just one, you can make, say, twenty commits out of it. – svick Jul 13 '11 at 22:38
  • If merge branches are not hidden, project log graph on main repo will became terrible (when there are several developers) – John Jul 13 '11 at 22:47
  • Look like it is time for fork git – John Jul 13 '11 at 22:48
  • "If merge branches are not hidden, project log graph on main repo will became terrible" This is a fair point. Especially if you're coming from SVN, all the branching and merging in a typical git history looks a little overwhelming. I think most people would say it's worth it, however, to have the full history of your project captured accurately. One thing you could do is minimize merges: For example, don't merge master into feature branches before they are complete. Just have one single merge, from feature into master, for each feature branch. – Tyler Jul 18 '11 at 03:06
  • "don't merge master into feature branches before they are complete" - it is typical use case of topic branches. I didn't asked for lecture on Git, I just need a good answer. – John Jul 18 '11 at 20:07
0

Based on your comments, here's another solution: Do your work in feature branches, like normal. Merge feature branches into master as needed, like normal. Before you push to the remote, do a squash merge to a separate branch, and push that branch to the remote. Example:

# Create two repos for testing
mkdir test-git-merging
mkdir test-git-merging2
cd test-git-merging2
git init
# Have to set this flag to be able to push with master checked out
git config receive.denyCurrentBranch ignore
cd ../test-git-merging
git init
# Base commit in first repo
git commit --allow-empty -m "init"
# Create the branch that will be pushed to the remote
git branch remote-master
# Make some files and commit them in master
echo foo >> foo
echo bar >> bar
git add .
git commit -m "added files"
# Make a change on a branch
git checkout -b branch
echo 1 >> foo
git commit -am "Modified foo"
# Make a non-conflicting change in master
git checkout master
echo 2 >> bar
git commit -am "Modified bar"
# Do a normal merge from branch to master--normal history
git merge branch
# Squash merge from master to special remote branch
git checkout remote-master
git merge --squash master
git commit -m "Everything is squashed"
# Set up the remote and push config
git remote add other ../test-git-merging2
git config branch.remote-master.remote other
git config branch.remote-master.merge master
git config push.default tracking
# Push the branch
git push

I've tested that sequence of commands to see that it works. Of course, the branch remote-master will still never have real history, meaning that it will always be dangerous to pull stuff back from it to your working branches, but that's essentially what you're asking for.

Ryan Stewart
  • 126,015
  • 21
  • 180
  • 199
  • I have tested you solution. Problem is just shifted to syncing master and remote-master. How should I take changes that others do in remote-master, to my master? However, nice try. Also possible use another scenario: merge master branch to feature branch (instead of normaly feature branch to master), and then merge --squash feature branch to master, however it is also just workaround, but looks better than rebase squashing – John Jul 14 '11 at 07:09
  • If you're going to mimic git-svn in one direction, you'll have to do it in both. In order to pull changes back from remote-master to master the way git-svn does, you would first fetch changes from the remote into remote-master, then rebase master onto remote master starting from the first commit not represented in remote-master. Of course, you'll end up losing your old merge history this way, too, but that's the way it works. If you want SVN-style merging, use SVN. – Ryan Stewart Jul 14 '11 at 15:22