Yeah learned this the hard way.

  • Ephera ( Ephera@lemmy.ml ) 
    link
    fedilink
    English
    arrow-up
    97
    ·
    1 year ago

    I’ve had juniors who didn’t believe this, so just to say it: If you know what you’re doing, practically any Git problem is recoverable.

    The one major exception is if you delete your local changes before committing them.

    • Yeah.But many of them are extremely annoying. Specifically screwing up rebase. It is recoverable, but very annoying.

      That said I have seen juniors make two other common mistakes.

      1. Pushing your commit without fetching
      2. Continuing on a branch even after it was merged.

      I’m fed up with these two. Yesterday I had to cherry-pick to solve a combination of these two.

      • psycotica0 ( psycotica0@lemmy.ca ) 
        link
        fedilink
        arrow-up
        33
        ·
        edit-2
        1 year ago

        Maybe I’m just a wizard, or I don’t know what y’all are talking about, but rebases aren’t special. If you use git reflog it just tells you where you used to be before the rebase. You don’t have to fix anything, git is append only. See where the rebase started in reflog, it’ll say rebase in the log line, then git reset --hard THAT_HASH

        Pushing without fetching should be an error. So either they got the error, didn’t think about it, and then force pushed, or someone taught them to just always force push. In either case the problem is the force part, the tool is built to prevent this by default.

        Continuing after merge should be pretty easy? I’d assume rebase just does it? Unless the merge was a squash merge or rebase merge. Then yeah, slightly annoying, but still mostly git rebase -i and then delete lines look like they were already merged?

        • See all this is fine for someone with good experience in git. They know how to solve the screw up. But wih junior devs, who don’t know much about it, they will just get confused and stuck. And one of the senior has to involve and help them solve. This is just annoying because these can be avoided very easily. Until they understand the pattern of how everyone operates with git, it just creates issues.

          To me first time causing this issue is completely fine. I will personally sit with them and explain then what went wrong and how to recover. Most of them will repeat it again, act clueless and talk like they are seeing this for the first time in their life. That is the difficult part to me.

          May be I’m just old school, and a grumpy old person, even though I’m not that aged.

        • Mr. Satan ( mr_satan@lemmy.zip ) 
          link
          fedilink
          arrow-up
          3
          ·
          1 year ago

          Same… My usual strategy: rebase, if conflict abort and merge, if no conflict continue; merge always with explicit commits to master / main (no fucking squashing); keep task references in branch names and commit messages.

          • balsoft ( balsoft@lemmy.ml ) 
            link
            fedilink
            arrow-up
            1
            ·
            1 year ago

            Same, but typically I will just resolve the conflicts during the rebase. Makes for cleaner commit history. Merge commits are for combining multiple big unrelated pieces of work together, where rebasing would be too annoying (let’s say 100s of commits each).

            • Mr. Satan ( mr_satan@lemmy.zip ) 
              link
              fedilink
              arrow-up
              1
              ·
              1 year ago

              In my cases I has to solve same code conflicts multiple times during a rebase, so I just don’t try them when hit with conflicts.

              I fail to see the benefits of “clean” git history

              • balsoft ( balsoft@lemmy.ml ) 
                link
                fedilink
                arrow-up
                1
                ·
                1 year ago

                In my cases I has to solve same code conflicts multiple times during a rebase, so I just don’t try them when hit with conflicts.

                Yeah if you have two branches, both with a bunch of commits which all modify the same areas of code, and reordering the commits doesn’t help, I can see how it is easier to merge.

                I fail to see the benefits of “clean” git history

                Well, if the commit history is clean and mostly linear, it’s much easier to read, understand and review. git blame will also be much nicer which is really important for debugging big codebases. Of course it’s a tradeoff, as usual.

        • Klajan ( Klajan@lemmy.zip ) 
          link
          fedilink
          arrow-up
          1
          ·
          1 year ago

          Continuing on a squash merged branch is very annoying, and I had to deal with this in one repo regularly… Luckily I was annoyed enough to research about this and found out about rebase --onto "main merge commit" "branch merged commit".

      • pmk ( pmk@lemmy.sdf.org ) 
        link
        fedilink
        arrow-up
        3
        ·
        1 year ago

        Is it ok to continue on a branch if you also merge back main into it? Like, branch gets merged into main on remote, local main pull, local merge main into local branch, push branch?

        • So this workflow is needed if you are working on a public, i.e. multiple devs collaborating on a single branch, scenario. But it is much better to avoid this as much as possible. Usually it is a ‘scoping’ issue, where you create a branch that is too broad. For example ‘api-for-frontend’, which is a massive thing.

          But let us say you absolutely have to get multiple devs on same branch, then this workflow is totally fine. There is nothing wrong in it.

          In our org we prefer to delete the branch after merge. In a way it says ‘this branch is closed’. This is to encourage devs to define smaller and more logically scoped branches.

          I want to take this opportunity to say that, branch is just a label on a commit, with some additional functions. Once you start focus on commits and lineage of the commits, then branches become some what irrelevant.

        • Is it ok to continue on a branch if you also merge back main into it?

          On some repositories, sure.

          But better maintained repositories don’t allow merge commits (because merge commits suck), and so will have squashed (or rebased) on merge.

          (If squashed) The squash will have changed commit IDs, so a long running branch rebased won’t benefit from a clean shared commit history.

          So it can work, but “you’re gonna have a bad time.”

          In general, git works best if branches are thrown away as soon and as often as possible.

          (Edit: Good clarification in response below, added here for consistency and accuracy.)

          • Ephera ( Ephera@lemmy.ml ) 
            link
            fedilink
            English
            arrow-up
            3
            ·
            1 year ago

            You don’t have to squash to avoid merge commits. Instead, you can git rebase main to update your branch. Effectively, this will rewrite the history of your branch, as if you had just branched from the main-branch and then instantly coded all your changes on top of that. (Well, the commit timestamps won’t change, but they will sit on top of the changes of the main-branch.)

            Afterwards, you should be able to merge into main by switching to it and then running git merge --ff-only your_branch.
            Because all the changes sit on top of the main-branch commits, it should be able to fast-forward. No actual merging needs to take place then. You’ve already resolved any conflicts while rebasing.

            This also allows you to keep branches for longer, so long as you frequently rebase and merge back.

      • balsoft ( balsoft@lemmy.ml ) 
        link
        fedilink
        arrow-up
        2
        ·
        1 year ago

        Specifically screwing up rebase. It is recoverable, but very annoying.

        WDYM? Typically git rebase --abort will “just work”. If you have specifically done something really wrong, just look into git reflog and then git reset --hard to whatever commit you were before the rebase.

        Pushing your commit without fetching

        Git won’t allow you to do that if you set up your server properly. It will force you to pull first. I have [pull] rebase = true in my settings so that it always rebases my commits instead of merging them, which makes for much cleaner history.

        Continuing on a branch even after it was merged.

        This generally shouldn’t be a problem, you can just rebase the branch afterwards and it will be fine (the common commits will typically just be dropped).

        • The problem is not when I have to rebase. I know how to handle it. But with juniors they approach us only when things are in a really bad situation, where they cluelessly applied some commands they found on internet or from an LLM. Then it is very annoying to sit down and untangle the mess they created.

          And regarding the pushing without fetching, it is usually a different branch. So they won’t incorporate the new changes in the main branch into their working branch, but just push their work into a branch. Again not a big deal. Just annoying.

      • I’ll get chastised, but when I screw up a rebase I create a backup branch and then have an LLM do the fixing…

        I’m not proud of it, but I’m a lazy man who doesn’t want to resolve the same conflict 32 times.

        • kibiz0r ( kibiz0r@midwest.social ) 
          link
          fedilink
          English
          arrow-up
          7
          ·
          1 year ago

          Having to resolve the same conflict multiple times suggests excess noise in your git history. You might want to pay closer attention to creating a useful git history. It’ll help with any future archaeology, and it’ll also help rebasing go smoothly.

      • Ephera ( Ephera@lemmy.ml ) 
        link
        fedilink
        English
        arrow-up
        7
        ·
        1 year ago

        Well, if you did commit it, but just hadn’t pushed it yet, and then somehow lost that commit, then git reflog would be the tool for it.
        Without a commit, sometimes you may have already staged some changes for an upcoming commit and can roll back to that.

        But if neither of those are the case, then I can’t really imagine how Git should help you there. You haven’t told Git about those changes yet, so it’s out of scope.
        At that point, you better hope your editor’s undo history goes back far enough…

    1. Use git for any code you write. Yes, even a simple script.
    2. Commit and push often. More often than you think is reasonable. You can always rebase / fixup / squash / edit but you can’t recover what you didn’t commit.
    3. ???
    4. Profit.

    Seriously, once you commited something to the repo it’s hard to lose it. Unless you delete .git. But a this point frequent pushing has your back.

    I know git can be hard to grasp in the beginning. It was hard for me too. I highly encourage everyone to put in the effort to understand it. But if you don’t want to do that right now just use it. Just commit and push. It will pay off.

    • Rooster326 ( Rooster326@programming.dev ) 
      link
      fedilink
      arrow-up
      6
      ·
      edit-2
      1 year ago
      1. (3) Get annoyed by constantly increasing Code Coverage Requirements on untestable (often legacy) code. Even afding comments requires code coverage go up! Line must always go up!
      2. Change step 2 to “Commit and push ONLY when absolutely necessary. Because adding comments often requires a rewrite of untestable code.”
      3. Go back to Step 2 and wait for a major bug.
      • 3 is not related to using git in any way. I’m not really sure what you mean in 4. I didn’t mean making a lot of changes, I meant that you should not wait with committing until you have a finished feature / fix / whatever. Commit after each refactor, commit after adding a new testable unit. It’s always better to have more checkpoints. If your team does code review, they will appreciate atomic commits too.

    • Primer - Zip ( Primer81@lemmy.zip ) 
      link
      fedilink
      English
      arrow-up
      2
      ·
      1 year ago

      I hear people praise git reflog a lot, but when do y’all use this? Most I’ve ever needed is git log --graph for history checking. Maybe if I was in a situation where I knew the code on local branch X was working on Friday, but not anymore on Monday, then I could use git reflog to go back to Friday for that local branch right? Is that the idea?

      • Slotos ( Slotos@feddit.nl ) 
        link
        fedilink
        arrow-up
        9
        ·
        1 year ago

        Power users rebase with squashes and fixups multiple times a day. Especially if the job’s integration process isn’t enforcing long living branches.

        Reflog is useful then, because you literally rewrite history every rebase.

      • chaos ( chaos@beehaw.org ) 
        link
        fedilink
        arrow-up
        4
        ·
        1 year ago

        I only use it when I’ve royally messed up and the commit I need to get back is no longer referenced anywhere. Accidentally deleted a branch, finished a merge or rebase before realizing I messed up, that kind of thing, just use the reflog to find it again, get a branch pointing to it, then try again.

      • git log will only show you commits in your history. If you’re only ever working forwards, this will contain all the stuff you’ll ever need.

        But if you’re rewriting history, like with a rebase or squash or something, or you’re deleting branches without merging them, then you can run into a situation where the official history of your branch doesn’t contain some of the commits that used to exist, and in fact still exist but are unlinked from anywhere. So reflog is the log of where you’ve been, even if where you’ve been isn’t in the official history anymore, so you can find your way back to previous states even if there isn’t otherwise a name for them.

        If all you care about is your current history, git can use the dates of commits just fine to see where you were on Thursday without needing the reflog.

    • JustTesting ( JustTesting@lemmy.hogru.ch ) 
      link
      fedilink
      arrow-up
      11
      ·
      edit-2
      1 year ago

      Been using it for over a year now and not being scared of trying operations is such a boon. It helps so much with learning when you know you can just roll back to an earlier state.

      I’ve had zero issues with it so far and no one at work noticed anything different, other than there being a bit more rebase spam on PRs.

      • EzTerry ( ezterry@lemmy.zip ) 
        link
        fedilink
        English
        arrow-up
        1
        ·
        1 year ago

        Anything you can do in Jujitsu you can do in git… The big difference is a paradime change:

        -instead of a working directory that has pending changes you need to add than commit, all changes are in a commit that is lacking metadata.

        The system has better “editing” of local history to set that meta data. But once you push to a shared repo you run the usual risks of force pushing.

        I’m not sold, rather git not do anything until asked and just run git status constantly but I don’t have first hand experience… I would theory it would be more likely to add a file you didn’t mean to… Unlike those who use windows guis for git and forget to add new files.

    • … and force push.

      If you ever find yourself in a situation where rebase or a force push seems to be the solution, take a step back, clone your repo in a new directory and copy the changes into you’re new checkout - ‘cause you gon’ and screwed somethin’ up, son.

        • Same. And even if you were to fuck up, have people never heard of the reflog…?

          Every job I’ve worked at it’s been the expectation to regularly rebase your feature branch on main, to squash your commits (and then force push, obv), and for most projects to do rebase-merges of PRs rather than creating merge commits. Even the, uh, less gifted developers never had an issue with this.

          I think people just hear the meme about git being hard somewhere and then use that as an excuse to never learn.

            • Because a commit should be an “indivisible” unit, in the sense that “should this be a separate commit?” equates to “would I ever want to revert just these changes?”.

              IDK about your commit histories, but if I’d leave everything in there, there’d be a ton of fixup commits just fixing spelling, satisfying the linter,…

              Also, changes requested by reviewers: those fixups almost always belong to the same commit, it makes no sense for them to be separate.

              And finally, I guess you do technically give up some granularity, but you gain an immense amount of readability of your commit history.

              • Eiri ( Eiri@lemmy.ca ) 
                link
                fedilink
                arrow-up
                1
                ·
                1 year ago

                Huh. Never thought of it that way. I was never bothered by a long commit history at all. Search and filter tools in the git client always get me where I want.

                The one issue I have is when there are way too many extant branches and the graph takes up happy half my screen.

                But that’s more of a Fork issue than it is a fundamental one. The Fork dev could conceivably find a solution for that.

                Either way, I guess I see what you mean. I’m just not that strict about commits. Commits just for the linter aren’t a thing since we have a pre-commit hook for that, and typo-fixing commits… Well, they happen, but they’re typically not numerous enough that I’d find them to be any sort of issue.

                As for whether I’d really want to revert a particular change – while I work, yes. Afterwards, I see what you mean; i could probably squash 50 commits into 15 or something. But when I think about the time investment of reviewing every commit and thinking about how they ought to be grouped together before making my merge request… I have a lot of trouble convincing myself it’s a good time investment.

                Maybe I’d think otherwise if we had a huge team. We have maybe 10 devs on this project at any given time.

          • Mr. Satan ( mr_satan@lemmy.zip ) 
            link
            fedilink
            arrow-up
            2
            ·
            1 year ago

            I’m the opposite. I just let git take care of the stupid content. Why mess with the commit graph? Merging locally (instead of squashing) works better with merge requests because the graph clearly shows what changes went where.

            I do some branch maintenance on my local branch (rebasing) until there are conflicts, but other than that I don’t see any benefit for messing with commit history.

      • Eiri ( Eiri@lemmy.ca ) 
        link
        fedilink
        arrow-up
        1
        ·
        1 year ago

        Hmm, I’m less afraid of force push. It does what it says on the tin. If I pushed a fuck-uo to remote and a reset is the simplest way out, you can bet I’m force-pushing that reset.

      • Eiri ( Eiri@lemmy.ca ) 
        link
        fedilink
        arrow-up
        1
        ·
        1 year ago

        I don’t understand it. Every time I see something about a rebase it’s some purist telling me it’s “cleaner”. Never got it to do what it says on the tin, and never hit a situation that I couldn’t solve using more straightforward tools like merge.

        • What’s your mental model for a Git commit, and a Git branch?

          Once I properly learned those two concepts, understanding rebases became a lot easier.

          I’ll try to explain it to the best of my abilities.

          • Think of a commit being a patch - a description of how to take a particular file from one state to another
          • A branch is a list of patches to be applied in order, from the point where the branch was created until the last commit on the branch

          When you rebase a particular branch, what you’re essentially doing is taking all of the commits that are currently on your branch, checking out the other branch, and then applying each of the patches in order on that new branch.

          A rebase can be cleanly applied if the premise for each commit has not changed when applied, but if the premise has changed, you get a conflict to be resolved before being able to continue the rebase.

          I mentally model a rebase a bit as a fast version of how it would look like to build the branch I was on, but on top of the branch I’m rebasing on.

          • Eiri ( Eiri@lemmy.ca ) 
            link
            fedilink
            arrow-up
            1
            ·
            1 year ago

            That’s a good explanation of what it’s supposed to do. That was how I understood it as well.

            But anytime I’ve tried it, I’ve ended up with conflicts where there shouldn’t be (like, I already solved that conflict when I merged earlier) and/or completely undesirable results in the end (for instance, some of my changes are just NOT in the result).

            So I just gave up on the whole feature. Simpler to just merge the source branch into mine.

    • Even if you rebase you can still recover the original commits until they are garbage collected. You are generally safe as long as the .git directory isn’t deleted, in which case your whole history is gone anyway.

  • ranzispa ( ranzispa@mander.xyz ) 
    link
    fedilink
    arrow-up
    1
    ·
    1 year ago

    The main reason I use git is it allows me to make mistakes without hard consequences. Any fuckup is just one reset away from being fixed. I like to: I have to fix this thing. While attempting to fix it I discover there is another thing that needs fixing on which everything revolves. I fix the second thing and commit. I’m now free to fuck around the code all I want and I’m sure I won’t lose that fix.

    For this I really like to use --fixup when I find out the change was not completely right or does not fit well with some other changes I need to do. I really like git absorb which automates this a bit.