More Productive Git
increment.com
increment.com
source /usr/share/bash-completion/completions/git
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.
Bash completion on Ubuntu/debian is out of this world. I can do things like
lxc exec <TAB>
and get a list of currently running containers.
[alias]
git = !cd -- ${GIT_PREFIX:-.} && git
This turns my most common typo (starting to type a git command, thinking about it, typing 'git' again) into what I wanted it to be. [help]
autocorrect = 1
This one is very useful too."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.
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!
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).
Stopped reading after I saw this.
Trying to learn something from a bad article is worse than reading no article at all.
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.
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.
git remote add origin git@yabbadabbadoo:org/team
git checkout -b feat/my-work-branch
# do work
git add -p .
git reset HEAD accidental-file.txt
git commit -m "Add sweet feature"
git push -u origin feat/my-work-branch
git pull origin feat/my-work-branch
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.
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.
Then you wouldn't really need distributed source control, would you ;)
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.
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.
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?
Staging area / Index is one of the best features of Git for me.
If I end up having a bunch of semi related changes in-progress; being able to easily group those into individual commits is great.
> The term `checkout` is multiplexed to do more things than I would've guessed.
Agree
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.
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.
Etc.
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.
It makes the staging very convenient to use. But without this command, I agree that it is a pain to use.
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.
Recently got turned onto `git push --force-with-lease` which is great.
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.
Quick quiz: What does 'git checkout a/b' do? I've seen users end up with 3 different meanings.
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.
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.
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.
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?
edit: It might have been this one: https://hackernoon.com/https-medium-com-zspajich-understandi...
As the article mentions,
git reset --hard
will blow away uncommitted changes in your working tree.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.
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."
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.
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. :)
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.
I maintain a large free list of Git aliases, and community feedback is always welcome.
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
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).
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.
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 :)
- Gitk
- Tower for OS X
- Github
Besides, some people enjoy using CLI tools the obvious reason that they're simple to use and can be used programmatically with minimal overhead.
I mean, you're just describing the act of programming in general here.
Just because something is hard it doesn’t mean it’s worth doing.
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.
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.
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?
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.
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 know many devs that only use git through their editor or some other git UI and don't know more than commit, pull and clone in the terminal.
Inevitably they always need help when something gets screwed up, or they jump through endless loops to somehow get the desired result through the UI
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?
p.s. What about SourceTree?
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.
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.
You should do a lot of learning on using a table saw before you touch one. Using git wrong won't kill you, using a table saw wrong will.
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.
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.
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.
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.
[0] http://www.team.net/mjb/hawg.html [1] https://xkcd.com/378/
Plus there's an intrinsic elitism in it being hard to use.
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.
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.
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.
git cherry-pick d8119f49cd4fd6b0366c5ca3af205f9c25af89ba
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.
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
[alias]
lol = log --oneline --graph --decorate
lola = log --oneline --graph --decorate --all
lols = log --oneline --graph --decorate --all --max-count=10
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.alias r='cd $(git rev-parse --show-toplevel)'
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.
git log --all --graph --onelineFYI without those options it is showing me part of the graph and implying that it is a linked list.