Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I'm teaching Git in University.

For all those who think that Git is easy, it's not.

It takes a student about 20-30 hours to really understand all usual Git commands. I'm not talking about something bizarre like ls-remote, but really understand merge, rebase, bisect. Not just syntax, but all the consequences. For instance, why rebasing something already pushed to public often leads to false merge conflicts, how does stash really work, etc.



If you’re including rebasing, then I can believe this (rewriting history is nuanced and complex), but I’m not sure I’d be teaching that straight away. My recommendation is usually only to start using rebase once you’re already very familiar with the rest of git, since it’s almost never necessary to achieve what you want.

Also, bisect is definitely not common, and the vast majority of my colleagues wouldn’t know it exists; I’d place it into the look-it-up-if-needed category.


I’ve used git successfully professionally for almost 10 years and I’m not lying when I say I’ve used rebase about 5 times. We just merge. We squash sometimes. I think it must be because I’ve always worked in smaller orgs but rebase just seems to always be over complicating something simple (a merge). I get that there’s a benefit of a cleaner history but to me the benefit of simplicity merge offers makes it superior


Done right and understood, it is as simple as merging, if conflicts arise no difference to conflicts via merge?

But you get rid of those ugly merges back and forth and unviewable histories.. Not sure why not more people care, I guess it is a little OCD I do that for my stuff.. however the 20-50+ user projects where everyone, often multiple times merges develop or even other branches in.. really unusable history right away, lets not talk about any point later. Git has derailed to a mere backup system where you can jump back, but understanding changes later becomes impossible :(

What people also rarely know: A linear history is without lies, but one can sneak additional changes into a merge commit that was in neither branch quite easy - I hate that!


> Not sure why not more people care

Most people don't care about most stuff, it's pretty normal.

But here specifically: Most developers don't read code, nor documentation, and essentially no one reads commit messages. VCS is a WOLM - write-only linear memory - to most developers. That's probably also why most people don't care to write any kind of reasonable commit message - the software requires them to input something, so something is input - and also do not care about unreadable (and also unusable) VCS histories. They're never looking at it, it's only written. Hence it's meaningless for them if it is extremely difficult to trace changes or hard to bisect, they don't even attempt such things. There's a reason the history browsers in all the online tools and IDEs effin suck, it's because on average nobody uses history.

I know, I know, this gets across very elitistically, but it's just how most people do their jobs. They get bugged to do a thing, so they sort of do the thing in order to not be bugged any more about it. I'm pretty sure that caring for these things is some kind of OCD like you say, i.e. a mental disorder.


My biggest issue with rebase from a learners perspective is that you get conflicts that simply don’t happen with merge.

I’ve had experiences where I’m trying to rebase a branch and it keeps flagging my most recent changes in the rebase when the intention is that I want all previous changes applied then as a final step show me a conflict if applicable, don’t show me one when it’s not the “final” step.

Admittedly maybe I’m doing it wrong.

I also don’t like how rebasing “main” onto my branch actually seemingly takes my branch and rebases it onto “main”? Maybe that’s a fault in my IDE not entirely sure


I think the difficulty with rebase and merge is much about semantics. When you "rebase" what does that word suggest to you? To me it sounds like "Base Again". So I'm changing the base from which I started the current branch to something else?

Not quite. That would mean that my old base is REPLACED by something else, right?

Instead rebase means take some other branch then put all the changes in the current branch on top of it, keeping everything in the current branch but just adding them on top of something else, right?

It grokked with me when in my IDE (WebStorm) I saw the menu-option allowing me to choose another branch and perform "Check Out and Rebase on top of the current branch". So you don't just "rebase a branch", you combine two branches. And when you combine two things here the order matters, and it is easy to confuse the order.

Similarly if you merge two branches, which one overrides? The left or the right operand? It is easy to get confused. Maybe I am. It is not my fault.


It does not help that git really is checkpoints rather than deltas. The semantic difference is usually ignorable, but it can matter when you're trying to rewrite history. It's coming up with deltas on the fly, and if it gets confused it can get very very lost.

Every rebase really is at least three branches: what you're merging into, where you started, and where you are now. And God help you if somebody rewrote history on any of those.

The fact that all of these have terrible names makes it so much worse.


In my org we require all important data to be listed on a pull request, then enforce squash merge. If you have multiple distinct changes you want reflected in the history then you make multiple PRs.

This makes bisecting a lot easier too.


I really wish git bisect understood merges better, so that you didn't have to fake it with squash.


"enforce squash merge" == "pretend Git is Visual Source Safe or CVS"


I use rebase essentially every working day. I use rebase for managing my local tree of patches, regardless of interaction with colleagues. Merge is fine, I guess, but do you never get the order wrong and want to reorder things before you push? Or keep moving around some local debugging patch on the top of your stack, without pushing it to your colleagues?

IMO merge is almost never what you actually want, unless you've been working separately for a long period of time (and generally you should not being doing that because it leads to surprising conflicts / regressions at merge time).


It depends what you mean by separately. Big organisations can have dozens of teams implementing unrelated functionality with asymmetrical overlaps for conflicts. I've never found a situation where rebase was appropriate for this kind of setup.


If the functionality is unrelated, I'm not sure why rebase would be inappropriate. It just wouldn't matter much other than keeping history clean (and rebase would make for cleaner history than merges).


What is the benefit of this to isolated teams? Rebasing a shared main that is under a constant stream of PRs is tedious and time consuming. What is the justification of this in terms of time spent for a company paying for that time? How is that time recouped via the availability of a linear history?


I always rebase from an up-to-date main/master before pushing my feature branches. So much easier to deal with than merging after the fact.

But yeah, after that initial push, it's just merges from there on out.


Git merging is completely stupid. It collapses multiple changes into a single commit. The original chain of commits is referenced, but in a useless way that only complicates the git history.

When you merge 17 changes from foo-feature into master, master has only a single commit. You cannot bisect master to determine which of the 17 broke master.

The 17 commits are there, but only in their original form, based on some old commit. Those 17 original commits are not equal to the single merged commit. The single merge could have a bad merge.

If there is going to be a bad merge, it's better to have a bad merge in one of 17 commits being individually rebased, than to have a bad merge in a single merge bomb that conflates 17 commits.

Your little branch of the original 17 commits should be purely a private object; it does not belong in the upstream. It's just a historic accident that your work was originally based on some three-week old random commit that happened to be latest at the time when you started. There is no need for that to be published. Your job is to make sure your code is based on the latest commit and promote it to the branch, as a sequence of individual changes (which all build and pass unit tests, etc).

I've literally not typed "git merge" since 2010, and around that time I learned how not to have Git perpetrate unwanted merges on me by learning never to type "git pull". "git pull" can be configured to be "git pull --rebase", but you will forget. I trained myself to do "git fetch", then "git rebase".

In all my last three jobs, the review tool Gerrit was used. Gerrit is based on cherry picking, which is rebase. Commits are submitted in their original form (not necessarily rebased to the target branch, but indicating which branch they are for). When approved, they are submitted and that means cherry pick. Maybe Gerrit can merge; I've never seen it used that way. Gerit has rebase right in the UI. You can take a commit and rebase it to its logical parent (latest patch set of an apparent parent with which it had been submitted together), or to the current head of the branch.


FWIW - I've worked with both rebase workflows and merge workflows. If you rebase a long lived branch what breaks is /your/ code not the rest of the codebase in a rebase workflow vs the opposite being true with merges.


It highly depends of culture of specific team. I've seen teams obsessed with "clean" history, rebasing and squashing everything they possibly could. I believe it's a matter of taste, I never understood the argument.


squashing is a form of rebasing, albeit a narrower and simpler case. Indeed I do not understand why rebasing is so popular instead of merging when you're going to squash at the end anyway.


You have to fix conflicts either way so what's the difference? I suppose when merging you only have to fix the cumulative conflicts, while when rebasing you have to incrementally fix the conflicts introduced by every commit which is annoying. I usually squash a branch (rebase on where it diverged) before rebasing to fix this.


It’s worth configuring rerere (reuse recorded resolution): https://git-scm.com/docs/git-rerere for merges and rebases, because repeated rebases or merges of similar code will become substantially easier.


> revere

Innocent typo but for anyone else reading, it’s “rerere”.


Thanks. I still had time to fix it, so I’ve corrected it. I had typed rerere, but autocorrect "fixed" it for me whether I wanted it fixed or not.


After rebasing you basically have two versions of the same commit, and that is the root of the problem.


> After rebasing you basically have two versions of the same commit, and that is the root of the problem.

No, you have two commits. Git commits are snapshots, not diffs. Git's data model is simple. The fact that people do not bother trying to understand it is the root of the problem.


I never stated otherwise, IDK what are you not agreeing with.


Why is this downvoted?


Rebase got a lot less annoying now that git has gained the update-refs ability. I'm often working on multiple branches simultaneously, and update-refs lets me easily work on them as a stack.


How do you use it? It sounds (from the manual page) like it just changes what a branch points to... so how is it different from "git reset --soft"?


Here's how i use it: I call my HEAD "bl-dev". Let's suppose I have 5 commits on bl-dev that aren't on main. Each of those commits is a branch with a functional name. If I type "git rebase --update-refs origin/main" all 6 branches get updated, not just bl-dev.

Let's suppose the next thing I do is add something to the bottom of my 5 branches. I dont switch to the branch, I stay on bl-dev and add a commit to bl-dev. Then I type "git rebase --update-refs -i HEAD~7" and move the commit up in the stack to the correct location and again all 6 branches update.

"git rebase --update-refs -i" also gains the ability to change which commit any branch points to.

I don't actually type "--update-refs", it's a gitconfig.


At my last job, every branch has to be rebased before merge, leading to an incredibly clean history.


I don't know how successful of a metaphor this would be for students, but for developers who haven't had any familiarity with DVCS that I have worked with, I use a coat-rail analogy with some success:

You start with a "main" rail of coats. Each coat is given a number, indicating what order it is in.

You start adding coats to a new, empty, rail, using the next number. When you are done collecting coats on this new rail, you want to move your coats onto the original rail.

In the time it has taken you to collect the coats onto your rail, someone else has already added coats from their new rail to the end of the "main" rail, and they used the same base number that you have - which means you cannot just add the coats from your rail onto the main rail, else the numbering would be broken - we call this a conflict. (NB: There is a magic guardian of the rails that means this just cannot happen, which is a plot device that is just to make this metaphor work so don't question it, it's just a metaphor.)

To resolve the conflict you have the following "rebase" options:

- Slide all of the coats on the main rail up to make room for yours, and update all of the numbers on your coats, using the new number from the last coat as the base number for your rail's sequence. This ensures that everything on the main rail is "before" your rail. This is the equivalent of a rebase. After this, you can then put your coats on the end of the main rail without conflict.

- Then there is the option to take a copy of the main rail onto the front of your rail, and organising the coats one-by-one (much like in the above), placing your coat(s) in between some of the new coats on the main rail, then forcibly replacing the main rail with your updated rail. This last one is just as drastic in reality as it sounds in this metaphor. We call this the "interactive rebase" and it is rewriting history for anyone who has used the main rail before.

- Finally we have a merge which means adding one big magic coat at the end that takes the coats from both rails and combines them in a singularity, with the new base number being Hawking's radiation or something, I dunno. The metaphor is no good for merges.

(Truth be told: the entire metaphor started in my head some years ago with just the visualisation of that distinct coat rail sweep noise to squish the garments on the rail to onside to fit what our main protagonist is holding onto the rail, the rest I just back-filled over time)


If you teach all the concepts of Git (e.g. commits point to parents but not to children or branches are labels that point to a commit) properly it takes some time but then you get a lot of the more advanced things such as rebase kind of for free. In my experience, people often struggle with those because they have no clue how Git internally works. I had the same problem but when I looked into that it clicked and suddenly all the commands made a lot more sense.


Using rebase is crucially important to anyone who is ready to start using git to track a remote repository and produce new changes to be pushed must learn about rebase. You have to use rebase to rewrite your unpublished commits over the latest upstream in order to be able to push a fast-forward change.

Many new users of git don't have the luxury of learning how to use local-only git with no remote.

Now rebase is a farm implement: a mechanized cherry picker. Cherry picking should be taught first, and then rebase explained in terms of being a multi-cherry-pick operation.

Before teaching cherry picking, you have to teach that Git is based on snapshots and not deltas. Git cherry-pick is part of tooling that is inside Git, but external to its snapshot-based storage model. When you cherry pick some commit into your current branch, the tool finds the common ancestor between your branch and that commit. It then does a three-way diff using the files in the cherry-picked snasphot, your own branch snapshot and the common ancestor-snapshot. The three-way diff operations produce a merged version that becomes a new commit: another snapshot.

If I ran a class on Git, we would spend part of a lecture doing manual merges with the diff3 utility: I would have the students take some ancestor file and make a "my" and "yours" with different changes, and merge these with diff3. We would go through conflict markers and all that.

Old time hackers who used other version control systems before Git knew all this stuff already. The first time I encountered conflicts, I already knew how to resolve them. Just a few git concepts were new like having to add resolved files to the index.

Imagine you know nothing about version control. Words like "unified diff" ring no bell. You've never seen conflict markers. You've never applied a patch or produced one.


> bisect is definitely not common

Agree.

> I’d place it into the look-it-up-if-needed category.

Disagree. Bisect is so useful in so many different scenarios that learning about it and the basics of how to use it is a great way to get people into git. Obviously not right at the beginning of their learning curve but as soon as the basics have been covered satisfactorily.


I wish more people would know about bisect mainly because they’d design the toolchains to actually support testing when you’re doing bisect.


I see bisect as a git superpower. Also grep (with rev-list). It's like knowing regular expressions. Not that one writes regexps every day, but this knowledge/skill definitely uplifts one to the next level.


I basically have to relearn regex's almost everytime, yeah it's a bit easier each time, but I still have to go back through some basic examples to get those old neurons stirring.


> I’d place it into the look-it-up-if-needed category.

Knowing how to use git bisect is what elevates a programmer to the next level. Just understanding how it works gives you a new way to reason about bug finding and fixing (or feature development using old and new), and then actually using it can make you a bug fixing master.


It feels like a weird and magical superpower but realistically I find use for it about once every 6 years and even then I'm fairly sure I could have done without it.

This was not my impression when I first learned about it. I thought I'd be using it all the time.


> and even then I'm fairly sure I could have done without it.

Just understating how git bisect works is the real superpower. The tool is a nice add on, but often you're right, is easier to bisect by hand by going to a known working commit and then doing a smart bisect based on the code you think might be offending.

But at least knowing the concept of bisection is a huge game changer.


I'm pretty sure every programmer learns about binary search near the beginning, and even without that has searched through some alphabetical listing without starting at aardvark (if not, I'd argue they have zero hope at much of anything abstract).

Really feels like a stretch to credit git, of all things, with that fundamental understanding. It's like saying you need to operate a nuclear power plant to understand the benefits of locking doors.


When people search through alphabetical listings, they usually don't use plain old binary search, but instead use something like interpolation search. For example, if you want to find the word "xylostroma” in the dictionary, you aren't going to start in the middle. Instead, you'll start about 90% of the way through, and then make adjustments based on how far off you were.


Yeah but that is only optimal if you know the general location. Often when you have a bug you don't know where it snuck in, especially if it's something like a race condition.


Sure. My point was just that contrary to what programmers typically think, people don't use binary search to look up things in a dictionary.


I don’t disagree, and I personally use it, but it’s a decent distance from teaching students the basics of git. I’d bundle it into a group of tools that are useful to know the existence of, and look up the docs when needed.


Rebase is used for many things in a lot of workflows. I use it probably 30 times per day in my job.


I don't think Git is easy at all.

But 20 hours seems a worthwhile investment to me for something they will likely use for at least the next decade of any serious work with software? I'm assuming that this doesn't mean literally 20 hours of instruction.


There are a lot of people who could benefit from git (or who are forced to interact with it sporadically) for whom this is a real problem.

The problem is also, if you don't use it daily git knowledge decays fast.

There is a piece of advise that was making the rounds (unironically) at the research institute where I worked before: "Before you do anything with git, first make a local backup copy."


That’s the idea behind https://xkcd.com/1597/ and it’s more true than people will admit.


Can't agree. While learning git isn't trivial it is still easier than it was learning Subversion and at all places I have worked at a decent share of the devs understood git. If a dev cannot grasp git I would not trust them with any non-trivial code base.


Nobody claims that git is impossible to use. It clearly isn't or it wouldn't be so successful.

But it could demonstrably be better and easier and we are stuck in a local minimum of a good enough solution because of the network effects.


you mean merging branches? because in all other aspects, subversion is significantly simpler and i would say far better UI. Much of this also comes from not being distributed


Many more people use git than just developers. Especially with GitHub in there.


It really isn't.

git stash is the equivalent to saving your work somewhere else and getting a fresh copy.


No it's not. The recovery strategy when you've gotten your repo into aess is "wipe, clone, restore local backup, try the git thing again".

But even then, what's the benefit of using a strange git command, which means I have to track another bit of state only visible to git, which can easily be misused (by applying the stash to the wrong commit), and anyway doesn't save the actual working directory I care about (untracked files), over simply making a file system copy?


The benefit of using a strange git command would be learning what a strange git command does and then it's no longer strange. You'll learn how to create, read, update, and delete that new bit of state in git. Then you won't have to wipe, clean, restore local backup, try the git thing again.

You can start saving your work somewhere else, getting a fresh copy, and then try that git thing again when you know how git stash works. What you're proposing is like not learning how an incremental compiler works and suggesting to wipe, clean, restore local backup, try to compile the thing again to fix compile errors every time you have a compile error instead of learning how an incremental compiler works.


The problem is that git alternatives which achieve pretty much the same so not take 20 hours to learn. A lot of those 20 hours are spent because git has a poor UX and a poor execution model which almost requires understanding it’s underlying working and data structures to be able to use it effectively.

There’s several alternatives where you can be as effective if not more in a fraction of the time. The one that I preferred was mercurial, but unfortunately since GitHub was so successful we are all forced to learn git.


I share your sentiment and opinion.

Gitless looks, feels and smells like Mercurial (hg), which is simpler and more effective.

It only took everyone 18yrs to realize it (sarcasm).


What do you mean by 'more effective'?


> But 20 hours seems a worthwhile investment to me for something they will likely use for at least the next decade

Yet most people just want to use VSCode and don't want to invest 20+ hours learning emacs or vim


I used vim for 30 years by now, 15 of those it was my main text editor/IDE-like. I was one of those who would spend hours on achieving the perfect configuration and mix of scripts. I was one of those who thought smugly "I'm so much more productive than those idiots using Eclipse or Sublime".

But you know what? I moved to VS Code a few years ago and my productivity only increased. Everything is more intuitive and discoverable. Everything just works with no tweaking. All the convoluted macros and text manips I painstakingly crafted and memorized in vim are achievable in a few clicks in Code.

Spending 20+ hours learning emacs or vim is quite literally a waste, it's time we all admit it.

(I still think one should learn the basic cursor keys and how to save/quit in vi because sooner or later you'll have to edit something on a remote server with only vi. But learning emacs is still completely useless, though.)


> Spending 20+ hours learning emacs or vim is quite literally a waste, it's time we all admit it.

For me, with my ability to learn at the rate that I do, Emacs provides the best solutions for Git (Magit), email (mu4e), calendar (Org), to-do lists (Org), note taking (Org) and more.

And I don't use software like mu4e because I already use Emacs; I use it because I have installed and evaluated dozens of email clients over the years and concluded that mu4e is the best for me given my requirements.

For people who aren't as particular about the software they use, Emacs may very well be "quite literally a waste".


Yup. I couldn't ever use Git without Magit. The nice part about Magit is that it's already a very discoverable interface and, like Gitless, it just runs git commands asynchronously, so you can inspect the exact things Magit is doing. Yet it's very painless to blame, rebase, squash, cherrypick, ... compared to the Git CLI and other graphical tools I've tried using in the past (mostly the built-in Git interface of IntelliJ).

Given the poster mentioned using Vim for 30 years, I assume he is blindly lumping in Emacs because I've never had to maintain macros or text manipulations -- smartparens and the built-in text yanking features have been sufficient for refactoring code and structural editing.

Most of the things I do with Emacs, people will claim are doable with tmux and a dozen assorted shell utilities, which IMO is just false since you don't get any user interface or convenience close to e.g. Magit, TRAMP, notmuch, eww, and so on.

For instance, one of the supposed benefits of Vim is that you can SSH into some box without your editor of choice installed and still edit files. Why settle for such an experience when TRAMP lets you stick with your current editor, with all of its configuration and plugins, to modify files remotely?

Likewise, notmuch is very good at organizing threads across several mailing lists, whereas Thunderbird has needed me to Google dozens of questions, click lots of buttons to set up filters, and still end up with nothing better than a flat list of e-mails in my inbox.

Since my post is getting long, I'll lastly mention eww is great for browsing things like Javadoc, Codox, the Common Lisp HyperSpec, and other statically-generated HTML documentation.

The most time investment I've needed into Emacs was essentially

  sudo port install emacs-app
Then asking a friend to guide me through installation of a few packages. I don't use distributions like Doom or Spacemacs, and the last time I modified my init.el was apparently 2022-05-13. I got into Emacs in 2020.

I've tried time and time again to try using VS Code so that I can help some friends get into programming languages like Clojure, but I always find myself spending 30 minutes searching how to do things I take for granted in Emacs, like automatically indenting code as you type rather than manually hitting "Format Document" or creating a save hook running that function.


I have to ask: Did you just quit Vim the editor or also Vim the keybindings?

Because I can totally see not using the editor, but the keybindings, even the basic ones every emulation plugin manages to do well, are such a big win it's hard for me to believe I'd ever give those up.

Also, at least from my perspective, VSCode and Neovim are eye-to-eye, in the sense that both get most of their magic from interfacing with Language Servers, which both do very well. Though even the more approachable Neovim still seems to have a fetish for configuration/a hatred against sane defaults.


I spent hours using emacs as well, and then moved to VSCode. Everything's just so much faster in VSCode because 1) there are more plugins and 2) I can test and quickly learn plugins.


Not at all.

There's nothing out there as configurable and portable as Emacs.

Easier, sure.


I don't disagree, but I think a followup question would be "how configurable do you really need your text editor to be?"

Don't get me wrong, I'm all for tinkering with stuff and customizing to oblivion, it's fun and cool, but realistically how much better of a JS engineer are you going to be if you've customized the hell out of Emacs? Maybe a bit more, I'll concede that, but fundamentally I don't think it's going to be categorical.


I have no idea, I'm a software developer, I write code in whatever language I need to and Emacs is always there to support me.


Interestingly, the features of Emacs, Vim and VSCode are largely orthogonal (on top of any basic text editor). Further, a lot of people advocate using CLI instead of most VSCode features. Waiting for the holy grail, you can still learn from each:

* Vim key bindings for text edits

* CLI commands for Git

* Emacs modes such as Magit and org-mode

* VSCode for tight Typescript integration, nice block structure visualisation etc.

I hope some editor will combine this all. (I think Emacs will be best placed to achieve this with its extension ecosystem that already includes Magit, org-mode, evil-mode etc.)


VS Code already has extensions for all that.


VS Code doesn't have anything comparable to Org mode. The "VS Code Org Mode" extension[1] has maybe 1% or 2% of the features of Org mode for Emacs. Go read Org mode's manual[2] from start to finish (134,062 words) and then direct us to an extension for VS Code that has comparable features (e.g., plain text spreadsheets).

[1] https://github.com/vscode-org-mode/vscode-org-mode

[2] https://orgmode.org/org.html


I've tried org mode several times and I think it's both overkill and not something most people would benefit from considering the time investment needed.


Fair enough! I don't use it so wouldn't know.


VSCode has a long list of me-too features and extensions but in my experience, not many are of great quality.


What's your point exactly?

I spent a lot more than 20h learning emacs. It was my main editor for years.

I use VS Code now. It serves me very well.


> I spent a lot more than 20h learning emacs. It was my main editor for years.

Yeah same, are people saying 20h commitment is a lot now ? Not sure if I've gotten old, or if things are easier to learn now - but a 20h commitment seems like very lite.


(1) If I can spend 20 hours learning something boring or 20 minutes learning something else boring but they do the same thing I would prefer 20 minutes.

(2) There are more tools to learn. That 20 hours/minutes is being multiplied by an ever growing number.


Thing is, git is pretty much everywhere. I don't think I've had a single job in the last 15 years or so where the client or employer wasn't using git. 20h to learn a tool that will be used daily for decades (yes, I expect this trend to go on for at least another 10-30 years), and the choice is not mine to make, is not much.

I should say, if the choice was mine, I'd probably still choose git. It's powerful, it's something I can already make really good use, and I feel comfortable easing new people into it. Regardless, the point is that I don't have that choice as an individual who's part of a team or an organisation.

On the other hand, I can choose my code editor without interfering with my fellow engineers's own choices. Here I chose the one I could learn in 20 minutes and get better the more I used it.

It took me very little time to get productive with VS Code, and then a few more days to get used to most shortcuts I use. Everything else is accessible via the command palette and more shortcuts can be learned as their functions become used more frequently. Until that, the palette is an excellent interface. It also serves as a discovery mechanism for features.

With emacs I had to learn a lot before I started getting productive. I got very good at it. Multiple cursors, window jockeying, buffer wrangling, the works. Any functionality that fell in disuse for some time, I'd risk forgetting their shortcuts. If I did, the only way to use it would be to somehow remember the shortcuts, probably by interrupting work and googling, or by trying to navigate its archaic menu systems.

With vim it's not very different. I still use it more or less daily but mostly for single file editing over SSH, since even if I need to do more complex editing on a remote server, I can use my local VS Code.

I don't think people have to use VS Code. I work daily with other engineers who use it, but also any of the Intellij editors, vim, emacs, you name it. We can all live in harmony and collaborate just fine. Not so much if each would chose their own VCS.


> Yet most people just want to use VSCode and don't want to invest 20+ hours learning emacs or vim

To expand upon this, for version control there are pieces of GUI software that can allow you to handle the typical workflows without touching the CLI. Packages like Git Cola, GitKraken and functionality that's bundled with most IDEs as well.

In addition there are also platforms like GitHub, GitLab and Gitea which will let you easily get changes merged across branches with either a single commit or different strategies, all with the press of a button.

I don't think that there is a reason for everyone to do a deep dive into Git, aside from their own curiosity, or when using complex workflows.


I've been using Vim (well, neovim now) for a long time, it's my primary editor, and I think I'm reasonably good with it, but I really don't think I'm appreciably more productive than the average VS Code user.


"EMACS is not hard, you can learn it in a day… Every day."[1]

[1] https://www.youtube.com/watch?v=urcL86UpqZc&t=325s


The thing I like about Emacs is: there is always another 'prestige level' for you to strive for, because you will never master everything. You get better, and better, and better ... positive feedback, increasing ability to get stuff done.

win win.


That doesn't mean that learning Emacs would not be worthwhile, it just means people don't do it.


When I teach students git I show them init, status, add commit, diff, and log. That's all I focus on for several weeks.

That's enough to track changes to your own projects, see the benefit of tracking what you've changed, and build the habit of commiting frequently. IME, adding anything more about remotes and branches is overwhelming to the point they don't bother with git because they aren't going to distinguish the fundamentals from those more complex features.

Obviously branches and remotes are vital in real development, you just can't expect them to learn it all from the start.


Git is not easy, some concepts are confusing especially for newbies. I wrote a simple intro on how git works https://git-help.com


Students have to understand the concepts first, then the commands.

Many of the commands don't make sense, and many of them are dumb implementations, which wouldn't be done that way in a clean redesign of git, even if it were based on the same storage model and concepts.

Some of the commands are essentially tooling that is external to the Git storage model and emulates delta-based version control on top of the native snapshot model. The commands lead to fundamental misunderstandings such as that commits are changes.


I've used 20 or 30 git commands over 8 years or so. Many on a daily basis. I haven't gotten around to to rebase yet. It's definitely not essential.


No, definitely not, but if you start using it you can fall in love with it easy and suddenly find merging overly complicated :) I dread the merge workflow my colleagues do in a strange multi-repo-with-subrepos project - I just rebase all branches in all repos and find it even simpler and be happy and can still see my history at least :D


It takes hours to explain to some what variables are.


im gonna go ahead and say, that if it does that, they probably wont be needing something like git


The command line is really unintuitive. Like using 'checkout -b' to create a branch but 'branch -D' to delete one.


> 'checkout -b' to create a branch

Well that's actually "create a branch and then checkout that new branch". And you can use "git switch -c" if you feel the "checkout" verb is confusing.

The command to just create a branch is "git branch". Git branch won't touch the HEAD pointer, that's what switch does.

And if "git branch -c" were the command for "create branch and switch", it would be criticised in the exact same way: creating a branch and switching to it would be a different subcommand to that used for switching existing branches. Except now the branch command can also do "switchy" things to your HEAD pointer, but only sometimes (and the fact that checkout also only sometimes changed the HEAD is why switch was introduced).


What would be nicer is an interactive CLI interface for git. For example: "git switch <branch>", then if the branch doesn't exist, git asks you:

"Branch <branch> does not exist; create it? [y/n]"

To be fair, I've long used "checkout -b" and I don't think new branches need this, but it might be helpful in special situations like rebase/merge conflicts. I appreciate this sort of interactive CLI in other tools (apt, vite, etc.), versus having to look up the manual for the right options/switches. It's a different approach that might be more annoying to some power users, but is more friendly to most other users.

(This is also where GUIs are helpful, since they display most of the useful commands and options for you. Plus they can do things like see line history by commit and list your stashes for super-easy switching; GitLens/GitLess in VSCode do these.)


I really like using The Git Parable to help people understand the motivations behind Git. Remotes and staging seem really weird at first.

https://tom.preston-werner.com/2009/05/19/the-git-parable.ht...


I think git is fairly easy as far as data structures and such goes but the issue is that you need to understand it to use it well.

In the same way that you don't need to understand the inner workings of Google Docs, Git should be something you don't even have to learn. Sadly we're not there.


I often ask the difference between a merge and a rebase is in my interview questions. It is exceptional common that they cannot even describe it.

I typically use it as a barometer for how in depth the candidate tries to understand underlying mechanisms of tools they use.


This is the type of interview question I hate. You’re basically selecting for candidates who care about the same problems you do.


Yes, if I want to find someone to work with I certainly want someone that do care about not making a total mess in the VC history. Selecting for that seems like a very good thing, regardless of whatever else they contribute.


Exactly. Dig into what they know!


if the interviewee would be a direct report of the interviewer, I dont see the issue


Not an issue per se, but there are plenty of candidates who might not care about merging vs. rebasing but have an interest in other things. So many interviews consist of interviewers hoping you parrot their own worldview back to them. It’s not a good way to build a team.


I prefer rebasing (for the usual reasons). I have successfully worked with people who prefer merging (for the usual reasons).

I don't think I'd work successfully with people who don't care.


I don’t care. Why? Because it’s largely a meaningless distinction that has nothing to do with the goal at hand. It’s like eMacs vs. vim or tabs vs. spaces.

Another way of thinking about interviewing is this: you say you don’t want to work with people who don’t care about this problem you care about. That’s fine, I guess. But if you changed your viewpoint to “I want to work with candidates who care about interesting things” then you might find you ask more about what they care about and less about what you care about.


I'm with you. I don't care. I prefer merging but if someone insists on rebase + squash commit I don't care because it doesn't make a difference.

Sometimes I'll tell a rebase person that if they don't like merge commits they can use git log --no-merges and you won't see merges. The majority of people I come across who prefer rebase for "clean history" reasons don't know this.

If you truly understand the difference between rebase and merge you'll come to the conclusion that it doesn't matter what you use.


It's also exceptionally common that the difference doesn't matter in the slightest.

I'd file this question under "trivia the interviewer believes correlates with performance".


It's "trivia that would be difficult to avoid picking up as a professional software developer".

Like, asking what a for loop does wouldn't give you any real positive signal, but if they can't answer it's a strong negative signal.


It's super easy to avoid. You dont have to learn git's internal model to use it and it barely matters whether you use merge commits or rebase in 99% of code bases anyway.

You might as well judge people on how well they know xkcd comics or VIM keystrokes.


I don't get it. Why would you spend so much time on git? You can teach the core ideas in 2 hours, let them do some homework (4 hours?), and the rest they can figure out later. I don't see the value of understanding git in detail.


Pareto principle. 80% of the time all you’re doing is git add, git commit and git push.


I've been using git for twenty years and I still don't intuitively know what half the operations do. When my local tree fucks up, it might as well need open heart surgery, because I can fix my repo as much as I can perform that.


I've only taught git like two or three people. 20-30 hours is insane. Could it be that starting from the commands is not the best way?

Git is basically just blobs, trees, commits, and refs [0]. Four simple concepts. Yes the interface is confusing and I don't know it either, but things are easy enough to look up.

[0]: I love "fast intro to git internals": https://docs.google.com/document/u/0/d/1X5SnleaX4qpLCc4QMAMW...


You taught people with some sort of existing knowledge or advantage. This is one of those classic pitfalls that comes with experience - we forget how hard things were early on and/or fail to realize when something was “easy” because we had natural talent or passion.

It’s probably best to consider that something like git is _not_ inherently interesting and is more likely (subjectively) boring and tedious to humans who are comfortable with simple saving and undoing of files.


Rofl

Git is the only software where the need for learning its internals is recommended

It is a sign of huge failure of API design


The porcelain parts of git are terribly complex (though improving; especially if you just apply the config changes it suggests during normal operation).

However, the core data model is simple (it is a content addressable store, where each commit contains pointers, forming a directed graph; the pointers are unforgeable, so the graph is acyclic).


This meme needs to die. That is one tiny component of the data git touches when working with it.

There are many sources of interacting states, some internal to git, some not:

  the local tree of commits
  remote trees of commits
  a possible origin relationship between the two
  branch labels on each local and remote with possible relationships between them
  the HEAD label
  stash
  index/staging area
  the actual working directory
  .gitignore
A simple question like which files are being tracked is actually a complex result of several different places in the above. Untracking a file is consequently extremely non-obvious.


Each commit in Git contains a file tree. So a single commit is what’s needed to answer the question ”what files does this commit track?”, which is the only question about file tracking that makes sense to ask in Git.

Describing Git’s behaviour in terms of other version control systems’ semantics (e.g. Subversion or Mercurial) is not necessarily easy, but that’s not what’s being claimed.


That's incorrect. Git considers files tracked if they are in the last commit or staged. As far as I am aware it considers files untracked if they are not tracked and not ignored (though git clean -x documentation suggests that it considers such files untracked and simply ignores them when listing untracked files, which also makes sense). So un/tracked depends on last commit, staging area and possibly .gitignore.

> Remember that each file in your working directory can be in one of two states: tracked or untracked. Tracked files are files that were in the last snapshot, as well as any newly staged files; they can be unmodified, modified, or staged. In short, tracked files are files that Git knows about.

> Untracked files are everything else — any files in your working directory that were not in your last snapshot and are not in your staging area.

https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-...


And a monad is just a monoid in the category of endofunctors


Any tips for someone outside the industry wanting to up their hobby programming game? Basically just trying to avoid the Useful_Script_v2-Final-Final-ReallyFinalThisTime.py syndrome, and realizing the value of a dated change history.


My suggestion would be to not learn git. Go with just about any other version control system if you’re not using it professionally. I’ve used cvs, Subversion (svn), Perforce (p4), and others. Honestly, Subversion and Perforce were both significantly easier to setup, learn, and use than git. While they all have their growing pains, it took me about a week to get used to Perforce. It took me more like a month or two to get used to svn. I’ve been using git for years and still find it very hard to use and strongly dislike interacting with it.


I second Subversion - though only because it is the closest to an open source alternative to Perforce. Otherwise it has a bunch of problems, like three separate half-baked implementations for shelving and aside from TortoiseSVN every other GUI front end has been either abandoned or on life support with a bunch of bugs.

But unless you have to work with other people in places like github, etc, it beats having to bother with git - especially for games that have a ton of binary files (which, unlike what some people will tell you, you want to have both version controlled and in the same repository).

Hell, if you really want a DVCS go with something like Fossil, it is still much easier than git, simpler to setup (just a single binary) and has more features (wiki, bug tracker, forum, etc) that you will find useful anyway.

Though personally the best experience i had with VCS is with Perforce, at least in gamedev: check out the latest version, merge any local changes, make modifications in a changelist, shelve the changelist in case i want to stop working on something and work on something else, use the shelve to send a WiP version to a coworker to merge with his changes (or see if things work as expected) or for code review, etc.

Sadly Perforce seems to be bound in a company that tries to sqeeze it for all its worth, adding a bunch of stuff of questionable usefulness, etc. It'd be nice if there was an open source alternative to it that allowed for the same or very similar workflows, all the issues i had with P4 over the years (e.g. merges between streams) were due to how P4 seems to be implemented, not due to anything inherent in the workflows themselves. There is no reason for an alternative to copy all the bugs.


Hard disagree. Subversion is awfully complex compared to git.

Yes, Subversion is initially easier to learn and use than git. It's not easier to set up as it's client-server while git is fully local. Also Subversion is an incongruous mess.


Subversion's CLI is actually sane and much easier compared to the abomination provided by Git. Additionally, Subversion can be used entirely locally, without the need to deploy and configure any server application.

It seems that you are comparing apples to oranges. Building your own SVN server from the ground up can indeed require some effort. Doing the same for Git demands more or less the same level of effort on your part. So, I believe you are comparing building an SVN server from the ground up to something like installing Gitea or GitLab, or using Git locally.

Again, you don’t have to install an SVN server. Just run `svnadmin create REPONAME` and use the `svn` client to import your data into the repository.


You don't have to set up a database for Git, either, and it works entirely locally. Git init, edit or copy in some files, git add, git commit, boom you're done. Optionally add a remote, push to the remote, pull from the remote if needed. If you're working alone, as I do, this is about 95% of the Git I need. Occasionally I clone to a different machine, or use Working Copy on iOS.


So? You've just described exactly the what's achievable with Subversion. The only missing part is adding remote repositories.

> You don't have to set up a database for Git, either, and it works entirely locally.

What database? Subversion doesn't need any special database to work. Just the repository and its working copy. Both can be local and can be created with two commands.


You're just talking past each other. You were responding initially to another user saying Subversion needs a server, and you responded that it doesn't. A different user responded, thinking your statement meant that you thought Git needed a server.


I disagree (with your advice, not your experience). I'm a total amateur and use Git for versioning prose. It is the only SCM that I can easily use across multiple devices and platforms. I don't use it for complex operations, mostly clone, commit, pull, push, branch now and then. I taught myself to use it from the command line. I guess being curious and persistent helped me get to whatever minimal level of utility I have with it.


I like Perforce it is fairly easy to use.

If you want to go old school there is RCS or SCCS. GNU provides source code (for SCCS there called CSSC). Though *CS are per file not per logical commit.

IIRC Perforce actually used RCS under the covers for storing the deltas.


The main complexities of git really come when you start having to work with other people also editing the same files you are. If you're just doing a solo project, you'll likely be mostly on a single branch, maybe a handful of others if you're experimenting a lot. In that case, you largely just need to know add, commit, push, checkout, and can largely ignore the complexities of merging and rebasing.


You only need to understand {init,commit,diff,status,push} to use git. When something goes wrong you can delete your .git and start new. This obviously not what you want when you have a codebase with collaborateurs somewhere public accessible, but its fine to get used to it.


Telling someone to "delete your .git" is actually TERRIBLE advice. This should never be necessary unless you go screwing around in .git and break internals. It has a high probability of causing irreversible data loss. It's exactly the worst habit to build if you want to start collaborating.

If your repo ends up in a weird state, learn how to fix it. It should not be terribly complicated, especially if there is no rebasing happening.


That's only true if you don't want to undo any changes. What's the easiest way to get back the previous version of function foo() in file bar.py if I already made other commits to the same file, and want to keep those?

Keeping a "bar copy(2) final working.py" file is not about having a nice looking timeline, it makes it very easy to get back to a working state. All you need is copy and paste, or keep the working function as a comment in bar.py. You can see your working code and know you're not messing with it when you're experimenting with bar.py. I'm not saying that's the best way of doing it, but it's a very common use case that's not usually addressed in git guides, where it's all about pushing commit after commit, maybe branching, maybe pushing to a remote with others, but rarely enough focus on undoing mistakes after some experimenting if you didn't branch first.


> What's the easiest way to get back the previous version of function foo() in file bar.py if I already made other commits to the same file, and want to keep those?

You are operating under the assumption that foo() changes in a vacuum. That is an invalid assumption for lots of software changes.

Commits are supposed to contain one logical change each. That logical change may or may not cross function boundaries (often it will).

Reverting a commit should revert the logical change. That is how you accomplish what you're after in git.


I've seen so many people do the "select function body, copy, toggle comment, paste copy of function, try out ideas on this new version" workflow. I've done it plenty too in Matlab and similar during various labs at school. I'm not talking about best practice during software engineering, I'm talking about having the confidence your code can easily get back to a known good state if you want to experiment, like beginners should do a lot of.

And plenty of times functions are self contained enough that you can change the function body without changing other code as well.


The light bulb moment for me learning git, which I don't see get mentioned nearly enough, was this:

Stop thinking in terms of branches, and start thinking only in terms of commits. Pretty much every git operation makes so much more sense when you consider your repo just as a tree of commits (technically a DAG), rather that trying to reason about what it does to the branches. Branches are really just pointers to commits which can change over time, and most git commands don't really care about them.


I think you can immediately get value out of Git, even if you don't understand almost anything. Also there's a lot less footguns if you're not collaborating with anyone else.


Check out the book Learn Git in a Month of Lunches. It's exactly as advertised—only thing to keep in mind is that it was written before the master > main changeover, so depending on your local config you may need to swap that out when you're following along with its exercises.


Since you teach Git, I'm curious if you've tried https://ohmygit.org/ , and what your opinion of it is?


I taught myself Git in University. Over the course of a decade, I've taught Git to dozens of people. Sure, some people take more time than others but 20-30 hours sounds absolutely wild to me!


If it takes students with no background in source version control to really understand the usual Git commands in 20-30 hours, that's a huge success.


The goal here is to save my files, change things, and get back to my old version if that ended up being a bad idea. That's a simple request. 20 to 30 hours of learning for a big undo is bullshit.


They have background in IT


Honestly, “easy” is relative. Understanding software engineering is a study of 4 years, so having someone take a course on fit for 20-40 hours is literally half a week of proper studying and you’d know git. I don’t get why there are bootcamps for _only_ JavaScript CSS that take at least 8 weeks of hard work and then half of those to learn git and call it “not easy”. It’s the depth that we want to commit to understanding something that leads to people saying it’s not easy. Invest proper time into it and everyone (in sw eng) can learn git


> For instance, why rebasing something already pushed to public often leads to false merge conflicts

This sounds like obscurantism.

What bad thing happens if students just assume that rebasing something already pushed to public will cause merge conflicts, and just never do that?


I’m not sure it would be much shorter with some other version control program. Merges, rebasing and bisect are fundamental to what version control does.




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

Search: