News for hackers. Stuff that matters.
Re:Git rebase in depth by gwright on Friday May 10, 2019 @10:59AM (#19878396)
About 99.9% of the time when people talk about rebase they talk about ‘editing’ history or ‘rewriting’ history as in the first sentence of the article.

I find that terminology terribly misleading and when I was learning git and rebase it confused the heck out of me.

No commits are harmed in the operation of `git rebase`. All the commits you had in the repo before the rebase are still in the repo. Git rebase creates a new sequence of commits and after doing its work relocates the branch name to the tip of the new sequence but you can easily access the previous commits if need be:

    $ git co feature-branch
    $ git rebase develop
    $ git co -b before-rebase-feature-branch feature-branch@{1}
Re:Git rebase in depth by Chazprime on Friday May 10, 2019 @11:45AM (#19878841)
This really should be the top comment here. Learning about the non-destructive nature of Git really helped me overcome the unease around using some of Git's more advanced features (especially in a team environment).
Re:Git rebase in depth by Buttons840 on Friday May 10, 2019 @12:33PM (#19879409)
Yep. Specifically, git will never delete a commit, unless it is old (like 30 days old or older I think?) and is not part of a branch. I suppose there may be some arcane commands to force a deletion, but it wont happen by accident or by normal usage.

Like you, I felt much more comfortable using git after learning this.

Re:Git rebase in depth by dahart on Friday May 10, 2019 @12:58PM (#19879727)
> git will never delete a commit, unless it is old (like 30 days old or older I think?) and is not part of a branch.

Yeah, completely unreachable commits have 30 days, even when you run git gc. The default reflog for a branch is even longer: 90 days!

https://git-scm.com/docs/git-gc

Re:Git rebase in depth by shandor on Friday May 10, 2019 @02:29PM (#19880757)
This is also why commiting very often is a very good idea.

I often try to reassure people new to git that "if you'll just commit often, there's basically no way you can lose work so that I can't help you get it back. Apart from deleting the whole repo folder. Don't delete the repo folder.".

I also have the habit of preventing non-fast-forward pushes on origin/master, which also helps when I can tell my team that they can't trash the origin even if they try.

Re:Git rebase in depth by kohtatsu on Friday May 10, 2019 @02:43PM (#19880889)
Which merge strategy do you recommend?

    # Merge commit
    git merge --no-ff -m <message> <hash>
    # Squash and merge
    git merge --no-commit --squash <hash>
    git commit -m <message>
    # Rebase and merge
    git rebase --force-rebase <hash>
From https://stackoverflow.com/a/52301456
Re:Git rebase in depth by shandor on Friday May 10, 2019 @03:02PM (#19881112)
I...have to admit that my merge strategy, and what I teach my teams, is "don't" :) (only slightly tongue-in-cheek)

I believe in clean, linear history, and strongly prefer rebase-based workflows to merges. That's actually one of the reasons I chose Phabricator for my current place, as it is also very opinionated towards the same way of working.

Edit: oh, and to answer your actual question, the third one.

Re:Git rebase in depth by greyskull on Friday May 10, 2019 @03:27PM (#19881373)
+1. Interactive rebase to squash your feature branch, then ff merge into master/mainline.

Years ago when I was just reading about git instead of using it, I saw sentiments along the lines of "always use feature branches and merge them so your thoughts and process can still be looked at later". In the last ~5 years or so I've worked professionally, I've not once wished I could reference intermediate commits in my own code or someone else's. I've found that ambiguities and clarifications can and are caught during the code review process.

I'd say another couple of benefits:

- It's relatively easy to teach git workflows when the log/graph is linear, and similarly it's _way_ easier to reason about your workspace when you have an actual production codebase.

- Merge commits can make certain operations like reverts and patches harder to reason about

Re:Git rebase in depth by u801e on Friday May 10, 2019 @04:26PM (#19881907)
> In the last ~5 years or so I've worked professionally, I've not once wished I could reference intermediate commits in my own code or someone else's. I've found that ambiguities and clarifications can and are caught during the code review process.

One command I often use is git blame which allows me to find the commit that's associated with a particular line of code. Then I can look at the commit message and the diff against its parent. Perhaps what I'm changing may undo a bugfix and I wouldn't have realized it without reading the associated commit message.

Re:Git rebase in depth by kqr on Friday May 10, 2019 @05:41PM (#19882516)
That's separate from what the grandparent talked about. During the process of developing a new feature, I may incrementally refactor old code a few times, but only some of those changes make it into the final merge.

When I look back at the history, I'm only interested in seeing the changes that actually made it through, not every intermediate alley and dead end in between. If those dead ends are significant discoveries/results, I document them elsewhere.

Re:Git rebase in depth by Vinnl on Saturday May 11, 2019 @07:22AM (#19885642)
Yes, that's exactly my main motivation for rebasing too: properly thought-out commits can give more context to the lines of code I'm looking at. (I wrote these thoughts up in more detail here: https://vincenttunru.com/Spend-effort-on-your-Git-commits )
Re:Git rebase in depth by mikekchar on Saturday May 11, 2019 @03:58AM (#19885127)
The trick is you have to pick one of "merge always and avoid rebase" or "rebase always and avoid merging". If you take a branch, merge master into it, do some more development and then rebase it onto master, you are asking for trouble. If you have a revert in there (and especially a revert on a merge commit), it's a world of hurt.

But either way works fine. It just gives you a different history. My team likes merging because they don't understand exactly what happens when rebasing. In that environment `git log --topo-order` is practically a necessity, though.

Re:Git rebase in depth by yebyen on Sunday May 12, 2019 @07:52AM (#19891362)
I prefer to say, merges should only flow one way. (And always rebase before a merge.)

If you are merging master into a feature branch that has ongoing work and continues without merging back to master, that's the problem.

If your feature branch is short-lived, it can be easily rebased.

If your other branch is more like a release branch, with lots of work that can't be rebased easily, some times you can't really avoid a merge from master without communicating it first. If your team is large or distributed it might not be practical to say "release has moved to (rebased ref), please catch up"

In that case you should treat merges to release the same as merges to master (they should be finished bits of work that are considered published) and any unmerged features for the release, are kept on feature branches that are based on the release. They can be rebased after the point where master is merged back into release to avoid the nasty merge conflicts.

Re:Git rebase in depth by gbacon on Saturday May 11, 2019 @07:44AM (#19885698)
When cleaning up my own feature branch for review

    git merge —-squash <tree-ish>
When merging into the baseline

    git merge —-no-ff <tree-ish>
The reason for the latter is subtle. Yes, a perfectly linear history is nice in the aesthetic sense. However, the merge commits are artifacts of reviews that are useful in process audits, which QA and QC like to preserve.
Re:Git rebase in depth by MichaelMoser123 on Friday May 10, 2019 @01:33PM (#19880154)
How comes that I see older commits with git log -p ? I can even see what the commit changed.
Re:Git rebase in depth by tomcatfish on Friday May 10, 2019 @01:54PM (#19880405)
Those commits are referenced. Parent comment is talking about commits that have no references to them (ie. You make a commit then remove all traces of it, it is not gone completely until after a certain amount of time).
Re:Git rebase in depth by kradroy on Friday May 10, 2019 @12:39PM (#19879488)
I had to do a git history rewrite via "git filter-branch" and one other method. I can attest that you really have to go out of your way to actually permanently get rid of anything in a git repo. It's always funny to me when I see an engineer have a panic attack the first time they think they've trashed the repo and lost important code. They always have that same look as relief washes over them when I show them how to recover from the mistake.
Re:Git rebase in depth by rags2riches on Friday May 10, 2019 @03:17PM (#19881262)
Git is non-destructive and its great. Until you learn why the really dangerous command nobody talks about is git checkout.
Re:Git rebase in depth by lisper on Friday May 10, 2019 @03:24PM (#19881339)
Or until you accidentally check in a file that contains a secret. Then the non-destructiveness becomes a serious problem.
Re:Git rebase in depth by palunon on Friday May 10, 2019 @04:20PM (#19881850)
Two possibilities there: either your secret was published to others, and it's not a secret anymore, or it wasn't, and you can easily remove it. (Even from your local repo, if necessary remove the relevant blob hash)
Re:Git rebase in depth by kkarakk on Saturday May 11, 2019 @07:04AM (#19885601)
Easy to say but a chinese dev went to prison for pushing DJi's secret crypto key to github
Re:Git rebase in depth by thanatos_dem on Friday May 10, 2019 @12:16PM (#19879207)
Once I learned about the reflog I got a lot more adventurous with git. Now I’m the “git expert” in my team.
Re:Git rebase in depth by dmitryminkovsky on Friday May 10, 2019 @11:43AM (#19878831)
> No commits are harmed in the operation of `git rebase`. All the commits you had in the repo before the rebase are still in the repo.

They are still in the repo, but if no treeish item (eg. a branch) points to them, then they'll eventually get garbage collected.

Still, glad to see people are trying to elucidate git rebase. A small subset of its functionality is fundamental part of my workflow and I wouldn't know how I'd use Git without rebasing.

Re:Git rebase in depth by Sir_Cmpwn on Friday May 10, 2019 @11:45AM (#19878843)
git-gc will also preserve objects which are referred to in reflogs - it doesn't just have to be tree-ish. From the man page:

>git gc tries very hard not to delete objects that are referenced anywhere in your repository. In particular, it will keep not only objects referenced by your current set of branches and tags, but also objects referenced by the index, remote-tracking branches, refs saved by git filter-branch in refs/original/, or reflogs (which may reference commits in branches that were later amended or rewound). If you are expecting some objects to be deleted and they aren’t, check all of those locations and decide whether it makes sense in your case to remove those references.

Re:Git rebase in depth by dmitryminkovsky on Saturday May 11, 2019 @10:31AM (#19886361)
I didn’t know that! Thanks so much. I was always a bit nervous about things in my reflog being GC’d.
Re:Git rebase in depth by Dayshine on Friday May 10, 2019 @11:55AM (#19878973)
I really don't understand why git doesn't create a tag when you rebase in case things go wrong, or more generally when doing potentially gc-able actions. Pretending the average user will know how to get things back to how they are is silly.
Re:Git rebase in depth by jrockway on Friday May 10, 2019 @12:00PM (#19879029)
Re:Git rebase in depth by brandmeyer on Friday May 10, 2019 @12:47PM (#19879592)
This is technically true, and a common reposte when talking about preservation of history edits.

Unfortunately, the reflog is confusing and hard to use correctly in the case of an interactive rebase with multiple steps. It is hard to figure out exactly how far back you need to go in the reflog to get to moment before the rebase started if you want to start over. It also just so happens that its when an interactive rebase goes awry that I really want to reach for the reflog to fix the damage.

Re:Git rebase in depth by eridius on Friday May 10, 2019 @02:17PM (#19880638)
HEAD and the branch have separate reflogs. Each step of an interactive rebase adds a separate entry to HEAD's reflog, but the branch's reflog only ever gets a single new entry when the rebase is complete. So you can run e.g. `git log -g master` and skip the rebase intermediate steps.

It is rather unfortunate that there is no convenient documented shorthand for "show me the reflog of the current branch" (`git log -g` gives you HEAD's reflog). That said, after a bunch of experimentation, it seems like `git log -g '@{0}'` will give you the reflog for the current branch. Apparently this works because e.g. `git log -g '@{2}'` gives you the reflog for the current branch skipping the first 2 elements.

Re:Git rebase in depth by dmitryminkovsky on Saturday May 11, 2019 @10:36AM (#19886381)
Thanks for pointing this puts I didn’t realize/notice this until recently. And it makes a lot more sense than having one reflog. I would have liked to have known sooner.
Re:Git rebase in depth by u801e on Friday May 10, 2019 @01:45PM (#19880295)
> Unfortunately, the reflog is confusing and hard to use correctly in the case of an interactive rebase with multiple steps. It is hard to figure out exactly how far back you need to go in the reflog to get to moment before the rebase started if you want to start over.

When you run git reflog after rebasing, you will see lines like the following:

  29d82ac HEAD@{6}: rebase -i (finish): returning to refs/heads/your-branch
  29d82ac HEAD@{7}: rebase -i (fixup): Commit message 2
  4f8e996 HEAD@{8}: rebase -i (pick): Commit message 2
  f3a954e HEAD@{9}: rebase -i (pick): Commit message 1
  f74b8a5 HEAD@{10}: rebase -i (start): checkout origin/master
The line listed after the one that has rebase -i (start) is the commit you were on before you started the rebase. If I screw up a rebase, then I will stash any uncommitted changes and run a git reset --hard to the commit listed below the rebase -i (start) commit I see in the reflog and start the rebase again.
Re:Git rebase in depth by chrisweekly on Friday May 10, 2019 @11:03PM (#19884263)
Yes, git stash is awesome! I use it all the time to "snapshot" my WIP and/or to quickly get a clean working tree when taking an interrupt to work on something in a different branch. (`gs` alias for `git stash save -u`, along with `grs` for `git reflog show stash` -- which shows the commitish for each stash...)

I see the stash as kind of like a private remote, in that I can freely put whatever messy or experimental or half-baked WIP I like, gaining the benefits of a commit without inflicting it on anyone else.

Re:Git rebase in depth by Stratoscope on Friday May 10, 2019 @01:32PM (#19880148)
SmartGit does a brilliant job of integrating the reflog and stashes into the rest of Git. The history log window has a Branches panel, which is a tree view with subtrees for your local and remote branches. Below those is another subtree of any stashes you have saved, and then a Recyclable Commits checkbox.

When you turn on Recyclable Commits, every commit in the reflog shows up in the history tree just like any other commit. You can see exactly where they diverge from your other branches and can work with them as you normally work with any commit.

Same thing for stashes: check one and it just shows up as part of the commit tree as if it were a normal commit.

I've used SmartGit for years and highly recommend it over the Git command line for the way it gives you so much more insight into the state of your repo.

Re:Git rebase in depth by Dayshine on Monday May 13, 2019 @05:26AM (#19897430)
This is literally what I was referring to with:

"Pretending the average user will know how to get things back to how they are is silly."

The reflog is faaar more complicated to use that any of the day-to-day git commands.

Re:Git rebase in depth by mixmastamyk on Friday May 10, 2019 @11:59AM (#19879014)
Yep, it was designed by and for linux kernel development, that average users are using it is an accident of history.
Re:Git rebase in depth by irrational on Friday May 10, 2019 @01:54PM (#19880411)
So what are the chances that a version of Git, or something like Git, will be developed that is suitable for the average user? Someone above made a comment about how easy it is to do X in Git, and then preceded to write lines of Git commands that are as arcane as anything an alchemist could come up with. If that is easy Git, I'd hate to see what hard Git looks like.
Re:Git rebase in depth by mixmastamyk on Friday May 10, 2019 @02:08PM (#19880557)
Making it could be done, Mercurial already exists for example. Perhaps a next-gen version introduced with all the lessons learned over the last decade.

Getting folks to use it would be very difficult due to network effects however.

Re:Git rebase in depth by muxator on Friday May 10, 2019 @06:41PM (#19882948)
So true. I live a mercurial life, in a git world. Thanks to hg-git, it is easy to use it and just treat the remote git repository as a black box.

After having rewritten history locally (with Mercurial this is easy, powerful, safe and with a lot of tooling available) everything you need to do is doing an hg push --force.

For one, hg histedit with its curses interface (default since 4.9) is sweet.

Re:Git rebase in depth by acqq on Friday May 10, 2019 @04:51PM (#19882109)
Don't hope for git to become something else. Something else will be something else.

In reality, git is actually far from ideal tool, with its own weak points and use-case scenarios which it simply not or badly supports. So it's never "just you" don't feel bad that it's "hard." On top of this, even the scenarios that it supposedly "good" supports demand sometimes totally "illogical" combination of the names and parameters.

git is used in spite of its flaws for different reasons. Some actions are really very fast, faster than by the competition. Sometimes that is a reason enough. Another is -- we have to use what our colleagues use. Even another: once you become familiar with it, even if you were aware of the weirdness, it can stop annoying you. Still to be able to realistically compare it with something else, you have to at least try it. And that something else too.

Re:Git rebase in depth by mikekchar on Saturday May 11, 2019 @04:05AM (#19885143)
Something like Darcs is probably going to be the next generation. The nice thing about Darcs is that it records patches in an order independent fashion. This means that you can reorder your commits without penalty. This allows you to remove pretty much all problems requiring ninja-like skills to fix in Git. Darcs, has performance problems on merges, though (as a result of its approach). However, I remember a while ago about someone saying they found a solution to the problem. I think they meant to write a new system, but I can't for the life of me remember what it was called.

Anyway, once you get rid of the actual complexity in git, it's an easy step to work on the added complexity to the UI.

Re:Git rebase in depth by pdobsan on Saturday May 11, 2019 @06:08AM (#19885459)
Pijul (https://pijul.org/) is based on a categorical theory of patches (https://arxiv.org/abs/1311.3903). It is similar to Darcs but written in Rust. They claim that Pijul has solved the exponential merge problem. The docs, FAQ, and blogs, in particular the last one, are interesting readings.
Re:Git rebase in depth by theoh on Friday May 10, 2019 @02:51PM (#19880982)
Git is really a toolkit for version control. Linus (or some other Git proponents?) distinguishes between "plumbing" and "porcelain": the infrastructure and the UI.

Linus wouldn't claim to be a brilliant designer of user interfaces. It's totally conceivable that somebody could come along and develop a new way of talking about Git's functionality, implemented by a new "porcelain". Changing the vocabulary, creating a more comprehensible map of the internal logic of the thing...

Re:Git rebase in depth by mcguire on Friday May 10, 2019 @05:16PM (#19882319)
Unfortunately, none of the porcelains caught on, because all of the power users use plain git.
Re:Git rebase in depth by jdormit on Friday May 10, 2019 @05:42PM (#19882518)
Except those of us using magit instead ;)
Re:Git rebase in depth by theoh on Friday May 10, 2019 @06:22PM (#19882831)
Who knows what the future holds. Once upon a time all the power users used assembly language.
Re:Git rebase in depth by humblebee on Friday May 10, 2019 @01:41PM (#19880242)
feature-branch@{1} is the branch prior to the rebase.

https://www.git-scm.com/docs/gitrevisions#Documentation/gitr...

Re:Git rebase in depth by mkesper on Saturday May 11, 2019 @02:27AM (#19884902)
Create a backup branch before:

    git branch local/foo
If you mess up too hard, check it out again.
Re:Git rebase in depth by hinkley on Friday May 10, 2019 @03:04PM (#19881129)
> They are still in the repo, but if no treeish item (eg. a branch) points to them, then they'll eventually get garbage collected.

Why else are you going to go through the trouble of rebasing master if this isn't the goal you're shooting for? I'm a big proponent of commit history hygiene but even I can't defend rebasing master except for egregious things.

I think the only time I rebased master except for this was to fix a poorly executed mass file rename that broke git annotate.

Re:Git rebase in depth by rusk on Friday May 10, 2019 @11:58AM (#19879010)
I'd suggest creating the branch before the rebase:

    $ git co feature-branch
    $ git branch before-rebase-feature-branch
    $ git rebase develop
Re:Git rebase in depth by gwright on Friday May 10, 2019 @12:11PM (#19879144)
Worthwhile if you anticipate something going wrong, but usually things are just fine or a `git rebase --abort` will get you back to a safe place (if you are using an interactive rebase).
Re:Git rebase in depth by humblebee on Friday May 10, 2019 @01:44PM (#19880275)
Or git `reset --hard ORIG_HEAD`

> HEAD names the commit on which you based the changes in the working tree. FETCH_HEAD records the branch which you fetched from a remote repository with your last git fetch invocation. ORIG_HEAD is created by commands that move your HEAD in a drastic way, to record the position of the HEAD before their operation, so that you can easily change the tip of the branch back to the state before you ran them.

https://www.git-scm.com/docs/gitrevisions#Documentation/gitr...

Re:Git rebase in depth by dan00 on Friday May 10, 2019 @11:23AM (#19878612)
> No commits are harmed in the operation of `git rebase`. All the commits you had in the repo before the rebase are still in the repo.

The same changes are still in the repo (edit: I should have said branch here), but not the same commits, because the parents and children change and therefore the hash of the commits.

It is very important to be aware that the history is changed, because the previous history can not be without issues merged with the new one, which is the main pain point and the most problems that arise from a rebase.

Re:Git rebase in depth by Sir_Cmpwn on Friday May 10, 2019 @11:27AM (#19878651)
No, gwright is correct, and my guide fails to capture the nuance of this detail.

Each commit has a link to its parent, and represents the tip of a linked list. .git/objects is a heap of all commits (and other objects), and .git/refs contains a list commit IDs that define each head (e.g. master). git rebase will often introduce new versions of a commit to the heap and update the heads to reference new histories, but the old commits stick around and can be accessed through the reflog - with their full original history intact.

Re:Git rebase in depth by dan00 on Friday May 10, 2019 @11:39AM (#19878776)
It is right that the previous commits are still there in the repo, but from the point of git they are garbage now and going to be removed. The point are the commits reachable now from the branch.
Re:Git rebase in depth by dahart on Friday May 10, 2019 @11:53AM (#19878943)
What’s the matter with reachable and unreachable commits? Commits no longer needed should be unreachable and cleaned eventually, that’s a feature. Git is fantastic about keeping the unreachable commits for long enough that should I actually need them for any reason, they’re usually there. The default is 90 days. The number of times I need to dig into the reflog for any reason is very low, and always because I made a mistake. The number of times I’ve lost a commit irrevocably because it was cleaned before I needed it is 0.
Re:Git rebase in depth by ZeroGravitas on Friday May 10, 2019 @12:55PM (#19879678)
> The number of times I need to dig into the reflog for any reason is very low, and always because I made a mistake.

A good UI should allow you to recover from mistakes. Like the trashcan vs rm example everyone is using.

It's good that git doesn't permanently delete stuff, it's bad that you need to be a relative expert to know that. If git branch showed rebased branches and told you they would disappear in x days then beginners might feel less fear and embrace the power of git faster.

Re:Git rebase in depth by dahart on Friday May 10, 2019 @01:30PM (#19880118)
This is a little hyperbolic though, because git does have UI above the reflog designed for catching the most common mistakes. The reflog is a powertool, it is not the default UI, and most people never need to look at the reflog.

git rebase has an "abort" feature when you need to redo it. git has tag & branch & stash features if you want to save what you're doing before you rebase. The problem with keeping and showing rebased branches are that 1- you don't need them after the rebase is successful. You only need them when the rebase is going badly, and 2- you'd have a lot of unnecessary noise pile up. I often rebase multiple times before every push. I don't want to see them all, you probably don't either.

That said, I fully agree that git's UI could be better and help beginners feel less fear!

Re:Git rebase in depth by Sir_Cmpwn on Friday May 10, 2019 @11:40AM (#19878793)
git-gc will save stuff in your reflogs. It works pretty hard to avoid removing objects which are referenced by anything at all.
Re:Git rebase in depth by dan00 on Friday May 10, 2019 @11:48AM (#19878885)
Ah ok, the point about reflog makes sense. Thanks!
Re:Git rebase in depth by AlexTWithBeard on Friday May 10, 2019 @11:49AM (#19878896)
the old commits stick around

They kinda are, but that's like saying that deleted files are not deleted, but stick around for a while.

While technically true, for most practical purposes _rm <file>_ deletes the file. The fact that each and every "git 101" manual has to explain how to recover deleted commits, means something is wrong.

It's like saying: "Here's the key, and in case it doesn't work there's a pry bar in the garage". This is usually a pretty good indicator that the lock is broken.

Re:Git rebase in depth by mikeash on Friday May 10, 2019 @12:02PM (#19879055)
It’s more like saying that files in the trash or recycle bin aren’t really deleted. It’s true, they’re still there.

Someone who has never done it before won’t know how to retrieve them, but that’s hardly a surprise.

Re:Git rebase in depth by dahart on Friday May 10, 2019 @12:01PM (#19879041)
Comparing lost commits to rm isn’t a good analogy.

Git has a very good safety net when you know how to use it. The problem is knowing how to use it, not that it’s not there.

It’s a legitimate point that git’s UI sucks, that’s what’s wrong, and everyone agrees. But learn how to use the reflog and you will see the light!

Re:Git rebase in depth by pmiller2 on Friday May 10, 2019 @12:05PM (#19879088)
Git has very good safety even if you don’t know how to use it, provided you commit when you want something to be saved and you don’t rm the whole repo at the first sign of trouble.
Re:Git rebase in depth by AlexTWithBeard on Friday May 10, 2019 @12:36PM (#19879442)
I think my issue is that most people should not even know how this safety net works. But every other question about git on stack exchange seems to be "how do I recover from a failed rebase".
Re:Git rebase in depth by dahart on Friday May 10, 2019 @01:09PM (#19879861)
You have your wish: most people already don't even know how the safety net works. :P The existence of questions on a site designed to ask questions is not any indicator of how often rebase causes problems. Nobody posts to stack exchange every time it works and they're not confused. Aren't the questions on stack exchange a good thing, if what you want is for people to not have to learn the safety net? Just commit and rebase until there are problems, then if you get confused, go look up the answer on stack exchange or post a question if you don't see one already. Seems like the system is working?
Re:Git rebase in depth by pkamb on Friday May 10, 2019 @12:07PM (#19879107)
Just have a backup branch at the same commit as the branch you're about to rebase. It'll keep all of the pre-rebase commits on that standard branch. No need for the reflog or "trashcan" or anything weird like that.
Re:Git rebase in depth by PhaseLockk on Friday May 10, 2019 @11:37AM (#19878746)
My understanding is that the original commits will eventually be cleaned up during garbage collection if there is nothing else pointing to them. Is that correct?
Re:Git rebase in depth by dahart on Friday May 10, 2019 @11:48AM (#19878880)
> previous history can not be without issues merged with the new one

I don’t understand what you mean. Why would you rebase a branch and then merge the rebased version with the old version of that branch? I don’t think that’s a common workflow, that is a specific case you should avoid.

Typical use of rebase to clean up the unpushed portion of a personal repo before pushing doesn’t normally cause any problems. The main thing that pops up for me is trying to re-order my own dependent commits when I forget that one commit touched the same code as another. Squashing them during the rebase is the easy fix.

Re:Git rebase in depth by Myrmornis on Sunday May 12, 2019 @03:46PM (#19894061)
Yes, came here to say the same thing.

> If you've made a mistake and in so doing lost commits which you needed, then git reflog is here to save the day.

Seeing that sentence in the article immediately makes me think the author has poor git practices or even understanding. reflog is useful at times, yes. But it is not what saves beginners from losing work while practicing their rebasing skills. What saves them is that they didn't rebase an important branch. They made a temp branch, pointing at the HEAD of their important branch perhaps, and they screwed up the temp branch.

If people would just make this one thing clearer to beginners, it would help a lot of people learn git more easily and with less fear.

Re:Git rebase in depth by luhn on Friday May 10, 2019 @11:48AM (#19878888)
I'm familiar with the reflog and use `head@{n}` on occasion, but it never occurred to me that you could use that same syntax with branches. It seems obvious in retrospect—I feel silly.
Re:Git rebase in depth by war1025 on Friday May 10, 2019 @04:19PM (#19881843)
Thanks for pointing this out. I completely missed it when I read the parent comment. A neat trick.
Re:Git rebase in depth by sampo on Saturday May 11, 2019 @04:39AM (#19885246)
> All the commits you had in the repo before the rebase are still in the repo.

In your local repo yes, for next 30 days. Then git will garbage collect them. But when you force push new pointers to GitHub, the GitHub repo will lose access to the unreferenced commits right away.

But of course those 30 days will give you plenty of time to go back, if you changed your mind about the rebase.

Re:Git rebase in depth by nacho_weekend on Friday May 10, 2019 @12:56PM (#19879710)
Yes, I agree. Rebase has the ability to obfuscate and rewrite commits if you so choose. Rebasing to just re-order commits is totally viable and perhaps encouraged. We did this at a previous company and it made the commit history very clean to read. However, with great power comes great responsibility in a rebase, and a junior dev can easily mess things up if you don’t educate them properly.
Re:Git rebase in depth by gwright on Friday May 10, 2019 @01:14PM (#19879926)
Nope. It doesn't 'rewrite' commits. You are using the language I was calling out as confusing.

It creates new commits and moves the branch to the tip of the new sequence of commits. No existing commits are changed or deleted.

Re:Git rebase in depth by anamexis on Friday May 10, 2019 @01:10PM (#19879878)
OP's point was that rebasing cannot rewrite commits. It can only make new commits and change branch pointers to them.
Re:Git rebase in depth by Sir_Cmpwn on Friday May 10, 2019 @11:52AM (#19878929)
I just added a mention right after the big scary warning about how everything you do in git is non-destructive. Thanks for the suggestion!
Re:Git rebase in depth by pjc50 on Friday May 10, 2019 @11:59AM (#19879016)
As the old Andre Previn sketch joke says: all the right commits, but not necessarily in the right order.
Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @03:51PM (#19881606)
It's not 'editing' the raw history files, but you're still presenting a false history to your coworkers. To me there are essentially two kinds of rebases:

- Summarizing history: squashing "implemented subfeature A.A" and "implemented subfeature A.B" into "implemented feature A"

- Rewriting history: moving commits around, changing the base commit, and so on

In my opinion summarizing history is acceptable, you're making a creative decision that certain information will not be useful in the review/when trying to understand the code in the future.

Rewriting, on the other hand, is essentially lying. You're creating repository states that never existed, and which you have never tested. In the worst case, consider the following history:

    *     F: (master) Merge branch 'component2'
    |\  
    | *   E: (component2) Fixed component 2's integration with 1
    | *   D: (component2) Merge branch 'master' into component2
    | |\  
    | |/  
    |/|   
    * |   C: (master) Refactored component 1's API
    | *   B: (component2) Implemented component 2 that depends on 1
    |/  
    *     A: (master) Base
Yes, it could probably be completely linearized, but that would be a horrible idea. Commit B will leave the repository in a completely nonsensical state. Sure, you could squash in E to mitigate it (since, luckily, nothing else happened in component 2 in the meantime), but then you're still stuck explaining what will likely look like a bunch of really weird design decisions compared to if you had designed against component 1's new API immediately.

Historical context matters. If in doubt, don't rebase. Never `git pull --rebase` blindly.

Re:Git rebase in depth by gwright on Friday May 10, 2019 @04:30PM (#19881934)
It isn't lying. Advocates of rebase are always talking about a work flow where you are curating a set of proposed changes before merging into your "public" branches (.e.g, development or master).

No one is advocating that you use rebase on your public branches or basically any branch that has been "published". We are talking about feature branches or spikes or branches that exist just on one developer's machine.

Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @04:36PM (#19881977)
You're lying about the path that you took to get to that point, and you're creating a lot of (public) nonsense commits on the way there (unless you're very careful, and/or overly squash-happy).

Whether you've published the true history earlier is irrelevant to that discussion.

Re:Git rebase in depth by gwright on Friday May 10, 2019 @04:42PM (#19882036)
Let me try again. I'm advocating that you use rebase to improve the quality of your changes that will be reviewed before merging or even before being reviewed at all.

If I make three commits and then realize that I should have included something in the first commit, I use rebase to create a new sequence of three commits that has the corrected version of the first commit. I haven't shared those commits with anyone, this is just work that I've done locally.

Are you seriously advocating that creating a pull request with: (A, B, C, A-fixup) is better than using rebase and then creating a pull request with: (better-A, B, C)?

You think that second case is "lying" because I didn't show the intermediate step that included the mistake?

Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @04:59PM (#19882174)
Yes, it is lying.

You can mitigate most of the damage if it is convincing enough (for example, go through B' and C' and make sure everything still makes sense at each point), but realistically nobody is going to do that, because it's pretty inefficient way to spend your time. And even then, you're still removing context (unless you're just fixing a typo).

> I'm advocating that you use rebase to improve the quality of your changes that will be reviewed before merging or even before being reviewed at all.

That was clear from the start. But the fact that X breaks Y doesn't imply that Y is a good idea when X doesn't apply.

Re:Git rebase in depth by dang on Saturday May 11, 2019 @10:04AM (#19886216)
Throwing the word "lying" into an argument like this counts as name-calling and flamebait in the sense that the site guidelines use these terms. It leads to distracting, shallow, and therefore more boring conversation. Would you mind reviewing the rules and please not do that? Let's stay focused on exchanging what we're curious about.

https://news.ycombinator.com/newsguidelines.html

Re:Git rebase in depth by gwright on Friday May 10, 2019 @05:11PM (#19882272)
I really don't understand why you are choosing to use the word "lying".

Us mere humans make mistakes all the time. Typos, omissions, false starts, and so on. What is the value of throwing that raw set of events at a reviewer or complicating the understanding of the changes when viewed in retrospect from the future? What is the reason you call curating the work into a more polished form "lying"? Why do you think the time spent being intentional about changes isn't valuable when compared to the time spent by a reviewer (or your future self) to sort through the flotsam and jetsam of your intermediate work?

Re:Git rebase in depth by fulafel on Saturday May 11, 2019 @07:25AM (#19885652)
But reviewers in most Git workflows mainly look at PRs. Then if as a reviewer you want to see how the sausage was made, you can zoom in on the commits, including all the messy reality of how the work was done. In some circumstances you might of course want to hide this, but in an open and safe collegial environment this lets the reviewer understand your thought and work process.
Re:Git rebase in depth by raimue on Saturday May 11, 2019 @07:42AM (#19885691)
The reviewer also won't see all the things the author tried without ever committing these states. They don't need to see all the messy steps, or they would have needed to look over the authors shoulder all the time.

I rather review the final patch series with changes in logical order and not necessarily in the order the code was written or with intermediate work that was later reverted or changed again. I do look at commits, because also every commit message counts and is supposed to explain the individual change.

Re:Git rebase in depth by fulafel on Saturday May 11, 2019 @07:46AM (#19885704)
Sure, it's not a perfect record. But as in most things, perfect is the enemy of good.

The messy reality is valuable, when talking with your teammates about how the work was done and what kind of bumps were along the way. It's not about looking over their shoulders, it's about using data to develop together as a team, eliminating hinderances, etc - if you have the mutual trust to do that. And of course you yourself can go back and look for patterns of mistakes or problematic areas in code based on your history.

Like I said, to judge the change its, the whole PR diff is usually the most useful unit of inspection when you just want to see what happens. And if it's a big pr, you can of course always merge child PR's or branches against the big PR/branch, and look at the merge diffs.

Re:Git rebase in depth by fulafel on Sunday May 12, 2019 @04:57AM (#19890876)
Another formulation of the "learning as a team" idea-

The science principle of publishing your experiments, including failed ones, has the same benefits in sw engineering: others can build on your failed attempts, or save time by not replicating them.

Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @05:31PM (#19882436)
I'm using it to differentiate between summarizing (removing steps between A and B) and modifying (introducing new steps, reordering them, or editing them).

You can do it in a way that isn't harmful (as I mentioned earlier), but good luck getting a team to actually stick to that. It also doesn't help that pretty much no tooling encourages doing it properly.

Re:Git rebase in depth by avar on Friday May 10, 2019 @06:49PM (#19883001)
Are you lying to your co-workers when you draft an E-Mail to them, read it over, and decide to delete a paragraph or write it again from scratch? If your E-Mail client automatically saves drafts that's basically the equivalent of "rebase".

I made a typo when writing this reply, and pressed backspace to correct it. Is use of the backspace key lying?

I think you're placing a value on "history" that doesn't map onto all users of "rebase", or E-Mail client drafts. A lot of advanced users use it as the equivalent of "save" in an editor, sharing all those intermediate states is more noise than value v.s. crafting a sensible patch once you figure out what you want/what change to make.

Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @07:05PM (#19883107)
No, if you only merge changes then you're just summarizing.

The true problems begin once you start creating commits that represent repository trees that you never tested or reviewed, for example by editing past commits (invalidating any testing you've done of commits after that point), deleting past commits (aside from squashing an unbroken sequence of commits, or deleting them if the squash would result in a no-op), reordering commits, or rebasing commits.

Re:Git rebase in depth by avar on Friday May 10, 2019 @07:18PM (#19883173)
You're assuming that commits are tested before they're made, and that rebase invalidates this. I don't test most of my commits, just like I don't proofread an E-Mail after every word I've written. I do that later.

But yeah, the history you push to a canonical branch should generally be made up of commits that have all been tested in isolation. The rebase command doesn't make this worse, but better, e.g. with "rebase -i --exec='make test'".

I also prune out history of some false steps taken. Have you never written a program and done something like "I'll use a hash here <save><compile><test>, no actually a list makes more sense <save><compile><test> ...". Those intermediate steps are commits for a lot of advanced git users.

Sharing all your mistakes-as-you-go-along with the world doesn't help anyone, I'd typically be sending you a 100 patch merge request for some rather trivial change instead of 1-3 sensible commits.

Re:Git rebase in depth by int0x80 on Friday May 10, 2019 @10:51PM (#19884222)
That kind of rebase is just to refresh your work against updated masters etc. Of course you have to test against the refreshed (rebased) work again!! That doesn't mean you can't rebase. It means you can't randomly push untested work. If you know what rebase means you will understand that there are very likely new interactions with your code and you have to test your updated changeset. Exactly the same as if you merge. You have to retest the resulting tree.
Re:Git rebase in depth by meribold on Friday May 10, 2019 @11:43PM (#19884411)
A merge of a branch with N unique commits creates one new, yet-to-be-tested commit/tree. A rebase creates N. I doubt that it's common that people replay all the new history after a rebase and test each new commit/tree.
Re:Git rebase in depth by baddox on Friday May 10, 2019 @05:16PM (#19882323)
Maybe "lying" isn't the best term to use here, because it seems like you're using it to mean "not providing all information in a way that is morally bad." Of course you're not providing literally all information. Heck, I conceal a lot of information about my development process by testing and changing code before I even make a commit. But I think that's preferable to, for instance, providing a video screen capture of my entire development process for review.
Re:Git rebase in depth by aldanor on Saturday May 11, 2019 @04:54AM (#19885284)
Yea. Moreover, I would often ask my coworkers to rebase their code if there’s commits like “oops, missed a comma” because it distracts from the main point when you read the commit history.
Re:Git rebase in depth by bonzini on Saturday May 11, 2019 @02:08AM (#19884832)
> realistically nobody is going to do that, because it's pretty inefficient way to spend your time.

Of course you do! And it's not am inefficient use of your time, because it helps reviewers now, and yourself when you're bisecting later.

> And even then, you're still removing context (unless you're just fixing a typo).

You place that context in the commit message.

Re:Git rebase in depth by fulafel on Saturday May 11, 2019 @02:13AM (#19884854)
IME this is a very rare level of sophistication in use of rebase.

And how do you detect that you forgot / was too busy to do it, when you go back 6 months later? It's fragile, "fail-open".

Re:Git rebase in depth by bonzini on Saturday May 11, 2019 @02:48AM (#19884962)
You would be surprised. For example, this is a guide my colleague wrote to describe his git workflow:

https://github.com/tianocore/tianocore.github.io/wiki/Laszlo...

Re:Git rebase in depth by PButtNutter on Friday May 10, 2019 @07:19PM (#19883179)
I disagree.

Say upstream is at A.

I clone it in my local work-space, and make a few commits over the course of a few days. So my local is A B C

During this time other changes have been merged into upstream, so upstream looks like A D E

I now have two options. I can try to merge from upstream or rebase off of upstream. Merging introduces a messy commit history that quickly becomes difficult to follow. Rebasing removes my local commits, applies the changes in upstream, and then re-applies my local commits.

So after rebasing my local is A D E B C. There are no messy merge commits. And ideally, I can squash my local changes into a single feature commit, so upstream ends up incredibly tidy.

At no place in this process is there any dishonesty or lying. I haven't changed the history upstream, which is the source of truth. What's the issue here?

Re:Git rebase in depth by Nullabillity on Saturday May 11, 2019 @10:10AM (#19886248)
> So after rebasing my local is A D E B C.

No, your local is now A D E B' C'. Commits aren't just a diff between two tree snapshots, they are tree snapshots.

Hopefully you test and sanity check C' before submitting for review, but it's very unlikely that you're going to give B' the same treatment, making it more difficult for people to understand the history in the future (as well as breaking `git bisect`).

And even if you do, are your coworkers going to? Consistently? No CI tool that I'm aware of will enforce this for you.

> There are no messy merge commits.

No, but the underlying messy workflow is still there. You've just swept it under the rug for the sake of aesthetics, at the cost of future comprehension.

> At no place in this process is there any dishonesty or lying. I haven't changed the history upstream, which is the source of truth. What's the issue here?

Those are completely orthogonal concerns. You're presenting a false version of the repository state.

The common mantra of "don't rewrite public history" is about not creating a mess of duplicate commits, it doesn't imply that rewriting history is fine as long as it's not public.

Re:Git rebase in depth by Vinnl on Saturday May 11, 2019 @07:19AM (#19885638)
But you lie all the time, by that definition! If I write code, make a mistake and press Ctrl+Z before committing that code, I've just "rewritten" my history without my team mates being able to tell.

Your commit history is just a somewhat arbitrary recording of your code at certain points in time that you choose. Rebasing simply makes that less arbitrary, allowing you to document the way your code is built up in a structured way. Rather than having to decide on the spot whenever a certain combination of code is a good candidate for a single, atomic commit, you can make that judgment with the benefit of hindsight.

Re:Git rebase in depth by jolmg on Friday May 10, 2019 @04:45PM (#19882064)
How do you feel about deleting commits to avoid reverting them on such personal branches? Also, what about doing it to fix commit messages (maybe because they were accidentally written in a language that was not agreed on for the project)? What about splitting a commit with a generic "lots of semi-related things" commit message into multiple, more focused commits?
Re:Git rebase in depth by eshch on Friday May 10, 2019 @05:01PM (#19882190)
do you want to know all my wrong tries to make a thing work? why are you sure that all the commits i did are not nonsense? i look at the history as a way to 1) divide my work into reusable pieces of changes 2) document my changes to read for other developers.
Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @05:19PM (#19882348)
> do you want to know all my wrong tries to make a thing work?

Yes. A failed attempt is still a useful signal that people shouldn't try to simplify back to that way in the future (and why not). It's also a useful starting point in case the reasons it failed no longer apply.

Re:Git rebase in depth by scrollaway on Friday May 10, 2019 @11:10PM (#19884294)
It's very rare that "failed attempts" are a useful signal. When it is the case, it's better to document it (eg. as part of the commit message, PR, or the dev documentation itself).

Commit histories littered with commits that get back-and-forth reverted are frickin unreadable though. Extremely annoying to bisect, painful to comb through when looking for changes, noisy in git blame, etc. There's a ton of downsides for what in practice is very rarely even an upside.

Re:Git rebase in depth by jojo14 on Sunday May 12, 2019 @01:42AM (#19890363)
I agree with you, yet I don't understand why you were downvoted. I think git-rebase proponents haven't really ever worked in a professional environment particularly with several co-workers. I as a project manager would not trust a "rebaser" and I would question the time he spent to rewrite the git history. It is granted Merge and rebase need the same amount of reading the code and merging the differences. However with git-rebase there is the added cost of beautifying the history. Which means at least 2 drawbacks : one is the cost the other is more about memory. About cost, what is the point of rewriting the history when you have a (great) tool to janitor it. Then the git history automatically reflects the project history. If the git history is rewritten how would people remember the order of commits in case bugs occur. When did the bug happen ? Who should correct it ? IMHO those questions are more fundamental than a straight line of bullets in gitk.
Re:Git rebase in depth by gwright on Sunday May 12, 2019 @08:11PM (#19895467)
I can't help but feel like you don't understand a work flow that utilizes rebase in a responsible way. In particular you seem to think that the rebase is going to affect the history of a released version of your software (When did the bug happen?).

Nobody is suggesting that rebase be used to change the history of a released or published branch (master, develop etc.). If that is your concern and the reason for you not trusting a "rebaser" then you are simply mistaken, you are arguing against an imaginary workflow for which no one is advocating.

Rebase should be used only to curate the commits on a feature branch and to keep the feature branch synchronized with the upstream branch.

Re:Git rebase in depth by alkonaut on Saturday May 11, 2019 @04:29AM (#19885211)
I have a very simple solution to this: your feature is at most 1 or 2 commits (after squash) and they can be ff merge when your branch is done. Or it’s too big.

The exception to this is when a feature becomes more involved and has several logical steps, or any kind of history worth providing. This should be rare and when it happens, use merge commits to preserve history.

Not polluting the history with N trivial branches for every 1 branch that needs historical context, is a benefit of this.

Re:Git rebase in depth by JshWright on Saturday May 11, 2019 @07:55AM (#19885729)
In that case I assume you have also removed the backspace key from your keyboard?
[dead]
Re:Git rebase in depth by dang on Saturday May 11, 2019 @10:05AM (#19886219)
Personal attacks aren't ok here, regardless of wrong or annoying another comment is. Would you mind checking out the site guidelines and taking the spirit of this site to heart? We'd be grateful, since that's the only way for it to remain interesting.

https://news.ycombinator.com/newsguidelines.html

Re:Git rebase in depth by gwright on Friday May 10, 2019 @04:55PM (#19882146)
Or you could just rebase component2 when you learn that component1 has been updated on master:

    *     F: (master) Merge branch 'component2'
    |\
    | *   E: (component2) Implemented component 2 (now with updated component1)
    |/
    *     C: (master) Refactored component 1's API
    |
    *     A: (master) Base
So we've lost B and D from your example, but who cares about those commits?
Re:Git rebase in depth by Nullabillity on Friday May 10, 2019 @05:49PM (#19882565)
That's easy in the trivial example where nothing else happened in the meantime.
Re:Git rebase in depth by palunon on Friday May 10, 2019 @06:42PM (#19882956)
> and which you have never tested.

That's on you if you don't test every commit. I don't care if you had failing tests (or even build) when you were writing your feature. I care that every one of your patches (and thus commit) does one logical thing, and that tests passes (making bisect useful).

You want your PR commit history to tell a coherent story. No one care if a writer had 15 bad draft of their story before publishing, and the same apply here.

Re:Git rebase in depth by dahart on Saturday May 11, 2019 @10:22AM (#19886313)
> you’re still presenting a false history to your coworkers [...] essentially lying

This has been a common misunderstanding of git in the past, but thankfully is fading now. I was hoping it wouldn’t come back to haunt this thread. I don’t know where the extreme and hyperbolic idea of using git the way it was designed is “lying” and creating “false history” first came from, you aren’t the first person to suggest it, but it’s neither correct nor helpful to use that kind of language. This theoretical philosophical ideal that there’s only one true history is trading away things git was specifically created to do, as well as the practicalities of real world software development, in favor of a strange unrealistic and abstract notion that once git commit has been used the commit should never be touched again.

Everyone knows and agrees that rearranging already published commits is a bad idea. Not because it’s “lying”, but because it causes problems, costs other people time, and can even inflict irreconcilable merge conflicts on their work.

Cleaning up your own commits before you push using interactive rebase is not just a good idea, it’s the way git was designed, it’s what Linus does, and it’s kind to your team. This includes reordering commits and pulling with rebase.

> Historical context matters. If in doubt, don’t rebase. Never `git pull -- rebase` blindly.

Maybe you could back up your assertion with some examples of why it always matters, and why that justifies using words like ‘never’?

Your rhetoric is ignoring the real-world fact that on a large team, the majority of commits at any given time are orthogonal to each other, and that the parent commit you end up with is completely arbitrary.

Not only do I use pull -- rebase, I always git config --global pull.rebase true, and I frequently recommend others do the same.

Having merge commits in master every single time someone checks in is incredibly noisy and it inflicts friction on the entire team to force everyone to read the noisy log. I’ve always worked on teams that decided to take the more practical approach of one-off commits should not have a merge, regardless of when they happen, to keep history cleaner, and feature branches with more than a couple of commits or by more than one person should have a merge commit, to keep the master branch from having broken commits or unfinished features and so it’s always bisectable.

Re:Git rebase in depth by fulafel on Saturday May 11, 2019 @05:03AM (#19885301)
Yes, good explanation of the problem.

And the cherry on top is that you can't easily tell later if you are looking at rewritten history. So if the above kind of rewriting might have happened in your project, you will essentially not be able to trust git history anymore as a record of engineering decisions.