Comment by lalaithion

Comment by lalaithion 2 days ago

34 replies

The disconnect between git's beautiful internal model of blobs, a tree of commits, and pointers to commits, and the command line interface is so wild. All of these recipes are unintuitive even if you have a firm grasp of git's model; you also need to know the quirks of the commands! To just look at the first one... wouldn't it be more intuitive for the command line interface to be:

    # this command exists already;
    $ git switch -c some-new-branch-name
    # is there a command that simply moves a branch from one commit to another without changing anything else? It feels like it should be possible given how git works.
    $ git move-branch master HEAD~
Certhas 2 days ago

The real "internal model" of git contains much more data/moving parts.

There isn't one tree of commits, there are typically at least two: local and remote

Branches are not just pointers to commits, but also possibly related to pointers in the other tree via tracking.

Stash and index and the actual contents of the working directory are additional data that live outside the tree of commits. When op says "avoid git reset hard" it's because of how all these interact.

Files can be tracked, untracked and ignored not ignored. All four combinations are possible.

  • lalaithion 2 days ago

    None of these seem to preclude a command to make an arbitrary branch point to an arbitrary commit without changing anything else.

    • karatinversion a day ago

      You are looking for

        git update-ref <branch-name> <commit-sha>
      • DiggyJohnson 17 hours ago

        Wouldn't the fail or break under any circumstance where they don't immediately share a history?

    • fragmede 2 days ago

      This works if the branch exists or creates it if it doesn't exist, but not if it's checked out.

          git branch -f branch_name commit
      
      if it's checked out:

          git reset --hard commit
      • seba_dos1 a day ago

        > but not if it's checked out

        ...and for a good reason that should be apparent to anyone who understands git's model (HEAD points to a ref in this case, so if you suddenly change what that ref points to without updating the working tree you create an inconsistency).

        You can do that manually of course (with `git update-ref` or even a text editor), but then you get to clean up the mess yourself.

neild 2 days ago

The "move a branch from one commit to another without changing anything" command is "git reset".

"git reset --hard" is "...and also change all the files in the working directory to match the new branch commit".

"git reset --soft" is "...but leave the working directory alone".

  • rav 2 days ago

    Actually, "git reset --soft" moves the current branch to another commit, without moving the index (aka staging area) along with it, whereas "git reset" (aka "git reset --mixed") moves the current branch AND the index to another commit. I really couldn't wrap my head around it before I had gone through "Reset demystified" [1] a couple times - it's not a quick read but I can strongly recommend it.

    [1] https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified

  • lalaithion 2 days ago

    git reset only works if you're on the branch you want to move, which is why every one of these example flows has you create your new branch, then do the reset, then switch to the new branch, instead of just allowing you to move a branch you're not on.

Terr_ 2 days ago

> The disconnect between git's beautiful internal model of blobs, a tree of commits, and pointers to commits, and the command line interface is so wild

Something I heard somewhere that stuck with me: git is less less of a Version Control System, and more of a toolkit for assembling your own flavor of one.

  • JadeNB a day ago

    > Something I heard somewhere that stuck with me: git is less less of a Version Control System, and more of a toolkit for assembling your own flavor of one.

    That's how it is in principle, but it seems to me that there aren't that many different CLI "porcelains" in practice. Kind of like how Knuth figured people would essentially write their DSLs on top of plain TeX, not spend most of their time in giant macro packages like LaTeX.

    • dragonwriter a day ago

      > That's how it is in principle, but it seems to me that there aren't that many different CLI "porcelains" in practice.

      I think that's because most of the people that make custom tooling to support particular workflows build it into graphical (including IDE extensions, web-based. etc.) frontends, not CLIs.

pitaj 2 days ago

I prefer just using `git switch` because it's easy to remember the flags (and the position of arguments), but you're right, there is a simpler way:

    git switch -c some-new-branch-name
    git branch -f master HEAD~
  • DangitBobby 2 days ago

    You should also be able to do

      git branch -f master origin/master
    • pitaj 2 days ago

      This doesn't work if your local master was already ahead of origin

      • DangitBobby 2 days ago

        Indeed, as with all of these examples exceptions will apply and, it's a good idea to check the log before taking any such action. I believe your example also depends on exactly how many commits you've made that need to be moved. In any case, it depends on me remembering exactly what `~` signifies.

jimbokun 2 days ago

Are there alternative git command lines that keep the beautiful internals, but implement a more elegant and intuitive set of commands to manage it?

  • dalia-reds 2 days ago

    Check out jujutsu or jj (same thing). It's its own VCS, but it uses git as a backend, so it works with GitHub and other git integrations

  • maleldil a day ago

    Another vote for jujutsu. No one else needs to know you're using it. You can think of it as just a different CLI for git (although you shouldn't mix them). I used to use third-party interfaces like lazygit, but I don't need them anymore because jujutsu _just makes sense_.

  • stouset 2 days ago

    Seconded jujutsu. It's 100% git-compatible and one of those rare birds that is both more powerful and simpler to use in practice due to rethinking some of the core ideas.

lilyball 2 days ago

The "move a branch" command is `git push .`. Yes, you can push to the current repo. I have a script called git-update-branch which just does some preflight checks and then runs `git push --no-verify . +$branch@{upstream}:$branch` to reset a branch back to its upstream version.

  • zahlman a day ago

    > The "move a branch" command is `git push .`. Yes, you can push to the current repo.

    Wouldn't that copy a branch rather than moving it?

rav 2 days ago

For move-branch: Use `git branch -f master HEAD~` if you're currently on another branch, or `git reset --soft HEAD~` if you're currently on master.

assbuttbuttass 18 hours ago

> is there a command that simply moves a branch from one commit to another without changing anything else? It feels like it should be possible given how git works.

git switch -C master HEAD~