And you can type "git br<tab>" to write "git branch", "git checkout fun<tab>" to write "git checkout funky-feature", "git log --na<tab>" to write "git log --name-only" etc.
Pretty much every time you press <tab> somewhere while writing a git command, it does the right type of completion. And hitting <tab> multiple times lets you toggle through the options. So you learn git along the way.
This was one of my most enjoyable productivity jumps when it comes to using git.
If you're on macOS, update your bash and install bash-completions and git. The path above is likely wrong if you're using a package manager: for MacPorts you want to source /opt/local/etc/profile.d/bash_completion.sh, and for Homebrew it's $(brew --prefix)/share/bash-completion/bash_completion (the install process will tell you what to use).
The very first factual claim in the article is wrong:
"The most basic usage is: git reset useful_func.clj
This will replace the useful_func.clj in the current working directory with the last committed version in the repository HEAD."
Not a good start. What it actually does is reset the path "useful_func.clj" in the index (AKA staging area) to the HEAD state. It doesn't touch the working directory.
It's not clear to me if the author actually understands how staging works and how that affects the commands they suggest. They claim that stashing takes staged changes and then note that after stashing the working tree will be clean. That suggests the post is being dumbed down or the author is misunderstanding things.
Git guidance should almost always start with a brief introduction to the concepts you believe the audience doesn't know or fully understand. To begin with reset and not properly explain the index will just end up being confusing, especially with brief references to hard, soft and mixed resets later on!
I see this so often with power user tools. All power user tools are tools that you can only use reasonably well with some basic understanding. They are made not to be understood in the easiest fashion but to handle all complexities of a problemset as efficiently as possible. Therefore it sometimes seems harder to use from the outside, but actually the hardness comes from the problem it solves, not the tool.
So yeah, if you really want to use git well, learn its internals. It takes some time but actually not even hard. After reading the Git Book once I was even able to implement my own git (of course without performance considerations).
One would idiomatically use “git checkout <path-to-file>” for the functionality described by the author: “get some file back to the latest version committed in HEAD”.
There's an article like this every week or so.. I don't get it. Git isn't that hard.. You can pretty much get by 99% of use cases with like four or five commands.
The proliferation of articles like this is a very very good indication, that, yes, git is that hard, especially if you have to collaborate with other people.
Everyone has a different idea of what git does, what things are called, and different interpretations of the vast git vocabulary. What is a rebase? What is a branch? What is a reset? People have different mental models for all of these things.
Git would be easier if it weren't for all of the git users you have to work with. If you're a git solipsist, you develop your own mental model that works for you and you never have to care what anyone else does when they are using git.
I got a lot of mileage out of git with "do work on my own individual branch, never use `--force anything` even if a blog post on the internet says to, and don't rewrite history."
Reading just enough of the git-scm book to get a basic mental model of staging, branches, and pushing/pulling from a single remote (aka the things new people actually probably trying to do with git) can serve you well enough. I've since worked on teams that expected WIP commits to be squashed, used multiple remote repos, etc, but the above should be all the git most of the people complaining about git actually need.
I feel like there are two big reasons git gets the rap it does separate from any actual interface issues:
1. People tend to mess up with a tool more often when they are still getting acquainted with it. When things get hairy, people tend to just try random fixes so they can get back to work which makes the problem hairier still.
2. git might be one of the first tools someone uses that expects end users to map their mental model to it rather than trying to fit their pre-existing mental model.
Specifying the remote and branch name again when doing a `git pull` is not necessary after you've set it as the upstream branch (which the `-u` option in `git push` did in your example).
To play devil's advocate, I purposely never use push/pull without specifying the remote and branch because doing otherwise would cause issues if I accidentally forget which branch I'm on (which isn't super uncommon for me, as I've unfortunately gotten so used to seeing the branch name as part of my shell prompt that I don't notice it unless I actively look at it). I believe there's even an option you can put in your .gitconfig to enforce this.
Sorry, but it seems like you've worked in very low skilled teams. There are sometimes two different solutions to a problem, but they come with different pros and cons and you need to decide which to choose based on balancing reasons, not based on having different understandings of how git works.
For instance, when you have lots of parallel work, you have to decide whether to merge-commit each into the mainline or wether to rebase them. The first is an honest view of what happened, but might be harder to read. The other is easier to read, but might not represent well what actually happened. Git doesn't work one way or the other. Both is fine for git. And you should also be aware what it does under the hood for both options.
It's not, but if you don't use it mostly every day, or if you decide to "Delete repository and clone again" every time there's a problem, you won't ever get to learn how to fix it.
The staging area is totally unnecessary IMO. I think git would be easier if we didn't have it.
The term `checkout` is multiplexed to do more things than I would've guessed.
I find the staging area useful. It especially helps when you only want to commit a change in part of a file or just generally reviewing a commit before it's a real commit. And also to double check I'm not going to be uploading any secret keys (which seems to happen to people more often than it should).
You don't need the staging area to select hunks into a commit. The selected hunks could go straight into a commit. Selecting hunks is a different thing than putting the selection into an extra intermediate area between working directory and commit.
You don't need an extra intermediate area to review a commit. Commits are flexible and modifiable, so you can review the draft commit, modify it as necessary, and then publish it.
I always assumed it was there as an analogue of the state tracked by a UI such as TortoiseSVN's Commit dialog, or (though it's a lot longer since I lasted used it...) Perforce's changelists view. It's a list of files you've got checked out or modified: you tick the ones you want in the commit, right click to delete files or revert, double click to get a diff, that kind of thing. Between each deletion/reversion/diff/etc., the state of the tickboxes is retained, so you can sort of just fool about until you've got what you want.
But this sort of multi-step thing is often a pain to do from the command line, I find: unless you have some way of tracking the state between commands, it's no fun working through this list of items, building up a to do list that you then have to get done at the end with one uber command. And the staging area is this way of tracking the state when it comes to putting together your commit.
The gitless examples look to have many common possibilities licked, though, and perhaps that will suffice for most cases?
I didn't know about Gitless. The other interesting thing I see about it is that switching branches also switches out any uncommitted changes. On balance I think I find that less useful.
Honestly, I think that 'stash' is the more problematic concept for me. Not that it's particularly bad, just that it's extra. Make a new branch for your awful code, check out your old head and keep going. I learned hg and then git, and IIRC stash was more comfortable for my team's established workflow.
And maybe I have good reason to hate it. One of the only times I've ever broken a repo is by attempting to stash partway through a messy merge. Never did figure out if that was pebcak or a bug, or if I could gracefully recover, because I was in the middle of something. I shed a tear, nuked the repo and found a better direction to merge.
Ever since that happened I've gotten much more comfortable making and deleting branches. Among other things, they're easier to clean up and have proper histories.
> The staging area is totally unnecessary IMO. I think git would be easier if we didn't have it.
I can't even imagine not having it, I extremely rarely commit all changes, to the point where I really might as well alias add=add -p, and now I've thought of it I probably will.
> The term `checkout` is multiplexed to do more things than I would've guessed.
My rule is that if I think that, I've probably got the 'wrong' mental model.
Checkout gets the state of the worktree from somewhere else.
In its simplest usage, from another ref and changes to it.
With -b, as above, but with a new branch name.
With -- files, filter for only the given files, leaving HEAD where it is because moving it would be the opposite operation - taking the inverse list of files from current location to the specified one.
> The term `checkout` is multiplexed to do more things than I would've guessed.
Do you mean `pull`?
> The staging area is totally unnecessary IMO. I think git would be easier if we didn't have it.
It's an interesting POV. Especially since you can easily amend and rebase -i before pushing without any consequence. Thanks for the idea. I implement a git-like for a special use case at the moment and will certainly consider this.
Just learn all ten and be done with it. You wouldn't work in a factory with professional tools without learning to use the tools either. So why not just learn this professional version control system in and out. It's not that hard either.
Because a lot of people have a terrible workflow. Then they spend 1 hour on StackOverflow searching a magic solution to fix their mess.
And there are also those people who inflict themselves unnecessary strict rules for whatever reason. Like those who refuse to rebase and push -f on their own branches. Or those who refuse to use a GUI but keep messing up when diffing, resolving conflicts and staging specific files/lines.
I really do not like `push -f` because in the past git default configuration was to push all branches; things have improved now that the default is to push to the current branch.
Recently got turned onto `git push --force-with-lease` which is great.
I agree it's not hard once you get it, but the main thing is people don't get it. It's unintuitive. That's not to say the model is wrong (I think it's correct), just that there's a huge gap between what people think git is doing and what it's actually doing and so they end up fighting it to do what they think it should do.
I had a coworker explain that he did a merge and something unexpected happened to his branch. I had to explain to him that what happened was totally expected and that his understanding was what was wrong.
Yeah! I find git to be easy to understand conceptually, but the CLI is unintuitive and sometimes inconsistent. I often know exactly what I want to do, but don't know how to phrase it in a git command.
Agreed. Specially, flags of these commands are actual magic when it comes to productivity, at least for me. For example, not all flags of git commit command are used frequently but they perform a lot of different operations and can be easily combined to save the day.
My thoughts exactly. Maybe it's because I've used SVM and Mercurial before but I learned Git very easily. I find the commands and options fairly intuitive once you know you're manipulating a graph of patches.
But I guess this is very subjective. After all, I've never been able to master gnupg despite how long I've been using it for.
> I find the commands and options fairly intuitive once you know you're manipulating a graph of patches.
On the contrary, I find the "graph of patchs/Merkel tree/whatever" model pretty easy to understand, and have difficulty in using the commands to make the tree look like how I want it to.
Since started using Magit in Emacs, I found myself using the command line Git less and less. I can perform most Git commands with couple key strokes. Having a UI with integrated workflow with Git is pretty nice.
Long time Vim user here as well. I started my transition to Emacs few years ago. Along the way I discovered Emacs Doom distribution, which is specifically created for Vim users (and similar to Spacemacs, but lighter), and I never looked back.
One mistake that I saw several times is cherry picking or merging another branch into the current one, then realizing later that you didn't need those changes yet, and you revert the merge commit. Later, if you actually want to merge the other branch into the current one you will get in trouble as it's already "up to date", as the current branch is ahead. Even worse, if you instead merge the current branch into the other one, all your changes done in the other branch will be reverted. The takeaway: don't revert something if you don't actually want to revert that code. I am pretty bad with git, by I assume the correct way to reverse the initial merging would be to remove that merge commit entirely, using git reset.
I think both answers are correct, and the best thing is to understand where each approach will bite you.
I prefer to remove the commit because I am proponent of rebasing over merging. Though the issue is that removing merged can be tricky, because you have the merge commit as well as all the commits associated with the merge. It’s easier for me to manage by avoiding merges entirely, and just restructuring git history via rebases often.
Biggest issue is the first part, when it's "already up to date", so then when you merge the feature into the current branch and think it's merged, it will actually be missing, so you might forget to revert the revert, or not work anymore because of new commits/conflicts.
I honestly can't say I have ever had this problem. I also don't understand how you could forget to revert the revert? And why would new commits matter? Sure you may have conflicts, but you would have had them anyway if you hadn't reverted.
We've had to revert commits on our master branch after several commits have been added on top before, and we've never had an issue just checking out a branch off master and reverting the revert commit.
I feel like there are workflow things you could be doing to avoid whatever problems you're encountering possibly?
You can easily forget if someone else (not yourself) did this (they merge the branch and reverted it), later when you try to merge the branch it could be successful, without any merge conflicts, but still won't lead to the expected changes.
OK I suppose that is more likely, but I still think this is easily-avoidable through process. If you're closely-enough involved with a ticket that you were going to be the one merging it, I think it's reasonable to expect that you have an idea of things that have happened in the story.
I found one article, only one, that did more than anything to help me understand git. Can't find it anymore. :-( But it had to do with reflog and how any command could be undone since nothing was truly destructive, and how reflog actually had the edges in the graph and you just needed to know how to repoint them to the right nodes. Or something. This is probably one of my least helpful HN comments.
One of the most common issue I faced when I started learning git was diverging local and remote branches, franatically searching how to fix it and giving up 2 hours later.
But that's the goal of git -rebasing, merging- conflicts are pointed out to you so that you have to fix them. Fixing conflicts isn't a passive task, it can actually involve writing/modifying code, and by pointing out conflicts git makes it easier.
Yes, that has been my experience as well. Starting a new repo that has a remote tracking branch has been a source of constant frustration for me. I routinely mess up some incantation and then have no idea how to fix it. The mental overload is high enough with local branches, but I still don't quite follow what it means to have a tracking branch, it seems to complicate the nice and simple mental picture I have of the local repo as a DAG.
When you fetch from a remote repo, the state of the branches in that repo has to be recorded somewhere locally in your repo. That’s what remote tracking branches are. So if the remote called origin has a branch called master, and you fetch, git downloads the commits you don’t have and then updates .git/refs/remotes/origin/master to the commit ID of whatever master is on origin.
That’s all it is.
Basically you have a DAG just like you think. But git needs some way to label some of the nodes in that DAG. It calls those labels “references” or refs, it records them under .git/refs/, and there’s basically just three kinds: local branches (refs/heads/<branch_name>), tags (refs/tags/<tag_name>) and remote tracking branches (refs/remotes/<remote_name>/<branch_name>). There’s also the reflog which is a change log of the local branch refs, and a special log for HEAD which keeps track as you switch which branch is currently checked out.
Note: if you start poking around under .git (and you should in a toy repo!), you might not find exactly these files. For performance reasons, git sometimes combines the refs into a single file called packed-refs.
The only thing you really need to internalize is that all git operations are entirely local on your machine, except clone/fetch/pull/push.
(Another useful thing to internalize is that git pull is really just git fetch followed by git merge. git fetch is the part that involves network activity, while git merge is entirely local on your machine. I can't remember the last time I've used git pull, actually...)
So when you're doing git log origin/master, you're not looking at the current state of the master branch on a remote machine. Instead, you're looking at what the state was the last time you did a fetch/pull/push.
This is extremely useful for being able to work remotely.
For many of us git should be a multiplier - spend time doing your code and experiments in a safe way, because git, used well, will protect you. As such, learn the tool! Pro Git[0] is great, and you learn the how, but more importantly the why of the tool, so that you can make git a multiplier.
> We then tell git bisect to run the command lein test on each commit until the command exits with a 0 exit code, indicating that we’ve found the first broken commit.
According to git-bisect(1), "the script should exit with code 0 if the current source code is good, and exit with a code between 1 and 127 (inclusive), except 125, if the current source code is bad."
Why in the world would you say that? I check out a branch, I write some code, it doesn't do what I want, I do a git reset and try again.
If you aren't using git reset that means you're either a genius coder who doesn't make mistakes, or you are a coder who would rather keep going down a bad path instead of just starting fresh. Some people find it easier to just start fresh.
For me, it's never the case that new code I'm writing is SO devoid of value I'd rather pretend I never wrote it, but that's what a reset does. Rather, I keep iterating until I've made clear progress, then commit.
Because git reset --hard is kinda dangerous, I've resorted to managing my changes with other safer commands. I undo changes with git checkout. Sometimes I stash and forget.
I only use git reset --hard when I have accidentally committed something to an incorrect branch and I want to reset that branch to point to a specific commit after creating another branch.
I strive for perfection in other areas of my like as well. :)
git reset --hard makes a lot of sense with printf debugging.
A typical workflow starts by adding printfs or whatever your equivalent is until you've narrowed down the bug. Then you fix the bug, keeping the printfs until the fix is confirmed. Then you use git gui or an equivalent tool to form the commit(s) for your bugfix. Finally, use git reset --hard to remove the debugging detritus.
> A common workflow is:
> Mess up your Git repository.
> Google some error messages and read cryptic > > posts.
> Try a few fixes.
> Tear hair out.
> Delete repository and clone again.
You don’t have to be a genius to use git, I’ve never experienced anything like this, even though I’ve worked in 15-20 member teams with lots of conflict and all that. Read the docs and use it as it is suggested. I don’t think it is that hard...
I feel like this scenario is just not from real life
There's one of these articles at least once per week that makes it to top of HN. When are we collective going to come to the realization that Git is a corded drill in a battery-powered drill world?
Don't get me wrong, version control is necessary. Obviously. But if a plumber, a word-worker or some other artisan used a tool that required a weekly "It's okay, you'll catch on eventually" article, we would have never got out of the Dark Ages.
It's time for an intervention. It's time to take seriously the friction and frustrations it creates. Yes, it has redeeming qualities. But it's time to stop looking past those and do something about them (other than another article such as this one).
I, on the other hand, see these threads and wonder how arrogant and fraudulent our industry is when programmers have to pat eachother on the back and say the problem is git.
Git is a tool for creating and navigating a directed acyclic graph of revisions. It’s fine to chuckle and make fun about how esoteric that sounds, but at the same time I expect people that work on my team to rise to the challenge of proving that they occasionally attended data structures and algorithms class.
I understand not taking a day to learn git, I really do. It’s hard to find the time to learn everything that comes your way at work, and you’re not exposed to the practical challenges that augment documentation as part of learning if you try to crush it out all at once. But, if someone can’t learn git, I don’t know what to do with them. We’re not cranking out websites in an agile, typewriter-pool style open-office, sweatshop. I need people that can learn things at least as complicated as git, because they’re gonna have to keep up.
> "Git is a tool for creating and navigating a directed acyclic graph of revisions. It’s fine to chuckle and make fun about how esoteric that sounds, but at the same time I expect people that work on my team to rise to the challenge of proving that they occasionally attended data structures and algorithms class."
And those can (read:should) have a visual representation, yes? Why are we still typing archaic/cryptic commands - read: wasting brain cycles that could be better spent - for what are ultimately manipulation of something best represented visually?
It's time to move on. I'm sure someone will fax you when the time comes. Hopefully, you can keep up :)
How much of git is actually that hard though? There are definitely some extremely dark corners in git, but most people really only need 4 commands (add, commit, push, pull) to get started. Once you start needing to do more you start to incrementally adopt features. I’m not trying to trivialize git because it’s obviously complicated. I’m not sure I accept that someone can’t be productive with git in a reasonably short amount of time.
I have to say I thought something similar to your sentiment.
When I interview people for software engineering roles in 2019 who haven't bother to learn Git or struggle to understand it's use-case, basics and relatively simple to use interface I can quite easily use this to make some important assumptions about the candidate. The most important being that maybe software engineering isn't the right career choice for that person, at least not yet.
Is there room for improvement? Sure, but let's make sure where ever we go, it's to a better place, not a worse one.
Another thing about this is the assumption that a candidate has to be a Git ninja. If a dev can't read the Git documentation and narrow down the most important use cases, then it should definitely trigger a red flag. You don't need all the features to be productive. Unless you are an edge case, you can probably do most of what you need to get done with these six commands:
branch
checkout
add
commit
pull
push
Reading and understanding the documentation for those six core commands isn't a big investment, and it will pay off if you're doing software or documentation development.
> "I need people that can learn things at least as complicated as git, because they’re gonna have to keep up."
Not to get off topic, but it's your #1 job as team leader to put your people in the best position to succeed. Pounding you fist on desk and shouting "keep up" doesn't cut it.
The question here isn't what is or isn't learnable. The question is, why so much tension and friction (i.e., using the CL) when a visual representation is actually the far better representation of the model / data?
Keep up? Why are we tossing rocks in their toolbox?
I don't pound my fist on my desk like I need more pictures of Spiderman, the nature of the product domain we're working in is demanding.
This is not a defense of the status quo. It's an observation about working within the status quo. If I could choose for everything else to remain equal but git get easier, of course I'd take it. I'd choose for a lot of things to be better, not just software.
My observation is that of all the things a developer might encounter for the first time on our project and be asked to learn, git isn't a standout. This is what I meant by keeping up; there's a lot to learn.
We do what we can to reduce the load, spread it out, and I refine the crash course for new developers every time someone goes through it. But at the end of the day, we have jobs because we can pick this stuff up and get to work with it. Even if git is less than the platonic ideal of version control.
On the other hand, I don't know who these articles are really for. I have _never_ met a developer who struggles with git. Not many claim to understand it deeply, but all can rebase, cherry-pick, use the reflog, etc. and almost never do they run into issues.
It mystifies me. Git isn't hard, nor complicated. "Checkout" has a few too many meanings, and thats the singular gripe I have with it.
I’m about to roll out git to a team of 30 windows devs of the kind that do NOT like using command line (which is a perfectly sensible thing on Windows I should add, it’s rarely needed there and most command line tools including the shell itself sucks). I assure you they will find it complicated. I’ll insist we switch to git but it’s still going to be an uphill battle. Some will surely struggle also a year from now.
Windows user here, tho' I don't think that has much to do with my analysis/opinion. Ultimately, to me, the dev via Git is doing something that is best explained visually. It seems counter-intuitive to type commands for what is visual, at the very leaat it's unnerving (as if we don't have enough friction and stress in our day already).
To me, Git via the command line, constitutes industry "jargon". It's used - wrongly - to help exclude certain people within the broader culture. Git + CL === elitist.
It's also anti-dog food'ing. But perhaps this helps explain why so many UIs and UXs are so subpar? That is, the less you use something (i.e., a proper UI) the less you learn about them?
What about using git plus a shell make you an elitist? What if I used something else from a shell that isn’t as negatively perceived as git? I’ve used git with a ui (early on) and a shell (later) and I don’t understand what makes it elitist. Figure out what tools make you the most productive. If vim makes you more productive, great. If a full blown IDE makes you more productive, great. I don’t understand the mindset around being critical of someone doing something in a way that works for them.
I think the right approach here is to figure out how to use git in the company IDE. Then, have a presentation / workshop about how to use git in the IDE.
Personally I prefer the command line, but I imagine your coworkers will be a lot more receptive to using version control tools the way they're used to.
If you're concerned about command line complexity, you can try out gitless: https://gitless.com
It's a simplified command line interface to git, designed by looking at how users actually use git.
You have a point. But certainly, we could do better, especially since it's such an important tool. I'm certainly not disputing the concepts. They're necessary. But the tool? In that context "what if" doesn't feel like a bad idea either.
> Git is a corded drill in a battery-powered drill world
Git isn't a corded drill in this analogy, it's an electric motor: the potential foundation of many different tools for different problems. There's nothing wrong with it, it's just that it would make more sense to use it as the basis of a more complete, ergonomic tool, rather than just sticking a drill bit into the spinning part.
/usr/bin/git is like curl: a command line tool for precise manipulation of an underlying data model/protocol. It's complex, but it works great - if you want to interact with the underlying data model/protocol on its terms. Many people want something that automates a more complex workflow to help them accomplish a higher-level task. For HTTP, we have browsers; for git, we don't have much yet.
I'm one of those that likes git, finds it decently easy to use, and is much more productive because of it. But I do think there's merit to complaints about git. There's a wide range of experience, skill sets, and programming styles in our industry, and overall this isn't a problem as people can pick up the tools that work best for them. Look at text editors, for instance -- some people use sublime, others intellij, others vim, others emacs, etc. But for version control, there's really only git now. I'm personally a vim user, but I think it would be strange to insist that everyone must use vim.
The text editor analogy falls short in that version control has to be used by the entire team whereas a text editor only has to work for an individual developer. So, I can see the argument that the standard version control tool should be a little more intuitive. I think one challenge though is that, in my experience, it's not even the command line so much as some basic concepts around vcs that people struggle with, so "more intuitive tool" is a hard challenge I think.
It’s not obvious to me that a battery powered drill is the best tool for the job. If you are a professional doing non-trivial work sometimes the corded drill, with all its benefits, is exactly what is needed.
True. Agreed. A cord is not a battery. But we're not even entertaining that idea of having that choice. We have a corded tool. That's it. Remind yourself of using that next time you're standing in a couple inches of water :)
If people would stick to pull, push, commit, and merge 99% of the problems would go away. But there's always one "clean history" OCD nut job who goes ballistic if they see a merge commit in the history. They seem to know everything about git except how to exclude the merge commits from their git log command.
The regular people lose two days of work trying to rebase their merge commits to appease those folks.
Rebase should never have become part of the day to day git toolbox. If it didn't exist nobody would ever see a linear history, and so would never think to care about it.
Thank the maker for github's "squash merge" and "rebase and merge" buttons, which handle all that crap for you. If you're not using a tool that does that for you I'm sad for you.
Agree (And ironically of course some people agree on this in the discussion on every one of these articles).
Git is the C++ of version control. Of course it’s powerful. Of course it can do everything. And of course it’s a huge frustrating footgun with error messages that rival any c++ template compiler error.
The problem is that we have made it a de facto standard so it’s hard to replace. Even if a much better VCS emerged tomorrow, it doesn’t help if there isn’t support in large issue trackers, CI/CD systems, IDEs and so on.
I have great hopes that pijul will be the better git. But again, it’s the tooling and ecosystem that matters, not the qualities of the vcs itself.
Pijul looks cool, but "replace hard to understand directory content snapshots with easy category theory" isn't a compelling proposition outside of maybe the ML/Haskell community.
The main point of Pijul is, you never have to think about categories when using it. It's just a sort of Git where you almost never need to branch (the equivalent of a Git branch in Pijul is just a patch), merges are always deterministic and easy to understand, cherry-picking is the default, and works even for conflict resolutions.
Interesting choice of analogy. Remember Neal Stephenson's "Hole Hawg" essay [0]? He compares UNIX to this ludicrously, dangerously over-powerful hand drill with no safety features and all the ergonomics of a chunk of steel pipe. And by this he means praise! The implication in that essay was that a powerful, dangerous, unfriendly tool is in some way better than a user-friendly tool that lacks the power to remove limbs.
My takeaway from that essay was that in the real world, you will never see a contractor using a Hole Hawg, or anything like it, and hackers have a uniquely fucked-up attitude to human factors. Hackers will excuse the most tragic of user interfaces, with some kind of macho "rite of passage" bullshit. Yes, "macho":
"Now I view them all with such contempt that I do not even consider them to be real drills--merely scaled-up toys designed to exploit the self-delusional tendencies of soft-handed homeowners who want to believe that they have purchased an actual tool."
See? It's all about self-inflicting pain, because if you can't tolerate the pain of a crappy user interface, you're not a real hacker [1]. I see it in the defense of git's crappy user interface ("the reason you can't remember the 50 semi-orthogonal cryptic commands is because you haven't grokked its perfect model of directed acyclic graph theory"). I also see it in the perpetual defense of Emacs' crappy user interface (infuriating, because it is a powerful piece of software). Hell, I even see it in the defense of the command line interface itself (and associated scorn of GUIs) - many of its design decisions have been baked in since 1969, yet to listen to many apologists its perfection is such that it might as well have been carried down the slopes of Mount Sinai by Moses himself.
This is a major cultural problem with our community. Maybe, if we actually could bring ourselves to admit that our interfaces suck, we might start to make a little progress towards fixing them. Because right now, "tolerance for unreasonable bullshit" is a major filter for who gets to do programming.
"...when I got ready to use the Hole Hawg my heart actually began to pound with atavistic terror. But I never blamed the Hole Hawg; I blamed myself."
Yes. Blame yourself. Blame yourself for using a stupid tool with a bad user interface.
I think experience has shown that some people really like tools that others find really awkward. Sometimes even over the same features described in completely different ways. It is counterintuitive and different from other VCS and reuses commands to mean very different things (especially checkout and reset); that doesn't matter to people who are used to methodically learning these things from first principles.
Plus there's an intrinsic elitism in it being hard to use.
> But if a plumber, a word-worker or some other artisan used a tool that required a weekly "It's okay, you'll catch on eventually" article, we would have never got out of the Dark Ages
Tradesmen use all kinds of tools like that, which is why trade schools and apprenticeships are a thing. I bet there are weekly articles on how to get the most out of your Fluke in the trade press, we just don't read them.
I got shamed a few times in a new role awhile back in part [imo] because it was assumed I was 1000% git-fluent. The way I’ve started to view svc ticks is similar to how I view grammar knotsies. In the end the idea is to communicate, not to make other people feel like dunces.
Read the Git documentation thoroughly. Most people don't, and then wonder why they have no idea what's going on when a project they're put on uses Git for version control.
If you really want more productive Git, stop playing the Git Adventure Game!
When you poke at your repo on the command line, you never get to see it as a unified whole. All you can do is try a command, see what it prints out, and try to make a mental model of what this all means.
A good Git GUI will show you the state of your repo and unify all of the scattered concepts of the command line like the index, the reflog, and stashes.
SmartGit is my favorite. I've also heard good things about Tower, although it's only available on Mac and Windows, not Linux. (SmartGit supports all three.)
A couple of examples from the article:
> The process of a cherry-pick is brief. First, we identify the SHA for the commit or commits you want to pick, using git log or the like. Next, we check out the branch we want to apply the commit(s) to. We then pick the commits.
In SmartGit, you see the commit you want to pick in the log, right click it, and select Cherry-Pick.
> Another common issue is committing and then discovering you missed something in that commit. Sure, you could make an edit and add another commit, but sometimes you want to maintain all related changes in a single commit. In this case, you can use the git commit --amend command to fix it up.
> Let’s say you’ve edited useful_func.clj and then committed it.
git add useful_func.clj
git commit -m "Added even more useful function"
> But you forgot to commit your code and document your new function. Instead of editing and committing again, you can amend. Make the required changes to the useful_func.clj file, then add it again:
git add useful_func.clj
> But instead of running a normal commit, run an amendment.
git commit --amend --no-edit
> This will amend your last commit with your new changes and commit it. The --no-edit flag tells Git not to launch the editor and skip amending the commit log message. If you want to update the commit log message too, you can omit this flag.
In SmartGit, you use the same Commit dialog as a normal commit. It's on the menu, or Ctrl+K (Command+K on Mac) will take you right there. The Commit dialog has an "Amend last commit" checkbox which is normally unchecked. Simply check that box and it will do an amended commit. You can either keep the previous commit message that is displayed in the dialog, or edit it right there.
A couple of other topics the article doesn't touch on...
What about the index? In SmartGit, you can either use the index or ignore it as you see fit. I rarely use it myself. The Commit dialog just does the right thing when I ignore the index, committing my working tree changes directly. And if I do want to use the index, it's easy to get to from the same dialogs.
One of my favorite features in SmartGit is how it handles the reflog. Instead of printing out a list of hashes and poking through them to find the one you need, simply click the Recyclable Commits box in the log view. Now every commit in the reflog shows up as part of the normal commit log tree. You can work with these commits just like any other.
It does the same thing with stashes. Click the Stashes checkbox and they show up in the commit log too. (I wonder how many Git users realize that a stash is simply another commit by a different name?)
Maybe you're not sure exactly what was changed between two fairly distant commits? Click one of them, and then Ctrl+click the other. Now the Files panel shows you exactly which files were changed between these two commits and the exact differences.
I could go on for a while, but what I really wonder is why so many developers are reluctant to even try a Git GUI like SmartGit. It is so much more powerful and productive than the command line adventure game.
> When you poke at your repo on the command line, you never get to see it as a unified whole. All you can do is try a command, see what it prints out, and try to make a mental model of what this all means.
Or simply learn to use the git commands right. Then it shows you everything the UI tool would show.
I recommend everybody adding this to their ~/.gitconfig
Then you can simply do a `git lol` or `git lola` to get the same result as your fancy UI is showing you. And it also works via ssh. If you've manually typed that alias in a few times you will also remember it and have it readily available when you ssh into a customer server etc.
Any interface that forces you to manually visualize a complex internal structure rather than show you the internal structure itself is a design smell.
Any interface that forces me to manipulate such a complex structure with obscure textual commands rather than a drag and drop interface is a design smell.
The git graph structure is not amenable to command line. When I do "git log" it lies to me. I see a linked list for what is essentially a graph.
Without options it returns something that is implied to be a linked list. Try it. Anything merged into the current branch is shown as part of a single long list. It implies sequentialism in places that are parallel.
Right, this solves all my problems tack on hundreds of optional tags to every command that I have memorize and suddenly the user interface is perfection.
FYI without those options it is showing me part of the graph and implying that it is a linked list.
thanks for telling me about 'git amend'. I frequently screw up and fail to add the files I want or as soon as I commit I remember I needed to change something else. So my projects all have strings of commits that are a few seconds apart.
`git amend` and `git rebase -i` are two core features of git. It's okay if especially interactive rebasing takes some time to get used to. But it should certainly be part of every users standard tool set.
Pretty much every time you press <tab> somewhere while writing a git command, it does the right type of completion. And hitting <tab> multiple times lets you toggle through the options. So you learn git along the way.
This was one of my most enjoyable productivity jumps when it comes to using git.