Hacker News new | past | comments | ask | show | jobs | submit login
Git tips to stop you getting fired (apiaxle.com)
183 points by philjackson on April 8, 2013 | hide | past | favorite | 108 comments



If you're in danger of getting fired over a commit mistake, you have more and bigger problems than this article can fix.

These are good tips, nonetheless.


There is a bigger chance of getting fired for ordering 10x the amount of food for the team, while they are crunching...


Out of curiosity, do a lot of people use CLI git?

I personally am much happier losing a little functionality (and all these fancy flags) for a much clearer visual interface - I'm using GitExtensions btw.

Am I alone on this?


Not alone, certainly, but almost certainly in the minority. I don't think I've met anyone in person (in five professional years, granted) who uses a GUI for anything Git-related except complex merges or history visualization, both on rare occasion.

Not sure why your perfectly reasonable question is getting downvoted...


I have some colleagues which use GitExtensions exclusively (they are Windows users who think CLIs are a thing of the 80s), and they have a hard time understanding Git operations because of it.


i mostly use the cli, but i use a gui (git-cola) for interactively committing only part of the current diff. it's way better than git add --interactive. also gitk is nicer than tig, though tig is easier to use when sshed into another server.


Incremental (interactive) commits are probably best done from within your editor. I use fugitive [1] for Vim, there's magit [2] for Emacs, and probably a plugin for your favorite IDE, or ST2.

[1] https://github.com/tpope/vim-fugitive/tpope/vim-fugitive

[2] http://www.emacswiki.org/emacs/Magit


what does fugitive do for interactive commits that beats git-cola? i love vim for single-file things, but once it comes to a global project view i usually prefer to use another tool.


I have never use git-cola, so I can't compare, but for an overview of fugitive's features, you should probably look into the Vimcasts on that subject. There's overall five videos, this one is the first:

http://vimcasts.org/episodes/fugitive-vim---a-complement-to-...


I'll throw in my vote for CLI git. It's much better with the bash-autocompletion additions (many people I run across don't even know this exists) and a tweaked PS1 to show status as I hop around.

But my main reason is that I haven't used a GUI yet that doesn't a) take more time to do basics (aliases are great), b) bog down on projects with lots of files or lots of history, and / or c) lack some feature I rely on (good rebase and / or cherry-pick and / or reflog support is usually lacking). I'm also pretty comfortable with my workflow, so there's a fairly large step backwards to try something else, but it has definitely taken longer to get to this point than with most GUIs.

And in general I continually have to resort to the CLI for something, git related or make/rake/script related, so I just stay there. I'd love to switch to a good GUI, since they're generally far better at displaying information, but I haven't found one I'm happy with yet.


I use the CLI for everything except merges and glancing at history of a particular file. For merges I use opendiff (simple merges I'll just drop into vim and do it quickly by hand) and history/diffs between versions I use SourceTree.

Honestly, the GUIs are more confusing to me than using the CLI. Git does a pretty good job at pushing the user in the right direction.


I use gitextensions as well, and could never imagine using CLI. I don't have the patience to type out filenames or read ugly diffs through the console just for the sake of using CLI. On top of that, I'm an extremely slow typer so CLI is almost always a hinderance.

Staging a handful of files for commit in CLI takes maybe 30 or 40 seconds for me, where with gitextensions it takes a handful of clicks, not to mention I can read the changes I made to the file as I stage, which is useful for commit comments.


I don't have the patience to use a GUI.

The CLI autocompletes git commands, filenames, remotes, branches, tags, anything you can think of simply by pressing tab once. Just press tab twice to see all options for the context, for example list all tags matching a prefix entered.

Staging a handful of files literally takes me a few seconds on the CLI. I constantly use interactive rebase, stash, amends. I could never imagine using a GUI for this.


I also use the cli heavily for the reasons you've listed. I also use vim as my primary editor so the prompt is only a ctrl+z or :sh away.


What I find especially powerful is when reviewing files in the commit window you can stage and commit subsection of files.

It allows you to really quickly separate out different change into unique commits and gets rid of the need to make messy I-did-A-and-then-did-B commits.

Select the lines you want in the commit window -> Right Click -> Stage Lines.

You can also revert selected lines, but for some reason it's grayed out half the time... I'm not sure what black magic controls that feature.

You can do all of that in the CLI but it's a lot more clunky and time consuming.


`git add -p` splits your changes into logical chunks and lets you choose whether to stage each on.


It also lets you edit them (press e on a hunk)! I love that command. And it was clearly inspired by "darcs record". I also use commit-patch[1] quite a lot, it comes with Emacs integration which makes it heavenly (vc-diff then edit the patch to your liking, then commit).

[1] http://porkrind.org/commit-patch/


I use magit (popular emacs interface) for my day to day git work. I only hit the commandline for things like the ones I've spoken about in the parent article.


The opposite is true for me. I use git/hg UIs almost exclusively for visualizing the repository history, but find that they are too cumbersome for modifying the repository. If you need any non-standard options, they're generally faster to type (especially if you have decent command line completion), and standard commands I have aliased so that they are usually faster, too (if they aren't already fast to type).


I use the CLI for almost everything. The only time I use a GUI client is for complex stuff like cherry-pick or fixing conflicts.


What do you find is complex about cherry-picks?


From my experience, developers who rely on visual interfaces don't understand Git as well as developers who mostly use CLI. When relying on visual interfaces, at some point Git stops being the powerful tool it is.


You shouldnt generalize. I understand GIT very well and can (and for complex operations beyond the UI) use the CLI. However I generally use UIs because i simply prefer it. I see no need to use the cli for basic commits,pushes and pulls when neither is inherently superior..


I know this sounds very condescending and even a little elitist, but usually when people say "I am proficient with a CLI but prefer a GUI" I hear "I have memorised a few commands but I don't understand them, so I prefer a GUI". The reason being that I have genuinely never found a GUI for an application which is simpler or easier to use than a CLI.

I'm just curious; you seem to imply that you find basic commands (add, commit, push, pull) easier to perform in a GUI than a CLI. Why is that? What is it about a CLI which isn't simple?


All right, I'll bite, I think it was a little condescending. I consider myself pretty proficient with Git, with maybe above average understanding of the internals and the porcelain. I use the command line for most git operations, but have ended up using `git gui` for a lot of simple and complicated commits, which almost always end up using `add --patch`. My workflow is something like:

  work on the code
  use git gui instead of add --patch on the command line
  use git stash -k on the command line
  run tests suite
Git gui lets you pick individual lines much easier than `add --patch` does, and I find that wanting to have that available at my fingertips means I use it for non--patch adds too. Maybe this is an indication of some other "flaw" in my workflow where I'm generating a lot of changes that I don't want to commit yet, but I think it's common and inevitable when working on legacy code or in maintenance-mode. But even for new projects I use this because I'm usually cleaning up my work via --patch.

Another nice alternative to `add --patch` is magit for Emacs which lets you select a region in a diff and add that. I find both of these (git gui and magit) to be much easier and faster to use than `add --patch` on the command line, which has a pretty clever interface given the limitations, but is really far from perfect (split often doesn't work with small hunks, which means you have to open it in an editor. which means Emacs, so I might as well just use magit)

I've tried to get colleagues to use a workflow like this, so they stop committing garbage like bad comments and logging.

In my experience and humble opinion, your generalization is often enough wrong that I would avoid it. I've met plenty of people who prefer GUIs for this or that task which they could script or shell circles around me. It really all boils down to taste and what you find to work for you. Git's command-line interface is badly enough designed that you shouldn't make anyone feel bad for using something different. (I say this as someone who loves Git very dearly)

That said, I DO believe that users who NEW to Git specifically should use the command line a bit while they are learning, since it helps with the vocabulary used everywhere to talk about Git, while some GUIs bury it behind a leaky abstraction.


Thanks for the explanations. After reading my comment again I realise that I sounded like a typical Git elitist - sorry about that.

I'll turn it around and ask why, for simple tasks, is the CLI any better than a GUI ignoring personal preferences?

For me, the main thing is speed: I can type much faster than I can navigate a cursor (tab completion helps). I recognise that some GUIs have keyboard shortcuts to speed things up, but then at some point you're using the keyboard enough to justify using a CLI. The other thing is that I don't find graphical representations of my changes helpful at all. I commit early, commit often, so the output of `git diff` generally doesn't need to be paginated. My feature branches are small so I can merge them without the need to see a commit/branch graph.

To be honest it's hard to answer that without ignoring personal preferences because really, that's all it boils down to.

I can definitely understand the want to use a GUI when you're doing complex adds or merges. spacemanaki is right in saying that doing this a lot probably indicates a problem with workflow, though.


You're right, it does. I know where you coming from because i see it often myself, but you should never make assumptions about people because there's always exceptions.

Its not that the CLI isn't simple, it's that the GUI is just easier. From your post i think i can safely assume you sit in a CLI all day so it makes sense you would prefer to use it. I spend the majority of my day in windows & IDEs and while i always have a few bash cygwin shells handy its just easier to right click -> commit/push/pull/switch branch/fetch&rebase then to switch context and type it out. Oh and merging, I just find visual diff/merge tools nicer.

When i need to actually do anything complicated the CLI is where i go, but generally, i really don't need to.

I'll turn it around and ask why, for simple tasks, is the CLI any better than a GUI ignoring personal preferences?


There is a correlation.

To be able to use the CLI you need to be more comfy with git; but just because it's less intuitive doesn't imply it's a a more powerful tool. Just that the user-base has a higher git-familiarity floor


I use both CLI (when I'm on-server) and GUI (SourceTree on my Mac, TortoiseGit on my Windows PCs). I find the GUI better for most things for me, especially since it forces me into a review workflow before I commit and push much more than the command line tools.


Git Users Survey 2012 might give some indication: http://bit.ly/ZdRDxX

Questions 10-15 are relevant and show a quite wide variety of different tools people use. GUI's seem to be popular too.


I use CLI everything whenever I can simply b/c I can script anything moderately complex or more, back my scripts up to github or whatever, and never forget (or have to exactly remember) them.

I find that more valuable and useful than most CLI tools, although in their defense I haven't used one in years so maybe they're equal or better by now.

git-sh is clutch too - you can still run normal shell commands or full git cli commands, or you can drop the 'git' from git commands.


I use cli for everything but the occasional history inspection, for which I just use gitk. I have just recently started trying out p4merge as a mergetool.


SourceTree for OS X is great: http://www.sourcetreeapp.com/


Also available for Windows these days.


I use both. Most documentation for different operations is on CLI, but JetBrains IDE's for example have very powerful Git tools like in-editor git-blame, auto-adding files, resolving merge conflicts, and opening lines of code on GitHub.


I use gitk and tig from cygwin, osx (on osx actually GitX) and linux. But mainly the command-line.

Tried TortoiseGit, GitHub app and SourceTree - but use them rarely. Mostly if I want to get a good overview, they are bit easier to get into.


I use the CLI for batch operations on multiple repos/branches and some complex operations (history rewrites/repo maint) but for general everyday single repo use i typically use tortoiseGit or GitExtensions


I use the git CLI for most work; "git gui" for reviewing changes between writing them and committing them, especially for committing partial changes. Almost nothing else.


I use the CLI exclusively and rely heavily on the interactive commands: git add -p, git reset -p, git checkout -p.


People use a GUI for git?


i've only used the CLI on Win for features TortoiseGit was missing, though its SVN-ancestry has a lot of terms-clash with the actual Git commands issued under the UI.


I just ignore the flags that I don't need.


A warning about the ours and theirs commands: when you're rebasing, they will do the exact opposite what most people await them to do (thanks to git rebase's implementation).

From the git rebase man-page, --merge: Note that a rebase merge works by replaying each commit from the working branch on top of the <upstream> branch. Because of this, when a merge conflict happens, the side reported as ours is the so-far rebased series, starting with <upstream>, and theirs is the working branch. In other words, the sides are swapped.

https://www.kernel.org/pub/software/scm/git/docs/git-rebase....


Also, any code that isn't pushed to a remote doesn't exist. Or, it won't when your hard drive unexpectedly fails and your feature branch disappears. =)


You should be using file backup on any system with code on it. It is so cheap to do this today, it is a no brainer. Apple Time Capsule, Crashplan Pro, etc.


The only non-replacable thing on my development machine is the code. It makes more sense to me to always push my feature branches up to the server, which is backed up, than for each dev machine to be backed up separately.


Why don't you then just backup your dev machine's code directories to another machine?

Backup is good because it's automatic. Saving somewhere else is nice too, but it's not really backup.


It'd be more effort for no gain - and it would encourage me to keep changes locally, which is bad for collaboration.


Thrashing the index with half completed features is ALSO bad for collaboration.


It's good that my colleagues can see what I'm working on. It's not going to slow them down when they don't want it to, since git only fetches those branches you ask it for. So no, I have to disagree.


If you rebase a lot, then you want to avoid pushing code constantly until you get it where you want it.


So push to a remote feature branch that is named after your username, then rebase the changes in that feature branch onto the 'trunk' branch and push the result ?

The D in DVCS is all well and good, but there are business reasons for having a canonical store of all source materials.


One of the many reasons not to rebase code that's been pushed already.


As far as I know there's only one reason not to rebase code that's been pushed.

My point was that pushing constantly as a backup mechanism isn't an option if you intend to rebase frequently (unless you're the only developer on the project).


I have a personal clone of whatever project I am working on, any branches that I publish can be changed at any time using a push -f.


Depends on your team. I'm on a small one, and I often rebase and force push a branch I'm working on, because I know nobody else is working on it.


I suppose if you were really paranoid you could use 'git archive' to snapshot to dropbox.


All of my git repos live in a subdirectory of my dropbox as-is. I also compulsively push to remote. I also use Time Machine. I also rsync my home directory to an external drive in case Time Machine implodes. I also rsync my home directory to a server in another hemisphere.

Come at me, bro.


It's been a while, but storing .git files in Dropbox didn't work out so hot for me. Make changes in two places and Dropbox resolves the conflict by renaming one file to "X (Eli's Conflicted Copy)".... Git really doesn't expect to see it's internal files renamed like that.


The question then becomes "Why do I need more than one computer accessing git when computers now weigh 1kg?"


The last point is a great idea. I've had my NAS Time Machine backup get corrupted and TM forcing me to redo a full backup a few times now to the point of me abandoning it entirely..


Pushing to dropbox is a very common part of my workflow: https://github.com/rpetrich/git-dropbox It's not strictly safe to use from multiple machines, but as a simple backup it's very convenient.


This command has a mistake in it:

  ours   = "!f() { git commit --ours $@ && git add $@; }; f"
it should be

  ours   = "!f() { git checkout --ours $@ && git add $@; }; f"


Thanks, I've used an alias for checkout, "co", which I wrongly expanded when I wrote up the article. I've corrected it. Proofreading is another way not to get fired.


Has anyone ever gotten fired for making a git or other version control "mistake?"

https://news.ycombinator.com/item?id=5513353


Most certainly. I've witnessed it. It was a really bad mistake though.


Looks like your probation period is over.


Shouldn't the $@ also be quoted? If one of the argument is a quoted file path with a space, the unquoted form is going to see multiple paths.


Also note that the 'git add' here is actually completely redundant - 'git checkout <filename>' automatically updates the index with the checked-out version of the file, in addition to the working tree.


"...sometimes php developers commit configuration files..."

needless jab, imo.


yes. This is the first thing I fix on most Rails projects I inherit. Hardly exclusive to PHP.


Oh dear, you aren't supposed to commit configuration files? Is this a security thing? What's the proper way to distribute config files to to the server and other developers?

"sometimes php developers commit configuration files and things that are used in production where they shouldn’t be."

Not sure if I'm parsing this correctly. Should the files not be in production or should they not be committed? Is this just about overwriting the development configuration in the config file?


Configuration files probably include database passwords, AWS secrets, API keys, maybe even SSH keys. Fairly clearly:

1. They're really important and change periodically in sync with the rest of the app. 2. They shouldn't be in a public repo under any circumstance, EVER. 3. You probably don't want every single developer having access to your production database passwords.

Point 1 argues strongly in favour of putting them into version control for all the same reasons you'd put anything into version control.

Point 2 and 3 argues for putting them in your .gitignore (or equivalent) and copying files around by hand (or via a fabric script or what have you) during deploys.

Common wisdom seems to be that point 2 and 3 outweighs point 1, and for open source projects which live in public repos it probably should. Ditto for large enterprisey projects. But for a startup, working on a non-open source project, I think point 1 massively outweighs everything else.

As an example, the most common advice for configuration for django apps is to have a settings.py which imports a settings_local.py; you then put settings_local.py into .gitignore, and in every environment you create a new settings_local.py and add the local settings (database connection strings, template paths, whatever) into it. I started out doing it that way too, but I've recently reversed it: Now I have a settings_dev.py, settings_staging.py, etc, each with the specific environment settings, and each of which imports the common settings from settings.py, and all of which are in source control. Now I can checkout any branch or version of my app, and have some confidence that I've got the right settings to run it in whatever environment I want.

(I see philjackson has listed another reason for being careful with config files, but I'm not sure I agree. I'd say he's basically giving an argument for using different config files in different environments, and generally being a bit organised. And if there is any risk of developers fat fingering the config files, isn't that an argument to have them in version control so you can fix it easily?)


Heroku has made it very easy for multiple developers to have custom, local environment variables with Foreman, and their gem doesn't necessarily have to be used with Heroku for local machines. [1]

We use Heroku exclusively, so they manage configuration variables for us, but adopting an environment-variable structure on any UNIX architecture should be reasonably straight forward.

The nice thing about this setup is that many "if ( development && developer_is_bob ) or staging" conditionals disappear, because your app just swallows in the environment-specific variables by magic. They also help avoid "oops-I-didn't-mean-to-check-that-in" errors: yesterday a client's Login with Facebook button was down for a few hours because the client's developer developer swapped out the omniauth config by hand, then committed the new Facebook app ID along with the rest of his changes. I've told him to use Foreman in the future, which would have nicely avoided the problem.

As to your first point, there's no reason you can't version-control your configuration files on your servers, but keep them in a separate repo which your juniors, open-source contributors, or the thief who ran off with your developer's computer don't have access to.

[1] https://devcenter.heroku.com/articles/procfile#developing-lo...


An example scenario might play out thusly: Fred checks in the production configuration credentials (lets say mysql configuration for this example) in a file called passwords.php. Senior developer Bob Van Gogh checks out the project but needs to connect to his local mysql instance to develop. He edits the configuration file and hacks away on his feature. Somewhere along the way he accidentally commits passwords.php with his changes. Eventually his code is deployed and suddenly the app servers can't connect to the database. Bob's no good at football but he's a good developer and now thanks to that accident his reputation is tarnished beyond the football pitch too.

Configuration like that should be managed by something that isn't susceptible to these accidental changes.

As you mention it, security is an issue too. The fewer people who know the passwords to anything the better and the more you can keep the passwords from going over the wire the better.


Cool, thanks for the explanation. I usually have the development config in the repo and the deployment script overwrites it on the server.


That's better than the converse (default is prod, yikes!) but there's a risk of a prod server using the dev config, which might appear to work unless your dev environment is firewalled off. I prefer having an invalid or unusable config checked in, so the system doesn't even come up until I deploy the config I intend to use over it.


I know Bob, he's a much better footballer than he is developer


It's the cartwheels that set him apart.


Yeah could easily be applied to Perl dev's too


how about "any devs" or even "novice devs". as if there's some class of super-devs that's immune to versioning mistakes, ffs.


All phpers are now offended? haha, must be true than!


lolwut? had it said "ruby" or "python", there'd be a shortage of tear gas and cars would be burning in the streets.


Let's just abstract away the details and say something like: "...sometimes <arbitrary_programming_language> <arbitrary_programming_job> commit configuration files..."


"adverb adjunct noun verb adjunct noun"


    git-adverb adjunct noun verb adjunct noun


With regards to merging, I prefer using a merge tool such as Meld. Whenever you're in a merge conflict, just run git mergetool.

Meld is pretty easy to learn as long as you know to use shift-click to delete a chunk and ctrl-click to copy a chunk instead of replacing.


Git power usage looks dangerously like accounting.


Not all that complicated and follows a simple set of rules?


I realize that this post is targeted more towards advanced git users but it would be immensely helpful if you could add 1-2 examples to the every section (you only have some for the first section)


These are great tips. And so is the other post about Git Koans posted here today.

I'm a bit of a git fan and while such tips pique my curiosity and delight the git geek in me, is it actually wise to use these on a day to day basis at your job? Doesn't the argument about 'clever code v/s clear code' apply to highly configurable tools like git? While pairing with others or even using a common dev box, I like to use plain vanilla CLI git without intricate aliases, without intelligent git hooks, or other fancy extensions as far as possible.


What post about Git Koans? I did a google search, but nothing came up.


Snapshot stack? Huh.

git checkout -b

seems a lot simpler.


Simpler indeed. That's actually what stash does internally.

I usually don't make a separate branch, but just commit it in the current branch. Then you can rebase or amend later. You never need 'snapshot' if you know rebase -i.


You can also just `git reset HEAD~1` if you want to have your index reflect the changes rather than just working on top of an empty index in a new commit. My workflow is a --no-verify commit on the branch, then when I come back, just reset to the previous commit and continue.

This is pretty much identical to stashing, though I prefer it since it means the part of git I use is smaller.


I use this pattern from time to time (and should probably alias it). While checkout -b (or reset --hard <hash>) is good for most cases, I like making a stash entry if I'm in the middle of a logical unit of work and don't want to commit before I do something experimental.


we're also using a small script[1] that prevents committing debug statements by mistake. We put it as a pre-commit hook and also as a standalone check on our CI. It saved us from embarrassing mistakes in production several times...

[1]http://stackoverflow.com/a/14738093/305019


> Get everything you can into git hooks

This is a great idea, and it's one that my company provides: https://circleci.com. You can run standard tests, but also linters and whatever you want to increase your code quality. Users report higher productivity, and shipping code faster!


That's a nice, solid feeling product. I'm going to check it out properly soon.


Awesome! Feel free to ask any questions.


I don't understand the part about .gitignore not working for passwords.php: because that’s committed too, so then you risk someone forgetting about their valid edits of the file later.


Ah, I've just tried this locally. I was sure an edited, already checked in file would remain 'hidden' if in gitignore. My mistake, will update the article.


Gotcha, I love those "them and us" commands, thanks!


What's the reasoning behind the hack "!f(){}; f" getting shell arguments to work properly?


Does anyone here know of a good 3-way merge tool for Git that's available on OSX?


KDiff3 has worked nice for me and it seems to be availabe for OS X too: http://kdiff3.sourceforge.net/

(however I have not tested it on an OS X)


What is the difference between minimal and patience for git diff?


Seriously, command line for this sort of stuff? Also being stressed over source control when it is not deleting something permanently? Really?




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: