Since git 2.9 there is another experimental, opt-in, improvement to git diff that results in more readable diffs: Heuristics that try to capture the logical changes better. By default git tries to delay the start of diffs as long as possible leading to bogus highlighting of e.g. doc comments (slash star star).
For readers in a hurry, careful: `compactionHeuristic` ended up deprecated in Git 2.11 . The experimental heuristic to add to a >=2.11 .gitconfig is now `indentHeuristic`, see OP's second link :)
The compactionHeuristic was removed entirely in the 2.12.0 release. You can't enable both since only the indentHeuristic exists now, and serves pretty much the same purpose.
git-overview: Short report about top committers, files with most commits and most authors. Nice when you checkout a non-trivial repo for the first time.
git-onNotify: Do something (like `make`) whenever a tracked file changes. Usually used to build LaTeX and static websites.
git-randomline: Chooses a random file and a random line number there. The game is explain that single line to some fellow. Do this repeatedly to spread knowledge about a codebase.
I have not used it in a while, but I actually have a good occasion soon. I just updated it to only return interesting lines, which for now means at least 10 letters. That filters lines like "}".
I have his "git recent" alias, and then in .bashrc
alias co='select br in $(git recent); do git co $br; break; done'
so when I type "co" at the command prompt I get a numbered menu of branches in the order I last checked them out, and can just type a branch's number and hit return to check it out again.
I use a different version of git-recent that Paul Irish wrote (https://github.com/paulirish/git-recent) but thats pretty slick - thanks for sharing. Might have to switch - although sometimes its nice to also have the context.
The dots mean there are more arguments. The point is, every once in a while I analyse my shell history and add aliases for the most used commands. Looking at it now, it seems I should add aliases for `git push` and `vi Makefile`.
I also have the aliases g for git, m for make, and v for vim.
Which is better than if they have the same aliases as you, but they mean something else. I had an interesting time a while ago until I understood that my coworker uses 'st' for stash instead of status.
It's a ps/pdf toolkit type program. It is used by imagemagick as a backend for pdf conversion type stuff - so if you every need imagemagick you might find yourself in for some annoyance as well.
How much time does that actually save? I find that for any given task, I spend far more time reading and thinking than I do typing, and of the time spent typing, most of it is spent typing arguments.
I use `git diff` and `git log --graph --decorate --all --oneline` and `git status` so often, that it totally saves heaps of time. Especially the second one ― I usually type my `gl` somewhat subconsciously already; only afterwards I realize what I'm looking at, and start reading. That's possibly related to the fact that I commit very often, use many working branches, and then rebase -i (usually squashing and composing a good readable commit message) before publishing.
But anyway, if someone asks for help with "how to fix my mess in git", the absolutely first thing I do is exactly `git log --graph --decorate --all --oneline`, to start finding out visually what the mess actually is.
IIUC, the --abbrev-commit is unnecessary there, --oneline already does it. Makes the incantation possible to remember and type on a foreign console: "git log --graph --oneline --decorate --all"
edit: yep, per git help log:
--oneline
This is a shorthand for "--pretty=oneline --abbrev-commit"
used together.
I have similar aliases and have a similar concern. I usually think "git status" when I type gs. This way I hope I would be able to work without my aliases somewhere else (even though it would take longer since I have to remember to type the whole command).
I find this reassuring as I sometimes feel behind the times for using command line git instead of some fancy WYSIWYG interface. Am I in a minority or not? Is command line the preferred way and if so is it more productive? I just do commits to master, I don't do fancy hotfixes, feature branches squashed to master or fancy bisects. Maybe a merge conflict in my colleague's CSS is as hard as it gets for me.
Seriously, the more complex your use case is, the better the command line gets.
Personally, I use mostly command line git and on occasion a little bit of gitk if I get lost between all the branches. I die a little (read: a lot) inside when I have to help my team members with git and they adamantly stick to TortoiseGit. It's a prime example of the UI improving discoverability at the expense of performance (and even then the individual actions tend to get lost between all the numerous possible actions).
This discussion got me thinking about my push habits. While I only have to type `g psh`, the actual process has more commands. I check that I'm on the correct branch, check which commits will get pushed, and maybe even the diffs of the commits. Sometimes I have to rebase, fixup, and squash stuff.
It is similar for committing, where checking diffs and partial adding is part of the process.
Using an IDE or GUI might help to streamline this. I do not use any, so I don't know if they do this.
Maybe I should analyse my shell history for sequences?
Here is my own DSL. Interesting that it turns out we have similar aliases...
alias ga='git add'
alias gb='git branch'
alias gbD='gb -D '
alias gbc='gc -b '
alias gbd='gb -d '
alias gc='git checkout'
alias gcm='git checkout master'
alias gd='git diff '
alias gdd='gd --cached'
alias gdm='gd master...'
alias ge='git grep -InE '
alias gec='git branch --remotes --contains '
alias geh='git log --all --oneline --decorate -G '
alias gei='ge -i'
alias gff='gh && gpr && gr && ghp'
alias gfm='b=$(gw) && [[ "$b" != master ]] && gcm && gpr && gfu && gr && gc $b && unset b'
alias gfr='git fetch && git rebase origin/master'
alias gfu='git fetch upstream && git merge upstream/$(gw)'
alias gh='git stash'
alias gha='gh -k'
alias ghp='gh pop'
alias ghs='gh show -p '
alias gl='git log --graph --decorate --all'
alias gll='gl --pretty=format:"%C(yellow)%h %Cred%ad %Cblue%an%Cgreen%d %Creset%s" --relative-date'
alias glll='gl --color --graph --pretty=format:'\''%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%C(bold blue)<%an>%Creset'\'' --abbrev-commit'
alias gp='git pull '
alias gpr='git pull origin $(gw)'
alias gps='git push'
alias gpt='gps --tags'
alias gr='git push origin $(gw)'
alias grr='git rebase -i HEAD~$(grrr | wc -l)'
alias grrr='git rev-list master..'
alias grt='gr --tags'
alias gs='git status'
alias gss='git show'
alias gu='git config --get remote.origin.url'
alias gv='git describe --abbrev --dirty --always --tags'
alias gw='git rev-parse --abbrev-ref HEAD 2>/dev/null'
alias gx='git archive --format tar --remote '
If shell aliases don't tab-complete for you, you can get tab completion just by defining git aliases instead. One extra space if you also alias g=git. And it solves namespacing.
I don't know if it's the same in bash, but at least in zsh, "git branch <TAB>" and "b <TAB>" have the exact same result, if b is aliased to "git branch"; the first tab fills in the name of the branch, another lets me select a commit, and further tabs are command line options.
I like how he creates an alias to blame called praise. He's right, blame is a loaded word. The command I really use to "blame" people is bisect... though sometimes I use that to find something good too
I don't know, "praise" is a really generic word. "Blame" very specifically means, "who did this." And I feel like it's often used in a non-disparaging way: "Who organized this surprise party?" "You can blame me."
Also, truthly, if you're looking to see who/win a line of code was authored, it's almost always because you're tracking down a problem. :)
I actually did read the fine article afterwards and noticed that. Nice job, in fact this was one of the few HN submissions that drew me to both the comments and the article!
> Are we really that afraid of hurting someone’s feelings…
I don’t do it to save peoples’ feelings: I do it because there are two separate use cases for determining the author of something—sometimes I really do not want to blame[1] someone.
1. blame — verb: feel or declare that (someone or something) is responsible for a fault or wrong.
I always thought of it as blaming a commit for a change, not a person for a mistake. I can see how it could be taken badly though since the output makes a point of putting the author's name next to the commit id.
Basically, if you're in the directory `~/something/src/projectname/foo/com/something/bar/baz`, and want to get back up to say `~/something/src/projectname/foo`, `to foo` will do that. (Or `to oo` or `to o`; it matches the end of the name, and goes to the first match; `to ing` would go to `~/something/src/projectname/foo/com/something`).
> You’re not limited to just tags: you can use commit hashes.
Since tags, branches and `HEAD` are simply pointers to commits, it's good to know that you can interchange them and commits pretty much anywhere where you can use them (other than creating/deleting tags or branches, of course).
It's annoying that all the git commands start with 'git' unless you write your own aliases. It means you can't just type !sta to get the git status much less 'emacs !add:*' to edit the files you just added(!) ; you have to do a ^R search and edit. !git is almost never what you want unless it's just !! anyway. RCS had just co and ci and the like[+]
Clearly the guy who came up with this cockamamie scheme was unfamiliar with Linux. :-)
+ RCS was pretty bad too; I'm using it just for illustrative purposes
Something I love to do with git: make temporary commits at the tip of a branch so I can checkout other branches without losing anything. I much prefer this to stashes, generally. Stashes can still be useful to move changes from one branch to another, but generally I find changes make sense on the branch they were being written for.
> git commit -am "TMP COMMIT"
> git checkout ...
Once you switch back:
> git reset HEAD^
and you'll undo the temporary commit and be back to where you were.
Word-level diffs are very situational. In my experience they make the diff less readable more often than not, because they find the smallest common parts, which do not necessarily reflect the logical changes.
So how do largish binaries work in git nowadays? When I last looked (several years ago), the answer was essentially 'dont do it' or 'use this other tool to sort of make it work'. Can I store a few gigs of data (alongside my source code) in git?
I don't know how the situation has changed in regards to binaries, or if this is a good suggestion, I just remember reading about git-annex when it came out a few years ago.
Some binaries can be serialized so they at least function as text files for vanilla git's benefit. I did a project where we used LibreOffice or OpenOffice and we had a hook than unzipped the contents and flattened them into text for checking in and reversed that when checking out. It worked, technically, but we lost most of the benefits of git (tiny changes would lead to changes to several binary tables which lead to incomprehensible diffs). On the other hand the same project used gnuCAD which saves its files as text -- which was awesome: we made some edits (id changes and the like mostly) with sed and awk!
The big binaries problem is the sole reason anybody buys Perforce. It's horrible, but it does handle this case, and for folks like game developers there's little alternative.
I really do wish I could use git with solid works and Cadence files. Solidworks is the worst: their files are build with some Microsoft structured file library, and contain hard-coded paths; their dreadful proprietary SCM tool understands this and edits the file while checking it out to fit it to your local machine. Aaagh!
And it's all centralized. Recently we had an internet outage for a repo hosted on github: people still got work done and collaborated, pushing to and pulling from each others' machines until we had external access restored the next day. With FB down it was a pretty productive day!
I actually have that leaderboard alias in my gitconfig already.
I work on a codebase that's over 20 yrs old. A while back, I was interested to find out who had done the most commits, and what kind impact moving to git, with it's "commit early, commit often" mentality, had pushed newer players up the ranks. Suffice to say, it hadn't had as much impact as I was expecting yet.
.. shows progress for each branch .. this makes it surprisingly easy to see which of the developers in our group (with their own branches) is pushing the codebase further ..
This has nothing to do with developer assessment - its only for finding out, during the daily review, what branches have had the most activity and what is ready for the daily review.
This is why I wish Fossil were less opinionated and supported rebase and exposed branches and tags as the light-weight names that they are underneath the covers (just like git). Fossil uses SQL, which means that all of the things @csswizardry and much more that no git developer has ever thought of.. can be done with a little bit of SQL.
But no, Fossil's UI is like Mercurial's, and it favors merging over cherry-picking and rebasing. Their loss!
Fossil does have a cherry-pick operation, and anyways, one could trivially be constructed. Which means that rebase can also be constructed easily enough. But my impression is that the devs aren't interested in such contributions. And the heavy- vs. light-weight branching model in the UI is a big turn off even if I can deal with it at the SQL level. Fossil's push/pull model ([auto]sync everything) is also not to my liking -- sure, in a corporate environment pushing every branch is a good idea, but in an open source world it's not: I may want to push some branches to one upstream, others to another, and yet others not at all.
This is what I like about git:
- the index
- git exposes the Merkle hash tree concept at the lowest layer
- git branches and tags are just symbolic pointers to commits (see previous point)
- support for many remotes
- git is not opinionated -- if you want to use a merge-based workflow, you can, and if you want to rebase instead, you can, and if you have to use e-mail to exchange commits, you can, and so on.
I'm done with the Mercurial "you do what we say" model. A model they keep half-way reneging on, adding bookmarks (which don't work well), and histedit and rebase (why not both in one command?! "because we don't like git rebase" is the answer I imagine) (they really need to be one command!! what if in the process of rebasing you must drop commits that you know duplicate others in the new base?!).
I wish Fossil's developers saw this. But they're focused on their needs: VCS for SQLite3. Since they seem to have few topic branches, they like merging.
Conversely, since Fossil's devs refuse to be non-opinionated, I wish git's developers saw the power of SQL for VCS. It would save a ton of code C and shell code, and it would make new extensions trivial. It also would make git much more power-failure safe: since it could leave that to something like SQLite3 that does a fantastic job of it (and is very well tested, both in general and as to power failure safety).
Besides this, I wish git has branch history. That is, a single push can push multiple commits by different authors, so it would be nice if one could see who pushed what commits. This would be useful as documentation in and of itself: if you see N>1 commits pushed together and need to revert one of them, you might look at whether you need to revert the rest as well, as they might go together. (Some codebases like to push regression tests first, bug fixes after. This allows one to see that tests detect the bugs they're testing for and that corresponding bug fixes fix those bugs. If one has to revert a bug fix commit, one might have to also revert a corresponding test commit.)
Your mercurial experience is out of date. Mercurial now supports a rebase workflow better than git does (with github and their pull-request workflow dominating the world, nobody seems to rebase with git anymore). See the evolve extension, and for even more mindblowingly cool stuff, see mercurial absorb.
Mercurial seems to give merge tools better information when rebasing too. I've had to resolve some annoying conflicts when rebasing with git, and I've cloned the repository with hg-git and done the same rebase and had it go flawlessly.
Cool. Absorb sounds very nice. But even if bookmarks now work flawlessly such that I need never again deal with Mercurial's awful heavy-weight branching model, for me it's too late. This is what happens when you don't mind the store: someone else takes your business. Mercurial people spent years screaming about the evils of re-writing history only to now aim to provide a better rebase experience -- fantastic, but too late, the world has moved on.
Also, don't forget the index! I adore the index in git.
I hope people learn the value of not being opinionated when it comes to building mind-share. I know, being opinionated works for Apple, and Apple is a fantastically valuable company. But I don't think it works well for everyone else. Git's being not-opinionated may be the thing that is best about it.
There is something strange that I cannot explain. When I use git I am comfortable rebasing quite a lot. When I use fossil I do not miss it at all.
Similarly, when I use go I do not miss generics despite using them quite a lot when they are available in other languages.
So based on this, I both agree and disagree with your complaint about fossil not having rebase.
However, one place where I disagree is that fossil is not just VCS for SQLite3. Its github in a single executable -- much more powerful and potentially much more important for the opensource community. In some dystopian future developers will be using fossil over tor.
It's possible that if I started using Fossil seriously I'd have the same feeling as you. However, when I browse SQLite3's history, I still see a branched model, not clean, linear history.
I can imagine that a VCS might make merging so painless that one might not miss rebasing, but I would still prefer rebasing.
See https://github.com/blog/2188-git-2-9-has-been-released (section Beautiful diffs) for an example and http://blog.deveo.com/whats-new-in-git-2-11/#experimentalheu... for another similar option that I did not try yet.