Lately I'm paying more attention to the Git commands I run to help script Getting Git. I have so much material at this point, I was told to turn some of it into a blog post.
What I've found from speaking and pairing is that most of us aren't as comfortable with Git as we might like to be. It's sharing insight into the Git command options and workflows that developers really seem to enjoy.
So here are three Git commands I use every day. Yes, I'm going to skip
git status. No, they aren't Git commands you've never heard.
1: git add -p
So you've been hacking away all day on some changes, then you add all of them with
git add . or
git add -A.
Oh, the irony.
Leaving aside the heavy handed nature of these commands, you spent all that time crafting changes just to throw them in the Git repository. It's like preparing a nice meal, then shoving it all in your mouth at once.
When I complete my changes, I prefer running
git add -p. The
-p stands for patch. Running this command allows you to interactively review each of your changes. In doing so you can decide if you want to add the change or not.
While more time consuming than
git add ., it's well worth it. More often than not I find some changes I probably don't want to commit -- a comment or debug statement.
git add -p provides a final review to ensure my changes are ready to be committed.
2: git commit --amend --no-edit
When working on something, I usually only make one or two commits total. However, given the 10x ratio of reading code versus writing code these commits might happen over a long period of time. In between that time I like to make small, incremental commits -- even if it's just a WIP commit.
For these commits, I like to use
git commit --amend --no-edit. Yes, I know I can use
git rebase instead. But most of the time work is done sequential. So I don't need to need all that, I can simply append my changes to the previous comment.
This also allows me to keep a clean state, which makes it easier to run other Git commands as well as keep track of my changes over time. It also provides the freedom to spike on some changes that I may not end up using without relying on ⌘-z.
I'll admit, this starts to get into what I consider a commit (which I'll wrote about in my next post).
3: git reset --hard
I know a few of you just freaked out. Some people find
git reset scary, especially when run with the
--hard option. However I find it complements the other two commands. For example, if there were changes I didn't add with
git add -p or changes from a spike I didn't want to commit I can easily discard them with
git reset --hard.
Now, that's not to say you should be cavalier with
git reset --hard. There are still some scary stories. Simply being mindful will mitigate this fear. In reality, you should never be afraid to run a Git command when armed with
git reflog and
In the end, I think these 3 Git commands say more to my everyday workflow. Maybe you see how they fit into your own. I explain these and over 20 other Git commands in my upcoming video series Getting Git. Which is now available in early access. And check out my next post on when I make commits.
Top comments (20)
This post really highlights some of my pet peeves with Git and Git users. Git makes you memorize these long lists of undecipherable flags (
--interactive?) to do your DAILY tasks properly, and then on top the users end up feeling they are particularly clever having come up with these commands.
Your tools should allow you to work efficiently and correctly WITHOUT having to google for blog posts or spending eons on figuring out the most optimal set of flags. Your tools should NOT make correct use of them make you feel like you've been particularly clever. Git users also tend to have this weird attitude where they think they are clever for using the CLI for everything. Just use the CLI for the things the CLI is good at, and leave the rest for good and efficient GUIs.
I regularly see Git users use
git add . && git commit -m '' && git push -fbecause they're too lazy to figure out how their tools work, as their tools are garbage. You should use tools made for human beings instead of tools made by Linus.
Bottom line for me is that most people using Git should really be using Mercurial. There are some people like Linus who are beyond help and can never see reason, but the rest still have a chance. Why Mercurial? Well it's mostly like Git, except made to be used by people who are not Linus.
You should use a GUI for commits. Really do. You will get a diff of all changes that you SHOULD go through before committing, and you always interactively choose which changes get added. If you must use Git there are nowadays a few available e.g. SourceTree, GitKraken and various others available git-scm.com/downloads/guis .. For Mercurial there has been a really good GUI available for a very long time, TortoiseHG. Never wanted another one, it does everything I need from a GUI.
You should use tools made for human beings, that don't require mystical flags to do your job right. If you need to figure out mystical flags to be able to do interactive commits and choose and view which of your changes go to each commit, you are using the wrong tools. Mercurial btw has much more human readable flags for CLI usage, all the extra stuff you shouldn't need daily or is potentially dangerous is "hidden away" as extensions (e.g.
purgeextension, which removes all files from your checkout that are not in your repository) , while still most of the useful ones are still bundled with the base distribution and are simply disabled.
Your should use tools that are easily interoperable, and cross-platform, with minimal jumping through hoops. Git was made by Linus, for Linus, and practically only supports his workflow efficiently. Mercurial was made by people, for people, so extensions, hooks, etc. can be written using many different tools, including Python. Python runs on practically every machine ever made, unlike your BASH scripts and random binaries you stick in your Git hooks.
I've been using DVCS since way before most people knew what they were, and I've got a long history using both Git and Mercurial for various kinds of professional and hobby projects. In my experience Git really is unsuitable for anything but the smallest of hobby projects, and I would never elect to use it for any professional work on a project that is expected to grow beyond 1 developer.
I understand and agree with most of what you point out here. But can you go into more details about what you mean when you say Mercurial scales better Git? I have an understanding of how Git suffers at a big scale. It also explains why companies like Google, Facebook, and till very recently Microsoft do not use Git. I know that Facebook uses Mercurial, but I believe they do hack it in some way to use it at such scale. The only reason why Microsoft is switching to Git is they can also afford to hack it, thus their GVFS project.
I have no idea where you read that Mercurial scales better than Git, since I sure didn't use the word "scale". However, if talking about the project and team growing, Mercurial makes it easier for growing teams to extend it to their needs.
It works better when you have team members with significantly varying environments due to the use of Python vs. relying on BASH scripts/binaries for hooks etc, and the extensibility and wide variety of already available great extensions does make it easier to tune how Mercurial works specifically for you.
Facebook does not "hack" it. They use it in it's intended way, using the extension APIs.
I used Scale as a broad term here. I used it because of your last paragraph about using git for small projects only, basically scale includes the number of developers.
Also, I believe that Git hooks can be written in any language you are comfortable with, especially Python.
Yes Facebook hacked Mercurial same way Microsoft is hacking Git with GVFS. It is literally almost the same story but two different systems. Microsoft has been actively contributing to Git along with Google Android project, same way Facebook contributed over 500 patches to Mercurial. GVFS is going to serve a skeleton of the repo similar to what remotefilelog does. This is done to hack both systems into thinking that their files are there locally.
From what I gathered, there is not much of a difference between both systems except for your opinion on them. In other words, Facebook only used Mercurial because "they" deemed it easier to change rather than do what Microsoft or Atom did with Git.
When you say Linus build Git to be used Linus (i.e a truly distributed use), same idea applies to Mercurial as a DVCS since Facebook cannot use it in a central manner without it breaking.
All opinions aside, both systems are good but Git would be a better option to learn and get used to given its bigger user base, this is including all its commands options inconsistencies not an opinion over how human readable they are.
I really don't think you understand the concept of "extensions". Try to google for "Git extensions" or "Git extensibility". Just try it, see what you find.
You also don't understand what I mean with Python hooks as you didn't bother to read anything about it. Mercurial can literally call Python functions with clear arguments, where these Python functions have access to the Python API Mercurial provides for them, which is a whole lot more powerful and cross-platform than Git hooks could ever be.
Also you seem to be using the word "hacking" in a rather uncommon way. Creating extensions using the APIs designed for it is not "hacking", it is creating extensions. Most of the great extensions FB made for Mercurial are also available as open source.
And no, you really do not understand the differences between Git and Mercurial. If you only think about "Git vs SVN" or "Mercurial vs SVN" yes, Git and Mercurial are similar. They ARE both DVCS systems based on similar ideas. However, if you think "Git vs Mercurial" there are many very clear differences.
Please do read the material provided before jumping into conclusions of your own. from FB's post: "Our engineers were comfortable with Git and we preferred to stay with a familiar tool, so we took a long, hard look at improving it to work at scale. After much deliberation, we concluded that Git's internals would be difficult to work with for an ambitious scaling project.".
"When you say Linus build Git to be used Linus (i.e a truly distributed use)", no, you are putting words in my mouth and interpreting them to mean something completely different. I did not mean he built it to be truly distributed, I meant he built it for HIMSELF and for his problems, using flags and designs HE was comfortable with, ignoring every other person on the planet, like he tends to do. You CAN use both Git and Mercurial in a centralized manner, just look at GitHub and BitBucket, that however has NOTHING to do with anything I said. The difference I was highlighting was that Mercurial has been built for other people to use, Git has been built for Linus to use, thus Mercurial ended up being a lot more friendly to other people.
Also your last point is such a clear logical fallacy it's laughable. yourlogicalfallacyis.com/bandwagon
No, something being more popular does not make it a better choice. No, you do not have to choose only one country and city to live in, one language to program in, one OS to use, one tool for any job, and most definitely you should not choose these facts based on perceived popularity.
git add -pis nice, I believe the use case of "hacking all day on some changes" without committing any code should be avoided when possible.
Commit early and commit often. This gives me a safety net for when I screw something up. At the end of the day, I can
git rebase -i start-of-dayto clean up the mess. It is a bit less beginner-friendly, but I like it. Then again, I also like splitting commits during a rebase, as it allows me to "test" them individually during the rebase.
git-add -pisn't just for hacking all day without committing any code. I use it for two reasons:
git diff. It also allows me to exclude things that I don't want to check in, such as random extra bits of logging that I no longer need.
git rebase -iwith
Note that I also have
git cialiased to
git commit --verbose, which shows me the diffs in the editor window at commit time.
I totally agree.
git add -pis a wonderful command. But having spent too much time convincing co-workers and friends to commit early, I had to make that comment.
I didn't know about
git commit --verbose. That's neat!
As far as rebasing workflows go, I like aliasing
git commit --fixupto
git fix, so that I can "fix" any relevant commits. The log ends up looking really weird before the rebase, but since I know where each commit should go, it is not an issue.
Sure. I get that. I commit all the time, to the point that my commit comments are generally just things like
safsahghhfdddd, and might only be a line or two.
Once I'm starting to be happy with my branch, I go back with
git rebase -i(using
git reset HEAD~) and
git add -pto split the changes into sensible pieces.
Then I reorder the commits and squash/fixup as relevant so that my PR forms a coherent "story".
I frequently find myself pulling smaller refactorings to the start of the branch, so that they can be cherry-picked into master separately from the other changes. This allows other team members to start using those changes immediately, and reduces the number of conflicts.
Similar to your notes on
add -p, I prefer
checkout -pas an alternative to
reset --hard- you can make sure you're not throwing something away that you missed during the
addprocess. It works exactly the same way as
add -p, you can choose to ignore or throw away piece by piece.
Two out of three. :) I have
git amendas aliases.
Good idea to add aliases for these.
git reset --hardshould be avoided. Better remove unwanted changes changes with
git checkout --patchand then use
--hard's safe brother
git reset --keep.
git bisectis one of the best git commands if you are in trouble :)
I've been use gitx, which is a pretty version of gitk for ages just for the purpose of reading through commit diffs and writing commit messages, and staging/unstaging files. It supports amend as well, which I use a lot. It's one of those things where having a nice UI to review a lot of diffs quickly is a bonus.
Other than that, my git workflow is entirely command line based. I have two aliases: gitu, and gitc that for git fetch && git pull --rebase and git fetch && git push origin. So with gitx, gitu, and gitc I pretty much have my day to day workflow. I also have a gitl alias tied to a fancy customised git log commandline. Other than that, there's the occasional merge and branch juggling. Maybe an occasional cherry-pick and a reset git --hard in case I have unstaged changes I no longer care about.
In regards to
git add -p, I personally just use
git diff --staged.
That's another good one. I recommend tacking on the
-woption to avoid noisy whitespace changes.
The main point is to review your changes before blindly adding them. In the end, whatever command helps you do this is an implementation detail.
In my experience, git reset --hard is nice, but it doesn't get the job fully done because I've added new files or folders, so I often have to use git clean in combination with --hard. As a newbie, I was surprised that you had to use a second step to remove any newly created files after the hard reset and have always been puzzled that it's not a one command kind of thing.
Git stash is a nice way to handle some aspects of 3!
just try it