Hacker News new | past | comments | ask | show | jobs | submit login

You do that by merging.

For people who love a clean, linear history, this can be frustrating, because it creates a new commit that doesn't add anything new, it just merges two branches. At my current project, PRs get merged very slowly, and after every PR gets merged, we merge master back into all the branches, which has lead to a ridiculous number of merge commits, and the guy who loves clean history won't stop complaining about it.

The problem is: if you rebase instead, you don't actually change the old commit, you make a new commit that contains the same content change as the old one. But it's a new commit, different from the one you already pushed to remote. So now you want to push your new rebased commit (as well as everything from master) to remote, and git says that remote has a commit that you don't have locally. So it wants to rebase or merge that remote commit onto your local rebased commit, despite the fact that they contain the same change! Now if you choose to rebase your local changes onto the remote commit, it rebases all the commits that you just merged from master, creating new commits for them. Then pushes them to remote. Then you still can't merge your PR, because it now still doesn't have the original (unrebased) commits from master, because you just rebased them. But you've duplicated a ton of commits. This is a mess.

There are 3 ways around this:

* Replace the first rebase with a merge, merging master into your local branch.

* Replace the second rebase with a merge, from when you pulled remote when you wanted to push, duplicating the one commit you meant to rebase.

* throw away the old PR and create a new one.

The first and third are the good options. The second is bad because it has a duplicate commit, but it's not nearly as bad as when you tried to rebase twice in a row.

Seriously, if stuff gets complicated, throw away your PR. Or avoid it getting complicated by always merging. If you want clean history, your only option is to throw away your PR every time you merge master back into your branch. It's either that or accept extra merge commits.

A dirty shortcut to creating a new PR is to force push. This will throw away the original commit on remote and overwrite it with your new rebased commits. This will work fine as long as nobody has checked out that branch in the mean time. If someone else has checked it out and pushes to your remote branch again, they may still reintroduce the old unrebased commit, and you'll still have that duplicate commit.

I usually just accept extra merge commits. Sometimes I force push, but I really try not to. You have to be sure nobody else is using that branch. In a complicated setup with lots of developers, automated tests and build servers, I'm reluctant to count on that.




It seems like a lot of headaches could be avoided if you just don’t have people share branches. Then you just rebase master and force push away with reckless abandon,


That's certainly a possibility. But what if two people have to work on a big feature together?


Break the big feature up into smaller changes. Vertical slices help with that: https://news.ycombinator.com/item?id=33384275 Each change is merged to `master` after a relatively short amount of time. What some people call "trunk based development".

I've yet to build a big feature that wasn't worked on by 4 or 5 people at the same time. Since they're different vertical slices, they're different branches (and tickets). But even then you might have a frontend and backend person collaborating on the same branch for a small slice of functionality.

This is also not a problem as even with one branch for two people who work with it. In git there are constantly more actual branches around than you "realize". E.g. here there's 3 branches going around and you just merge/rebase them. One branch is the one in the shared repo. The other two branches are the local branches of the same name on each of the two developer's machines. They need merging or rebasing just like you merge/rebase with `master` itself.

Depending on what you changed, you'll have weird looking history and conflicts to solve (or commits to skip). Which needs some head wrapping around but git itself so far has never been confused by my "reckless force pushing" on a shared branch. It helps if you don't have two people actually changing the same parts of the code though. Then you're in a world of hurt for conflict resolution but it's not the force pushing part that creates the hurt. That's just always bad.

Before you bring this back into `master` you'll want to squash all this into one commit and thus all the weird history ceases to exist.

Also, communication is key. If someone force pushes, tell the other person and help them resolve any rebasing/merging conflicts w/ your knowledge of the changes you made. If two people sit in opposite corners, force pushing "their world view" without tell each other, you definitely will be loosing code.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: