It deletes all remote branches that are merged into the remote master. Because people always forget to click the "Delete branch" button after merging their pull requests.
While not an issue in Zsh, one bummer about using shell aliases in Bash is that auto-completion won't work. That doesn't really matter with an alias for `git status`, but it's annoying for plenty of others.
You can get around it doing the following:
_completion_loader git # manually load git completion functions
alias g='git'
__git_complete g _git
alias ga='git add'
__git_complete ga _git_add
Love #16 and the associated article. I cringe when I see something like "js fix" as a commit message.
However, not on board with the hate for rebase. If it's your feature branch and you aren't sharing it with others, I'd much rather get a cleaned up PR than one filled with junk commits because the author was afraid to rebase.
Nitpick with #16: I don't like when there is no "why" associated with a style rule. I'm speaking specifically to #3, "Capitalize the subject line". Why is this preferred to not capitalizing a subject line? Is there a reason, or is it an arbitrary decision (which would be fine - sometimes a style decision is, "We need a standard, and we chose this one." But I think the author of the style guide should explain that that's what they're doing).
But in general I liked the article. It's under-appreciated how helpful a good commit log is.
Sometimes commit message deserves to be moderately long, like a paragraph or more. If one did not reference a code review or issue tracker link, for example, the need would likely be common. Even with an issue tracker there's value in capturing a few sentences of detail and sometimes more in the commit.
By capitalizing the commit message, it is natural to extend it from a single sentence phrase to a paragraph with an introductory sentence. I think of commit messages as analogous to JavaDoc where the first sentence or first line is taken as the subject, or like a document with a heading. It would be silly for short commit messages not to use capitalization while long do. A capitalized message works as a short description of the intro to a paragraph. Generally. once you're writing more than a single standalone sentence, capitalize. In a permanent medium where it can be either one, also capitalize.
A capitalized sentence or sentence fragment works in many contexts, like within a document or email. It would be annoying to convert going back and forth. Lastly, commit messages can sometimes act as names or proper nouns, and capitalization reinforces that role. Capitalization looks better as project or item headers in an issue tracker, and so to the extent that commits follow items, it's nice to consistently capitalize.
Capitalize commit messages because when Git tools generate commit messages, they generate capitalized ones. (Be consistent.)
I grok not capitalizing IM or IRC or other chat conversations, though I do if I start writing messages longer than a sentence. For everything but IM, capitalization constitutes the norm and good professional style.
This rationale might not be entirely satisfying, because why does English have capitalization to begin with? That's a linguistic question I don't know the answer to. However, I do know that the norms that lead to sentence capitalization also apply to commit messages and code documentation Not capitalizing them feels like refusing to capitalize any other writing: a potential distraction from the content.
If the component name is conventionally written in lower case, because it's a technical term, then I think a comment written in this way counts as good style. I might choose to capitalize Foo myself, but I think foo is defensible in that context.
Where `<type>` is the type of change (e.g. `feat` for a feature or `docs` for doc updates), `<scope>` is the scope of a change, `<subject>` is the subject line, with the first letter uncapitalized, `<body>` being an explanation of the change in imperative, present tense, and the `<footer>` containing information about breaking changes and any issues the commit closes.
I like it because I find that adhering to this style lets me have a nice seat of easy to read commits which explain their purpose and scope clearly.
Also, it lets me use a tool like `clog-cli` [1] to generate pretty changelogs [2] automatically!
The only nitpick I have with this style is the fact that they recommend not capitalizing the first letter of the subject line. This means that, for example, in emails or when creating a PR, I have to capitalize the summary so that it looks correct. Minor, but annoying.
Capitalizing the subject line makes commit logs much easier to read in my opinion. There's a reason we capitalize letters at the beginning of sentences
But it's not the beginning of a sentence. It's supposed to be a continuation of the implicit phrase "When applied this commit will ..." In which case capitalizing makes no sense.
> It's supposed to be a continuation of the implicit phrase "When applied this commit will ..."
No: it's supposed to be written in imperative form. For those of us who are not linguists, it's easiest to explain this as a continuation of that phrase. However, it isn't a continuation. It stands on its own.
I would be cautious about getting into the habit of squashing lots of changes together into one commit before sending upstream. It makes git bisect harder. Squashing is fine, but I suggest preferring several commits of logical units of change over one commit for a whole feature.
I can't recall where now, but I remember reading (and agreeing with) an article which proposed a slightly different format - describe what the commit did. "Fixes the js typo on the foo page".
Grammatically, I prefer this method as well, since the commit has already been applied, so it's not "going" to do anything; it's already been done.
Of course, the only difference is in the tense of the leading verb, so it's probably one of those "potato" thing.
Well, especially if you take the source article to heart, "Fix" is actually future tense - "When applied this commit will fix the JS typo on foo page for Chrome". "Fixes" would indicate the present tense: "This commit fixes the JS typo [...]"
Fair enough, but how does a command apply to a git commit? If it's telling the git commit what to do, that doesn't make sense, since the commit comment is supposed to be about the commit, not a command to the commit.
If it's telling me what to do, that doesn't make any sense either, since the work's already been done; the results of doing that work is the commit.
I guess it could be considered to be an abstraction of what request initiated the change, but what value does that provide when going back through git logs (when compared to a past or present verb tense that describes the changes)?
I think the actualy reason for the choice of tense is brevity. Fix is three characters fixes or fixed is five, similar for update vs updates/updated, add vs adds/added etc.
I'm an avid supporter of rebasing over merging. I'll refrain from getting into my workflow, but here's what i want to say: For the love of all that is holy, never squash a merge commit nor squash onto a merge commit.
Squashing a merge commit is a perfect way to reintroduce old code back into master.
Squashing onto a merge commit is great way to lose changes. It's been a while since I have tried this, but creating a didactic repo if fairly easy. Create a repo with two feature branches, a file on each of master and the feature branches, merge featureA to featureB, make some changes or delete a file, `commit --amend` on the merge, and merge featureB to master. Then use `git cat-file` to look at those commits and commit trees. I've seen mysterious things such as simple as unreported changes to files mysteriously being deleted from the repo.
I use git often on the command line, especially for non-trivial tasks, but do not quite understand why someone would pick it for routine committing/tree view over a GUI. I find the ability to graphically see the state of the working tree and the index, and being able to stage/unstage individual lines by visual selection in a non-linear way absolutely natural. Likewise, the ability to get a context menu for a commit in a tree view and fire a command (rebase/branch most often) seems like something git was "built" for.
I, on the other hand, am very uncomfortable using a GUI for such things, and find it extremely distracting to switch back and forth between the CLI and a GUI. Luckily, we both have options that do what we want and work for our particular tasks/skills/aptitudes/learning-style/whatever you want to call it.
I spend a lot of time in the commmandline, so it makes sense for me to not use a GUI. This alias (in ~/.gitcofig) is gold for most of the "graphical" stuff I'd use something like SourceTree for.
In Git's early history the vast majority of its users were people who significantly preferred the command line interfaces over GUI tools because they can be much quicker (if that is how you work normally at least) and easier to automate. In fact at first there were no GUI tools at all. There is an amount of momentum in tutorials being written for the command line, so people learn from the command line, so people write their procedures/tutorials/other from that perspective.
And it makes sense to learn the basics in its native form and then learn the useful trinkets that are added on top - then your initial learning is restricted to the core so you are learning that which is transferable to all Git front-ends rather than learning specific to a particular GUI.
The way advanced users tend to work in my limited experience (I'm am very much not an advanced user) is to use the command line for the basic day-to-day working and then the GUI tools when anything more complicated (large and/or partial merges) is required.
Since interactive rebase was mentioned I'd recommend taking a look at its --autosquash flag and the --fixup flag of commit. With autosquash the interactive rebase will move fixup commits to where they belong:
git commit --fixup=<commitref>
git rebase -i --autosquash HEAD~5
My recommendation: configure the shell prompt (add __git_ps1 to $PS1), this saves a ton of time and makes it much easier to understand what is going on. Especially recommended for beginners (but obviously not limited to).
I hope I'm not the only one who thinks that "Update README file" is a poor commit message. It's overly nondescript. A better commit message would be "Update README install instructions" or "Fix README links to dependencies" or anything else that better describes what about the README file was updated.
My #1 git tip to anyone who will listen: use magit. Having the options for each command within easy reach makes getting git to do the right thing so much easier, and the UI feels very emacs.
If they're relevant to the code change ("Not sure what I did, but the tests are passing now ¯\_(ツ)_/¯", "Removing production usernames and passwords from front-end config files, MIKE ಠ_ಠ"), it's fine.
If I see a commit that's just "¯\_(ツ)_/¯", I will force-push over it, don't you even think about it.
At my old job I had to do a major cleanup of a git repo with dozens of old branches. I got really good with the `git log` command. Here my alias form my ~/.gitconfig that shows author, branches, and remotes in a colorful manner:
Sorry for the delay, the main idea is to show all the branches on the different remotes:
* 2016-04-11 86f68c3 Ivan Savov (HEAD, origin/bugfix/math_valign, bugfix/math_valign) Better solution to
| * 2016-01-20 df77345 Ivan Savov (origin/miniref, miniref) Customizations necessary for no BS math render
|/
* 2016-04-07 364619f Michael Hartl (upstream/stable, upstream/master, origin/master, origin/HEAD, master) Change to bigger line height for EPUB/MOBI
* 2016-04-07 92952da Michael Hartl Bump version
* 2016-04-07 6a56c24 Michael Hartl Merge pull request #152 from jackkinsella/patch-2
|\
| * 2016-03-23 216d410 Jack Kinsella softcover check compatible with brew
* | 2016-04-07 d792d4b Michael Hartl Merge branch 'minireference-feature/math_valign'
|\ \
| * \ 2016-04-07 5fa560e Michael Hartl Merge branch 'feature/math_valign' of https://github.com/minireference/softcover into minireference-feature/math_valign
| |\ \
| | |/
| |/|
| | * 2016-01-31 77a4e5e Ivan Savov (origin/feature/math_valign, feature/math_valign) Set veritcal-align for better looking inline math
* | | 2016-04-07 a369139 Michael Hartl Update README
|/ /
* | 2016-03-21 0e94095 Michael Hartl Bump version number
* | 2016-03-21 a5fbc82 Michael Hartl Reuse menu headings in MOBI ToC
* | 2016-03-21 fadd558 Michael Hartl Merge branch 'master' of https://github.com/softcover/softcover
|\ \
| |/
| * 2016-03-16 60dc7c9 Nick Merwin (tag: v1.2.5) added exercise generator for course chapters
* | 2016-03-12 fe2f844 Michael Hartl Lower the EPUB/MOBI line height
|/
* 2016-03-10 bba610b Michael Hartl Make anal changes
* 2016-03-10 c9bad17 Michael Hartl (tag: v1.2.4) Bump version number
* 2016-03-10 8edf40a Michael Hartl Add symbols for euros and pounds
Great set of tips. Unfortunately I find that so many post that suggest rebase recommend against force pushing. This takes a lot of the power away from rebase/amend. So much does this happen that is wrote a blog post titled "You should force push more"[0].
My current understanding is that... "it depends". I like that you identified ground rules/preconditions for aggressive force-pushing.
Imagine a scenario for a large team (think kernel). Chat logs of a team developing some feature look something like:
A: Ok, I have finished with issue1, check out commit abcd1
B: Hm, does not work for me. Looks like race condition in foo.c, fixed in abce2. Going to sleep.
C: You broke init_foo(), reverted in qwer3
A: Ok, modified init_bar() works on my machine, check dvor4
C: LGTM
Yet release branch contains all those commits squashed into abcd1. Now person B (or anyone else) has no idea whether which versions of init_foo() and init_bar() work on their machine and what to fix.
We sometimes tend to forget (and tools like github/gitlab help with that) that not only git, but the whole workflow might be distributed and changing history in one place might desync it with other places. I think that unless all that history is absolutely unnecessary, e.g. done by a single developer, is extremely well tested, contains loads of "oops" commits, history should not be messed with. That's why all the warnings: git cannot manage all the references to history
My favourite tip for commit messages: write them as if you would explain someone how to do what was done in the commit. So, instead of "fixed a bug" use "replace datetime object with date". It can be more abstract for larger commits (e.g. "refactor payments"), but it should be roughly analogue to what you would write to a ticket title to the same effect.
I usually rely on travis-ci to do this after I've committed and pushed to a branch (and only merge back when I get a green result, this is shown neatly in the Github UI).
A pre-commit hook probably works fine if your tests run in a few seconds. But in one of my projects, tests run for 10+ minutes and I want to get a test run on debug and release builds with a few different compiler versions. That's about 50 minutes of CPU time (but embarassingly parallelizable, although I typically don't do that). I don't want to have to wait for this to happen before every commit (not all of which even require testing, e.g. README commits).
I seriously must be doing something wrong, but when I'm doing an interactive rebase, if it stops due to a merge conflict I sometimes find I need to tweak other files, and to add the files to git I find I do the following:
git add $(git diff --name-only)
Am I wrong, or is this the right way of doing this?
For experienced users, I do agree wholeheartedly. However, to learn how and why git works, it is much more intuitive to work from the command line for a while. For example, you can browse the .git directory, see how refs work, browse through the logs, etc. etc.
Another reason why I advice learning the command line interface first is that it is the most versatile, so it's helpful to be able to fall back to it when necessary. Every GUI tool I've seen so far lacks a feature or two.
For learning what 'rebase', 'merge', 'sqush', 'git fetch', 'git pull' does it is nice to have a GUI. Command line on the other hand is usefull to restore lost commits with 'git log' and 'git reset' and I find it quite advanced topic. I think all basic commands are all in GUIS so those that I listed in first line.
I'm still not even quite sure how to a) discard edits that I've made but not added/committed yet and b) delete something from a repo that I added accidentally.
will discard edits which you've not added to the index. This command is destructive of course.
git rm -f somefile
will delete a file from the repo (you then have to commit the change). If you want to permanently delete a file, including from history, eg because it contains a password, that's a bit more difficult, but possible in some circumstances.
a) You can also use `git checkout -p` here that lets you selectively revert patches
I can also recommend these two aliases I have in my gitconfig:
unstage = reset HEAD --
undo = reset --soft HEAD^
`unstage` takes an argument and removes changes from the index (but keeps them in the file). `undo` undos the last commit and puts the changes into the index.
Unstage you pass a file or `.` for all
git checkout <file> to discard. This will checkout the full file to latest version tracked. Alternatively If you wanna save some of the file you can use git add -p <file> and stage the individual parts you want. After you've committed those you can checkout the file.
git rm <file> to delete something you've added accidentally
I used reflog for the first time a few days ago. I rebased a branch, and somewhere i messed up the conflict resolution, so I wanted to undo the rebase. It was surprisingly easy!
reflog is one of these things where you think "that would have been awesome to have" in hindsight.
In 2009 or so, I was using git-svn on the KDE SVN. I was preparing a major refactoring of Kolf in a local branch (about 60 commits with 10000 lines changed), and pushed it to the SVN once I was satisfied with it.
Unfortunately, the 20th-or-so commit failed because a SVN pre-commit hook rejected it (there were some DOS line-endings in a source file that I imported). At that time, git-svn was (AFAIR) already prepared to handle a failing SVN pre-commit hook on the first commit (e.g. when authorization is missing or stuff like that), but not somewhere in the middle.
The end result was that my working copy, my index, and my master branch was completely trashed. And I didn't have a backup... Luckily, the tip commit of my feature branch had not yet been packed, so a clever grep on .git/objects found it, and I could recover my pre-push state.
Since then, reflog has always been enabled on my systems. Luckily, I haven't needed it since.
EDIT: And another thing. Turn all your Git aliases into shell aliases (e.g. "git status" is aliased to "git st" is aliased to just "st" on my system) with this one weird trick! https://github.com/majewsky/devenv/blob/2c4252d37597617a493f...