Oh shit, git: Getting myself out of bad situations
ohshitgit.com
ohshitgit.com
I think anyone who uses the CLI is either trying too hard or hasn't realized the beauty of a git GUI.
Takeaways:
- My commit time is usually much faster than coworkers, with higher accuracy (less frequent accidental commits, etc.)
- I don't remember the last time I made an irreversible change to the repo, or had an "oh shit" moment. And that's despite using some interesting git features.
- Staging individual files, folders, lines of code, or hunks is easy. Makes maintaining multiple trains of though / addressing bugs while working on other code a non-issue.
- It's easy to keep files uncommitted for long periods of time intentionally, without slowing down my workflow.
- It's much easier to get an overview of the changes I'm making.
I think maybe the term you're looking for is "freeware"?
It's impossible to sing those names loudly enough.
[0] https://news.ycombinator.com/item?id=12677542I've only had to merge a branch once, and here I was completely confused on what was going end. This may be SourceTree's fault or git's fault. Maybe my lack of understanding.
I hate git, I don't understand git, I don't want to have to understand git, and I think the command line interface makes every UI error in the book. But SourceTree has made me like git.
It treats my "assume everything works like vim" habit well
If we take Ranger for example, who calls itself the "CLI file manager", then Magit is rather a "git CLI".
Why? It is designed for git and graphically displays revisions allowing you to pick and chose chunks of file and to revert individual changes.
It's also free for hobby / open source
but worth buying for commerical work, but it is pricey, and I think getting the lifelong updates is the way to go.
I really like Magit, which is a git GUI you can use without leaving Emacs. It handles 90% of my git needs and is very tightly integrated into my IDE (Emacs). I still use some shell commands (like git mv) occasionally but those are simply m-! away.
- Open source (and free) - Multiplataform
The one with the best usability was Git Extensions: https://github.com/gitextensions/gitextensions
It is somewhat old ugly, and open a little too much of dialogs, but the workflow really works. It guides you to make the right thing.
A great plus is that it already comes with Kdiff3, a great open source 3 way diff open source program.
It doesn't have all the bells and whistles of a GUI, but if you need to look at all the branches, and commits to a repository. tig is an excellent tool. tig doesn't issue any commands though, its only a browser, you'll still need to know the CLI. (essentially a ncurses version of gitk)
I'm normally in a ssh session on a remote box where my compile & run cycles happen. tig is curses based, so no X11 needed, filled in a really nice itch of mine.
Don't use clients if you don't even understand the basic git workflows. And those usually don't support the advanced oh shit situations this article is about.
Probably a failure of whatever UI you're using. I manage just fine.
The common statement from CLI types is that "it's just whatever you're better at using" which is true conceptually, but practically, again, CLI users make more mistakes either from fat fingers or lack of understanding of git.
Understanding git conceptually from a UI point of view is easy. You don't even have to have a full understanding of git to be effective at using it, if the UI is good. I'm shit with the git CLI, but I understand what git is doing.
Yes it's easy to do dumb shit in a GUI, the same is true for CLI. In fact, it's less likely that there'd be a button for doing something dumb than it is that a git novice would find some command on StackOverflow and attempt to use it without fully understanding the ramifications of it.
In a CLI I know exactly what's happening.
That's just my opinion though. If people feel comfortable working in a GUI all the more power to them.
If you don’t have a good mental model for git, you’re gonna have a bad time.
Maybe not in the way Source Tree uses it, but there certainly is[1]! I've had to use it a few times.
> git-revert - Revert some existing commits
Why do you think it's okay to share this opinion?
Usually I use the included gitk to view the repo, and the CLI to manipulate it.
Or, you know, understands and thinks in the semantics of the underlying tool and is already working in other text-based tools.
(Note: I use the CLI almost exclusively.)
Even someone who perfectly understands git can make a typo or have a brain-fart of a day. A GUI significantly reduces the chances of something like that for all users.
Sometimes dev obsession with tool purity does more damage than good.
When I've tried GUI's, I'm not 100% sure what's going on under the covers. Sometimes they try to obfuscate things. While I'm probably not the worlds most advanced user, I know enough to know what I want to do, and how to do it. The CLI let's me do it. The GUI get's in my way.
This. A thousand times over. I like to see exactly what git is doing and when; I don't want any magic stuff under the covers done for me.
As soon as I saw that button I knew I'd have trouble using it.. what will "sync" do? Push my branches? Pull tracking branches? Will merge commits get implicitly created? Or will it just fetch? From what servers? I didn't want to risk having my local master get pushed into production just because GH wants to make things easy for me, so I just quit it and went back to the CLI.
Personally, I use the CLI and often have no idea what I'm doing ;)
The best one, I think, being Magit for Emacs (if you can call that a 'GUI' given you can run it in the terminal).
If you get used to commit things by-line instead of by-file (which is generally highly recommended with git), and also clean up your history/squash things a lot, using git cli gets VERY tedious very fast; I'd rather do it in several keypresses because why not.
> It's Achilles' heel is speed, though -- too damn slow. (Last time I tried it, anyway, which was a while ago.)
Don't remember a single of case of it feeling too slow in the last few years, whether on linux/mac... (maybe it just got better over time though)
I also plan to make Magit faster across all platforms.
It seems like the sort of ui that needs to be near-instant in order to be usable, the premise being you can tap the various shortcuts to assemble a command very rapidly. But on windows this is an exercise in frustration because each command takes at least a second or two at best to execute and often much longer.
But that still doesn't help explain its benefits to someone who hasn't tried it. For the crowdfunding campaign that I ran earlier this year I wrote a few articles. For those unfamiliar with Magit I would recommend [2] and the more visual [3].
[1] https://en.wikipedia.org/wiki/Text-based_user_interface [2] https://emacsair.me/2017/09/01/the-magical-git-interface/#st... [3] https://emacsair.me/2017/09/01/magit-walk-through/#start
I think that the distinction that makes a Commnad Line Interface is the REPL.
I consider anything with a non-linear UI that you can see a GUI.
The one exception to this I've found is GitUp (mac only, sadly), and it's excellent. It's whole model is, "what operations can I perform on this graph," which is exactly the model git has. It's great.
No way. Only if you define “good” as “good at the kind of project that git is good at,” where it will hold vacuously.
I suffer daily through the cyst that is git LFS, and it’s a joke. It would be funny if it weren’t so tragic. I hear that it’s not doing any better in large scale mono repo land. Google doesn’t use it, afaik. Microsoft does (but multi repo, last I heard), Facebook doesn’t (custom Mercurial, some tasty quotes at [0]). Not a glowing “fundamentally better”, exactly.
[0] https://code.facebook.com/posts/218678814984400/scaling-merc...
https://github.com/Microsoft/GVFS
Pretty cool stuff. Doesn't seem to address the large-files case so much as the many-files case, though. I would love better git support for large files.
2. Microsoft uses Git in single large-scale mono repo form, for - believe it or not - Windows. It clocks in at about 3.5 million files, and a full clone weighs in at 300GB:
https://blogs.msdn.microsoft.com/bharry/2017/05/24/the-large...
They had to change git itself to be able to do that. So no, the article itself shows it was not ready for that big a repository.
That’s my point: without LFS it’s even worse to work with large files. If LFS is the best option you have, forget it. That’s an entire area of projects (anything with assets) you can’t use Git for.
https://www.atlassian.com/git/tutorials/resetting-checking-o...
Understanding that git reset --soft moves HEAD but doesn't change the staged snapshot or working directory, whilst --mixed updates the staged snapshot to match the commit but doesn't touch the working directory was very useful. And knowing that reset --hard updates both staging and the working directory to the commit was where I suddenly "got it".
It looks like you mindlessly associate a CLI with a poor -- or suboptimal -- user experience. In fact even your choice of weasel words conveys the idea that you want to mindlessly push an irrational belief in spite of not being able to provide arguments to support it. The truth of the matter is that git -- or any other VCS -- operated through commands that change the current state of the repo. The command line interface excels when the user wants to run commands. Any GUI developed for command line tool will end up doing nothing more than replicate what the CLI already does, and will do so poorly.
Put another way, Git is a process that can be rendered pictorially. Words (i.e., CLI) are a less intuitive abstraction.
Pardon me for stating the obvious :)
That's why I end up using the plumbing commands to do things that porcelain commands don't let me do directly. For example, I'll use git diff along with git apply and recountdiff (from the patchutils package) to stage individual hunks or edit hunks prior to staging.
Pick the right tool for the right job, man.
Joking aside, think about the ratio of tasks. Most of the git commands I do is deadly simple. There might be once-in-a-year complex tasks that are more suitable to CLI, but for 99% of the tasks I think GUI could have a net gain in total. Although I'm not a GUI user in this particular case, I'd advocate to use whatever most intuitive to you when possible.
Disclaimer: I don't think C syntax is that bad.
git porcelain is a CLI. I am well aware that it is only a subset of git's CLI.
This looks fantastic, thanks for mentioning it! I've been looking for a GUI that doesn't mesh poorly with [whatever patterns my team uses] / without always pushing other features or a signup.
it's reasonably fast until I throw it at a huge monorepo :) but it still works (~2fps)! even `gitk` errors on this one.
missing some hotkeys (like prev/next commit buttons in preview)
freezes on remote-repo actions like fetch/pull/etc. likely due to our enterprisey ssh setup.
generally missing a bit of polish. click targets are small, could use some more config (and only in one location, "search commits" is in its own thing), etc
Aside from the remote repo freeze-up, I'm liking it a lot. Way better control than others I've tried (i.e. it has nearly all the features), undo support, and a much better mental-model for Git in general.If I can figure out how to fix the remote freeze-up, it might become my daily driver, which would be a first for a Git GUI.
I hadn't thought about the prev/next preview missing hotkeys, but you're right. I realized what I do is go into preview with space, leave preview with space, and then use the arrow keys to select the next commit I'm interested in. So in effect, "space, down, space" is hotkey for next commit.
Bummer about the remote freeze thing. I think the dev is reasonably responsive to bug reports.
I've got a list of things myself I think could be better, but I've been too lazy to attempt any of them. But I do try to proselytize in the hopes it'll pick up a bigger community. :-)
I use CLI for almost everything but sometimes it helps to have a visual representation of the repo.
A gui with drag-and-drop to rebase a graph also seems like it would work well...
Still hoping for a git repl that just does graph queries/transformations though.
I do like the Gitx-dev fork by Rowanj [1]. Clean and simple. Unfortunately just for Mac OS though.
To make matters worse, what in a Mac GUI would be called “Revert” or “Discard Changes” is called “Discard”, something that, to me, feels more destructive than it is.
End effect? We have “Discard” being less destructive than “Remove”, while, to me, it feels the other way around.
(I may remember this wrong, but if I do, I think that’s a sign of the problem of not following platform conventions in your software)
A GUI works fine if you want to get things done. If you like to know what goes on under the hood, it's just confuse you.
It's pretty sweet that GitExtensions displays the exact command executed. Actually, it made learning vastly easier for the people I taught after myself.
Some people do better with GUIs; others the CLI.
One example of this is the table at the bottom of this page: https://git-scm.com/blog/2011/07/11/reset.html
As long as all you're doing is pull, branch, merge and commit, I don't think it matters.
No thanks, it’s CLI for me, regardless if the IDE promises git support.
Staging, especially partially staging hunks and lines when doing multiple things at once, is way easier in a GUI when you can scroll around for context and easily undo.
For everything else I prefer the command line, because it's faster and I know exactly what is going to happen. I can do what I need to do, no fighting. If I'm just committing everything, I use the CLI. If it's more complicated I use the GUI to stage and commit, and a CLI to rebase/merge/push.
I do not care if someone is using a gui.
My takeaway: - If i can use git on an cli, i can use git on any server with an cli. I do need this for when i use git on my ansible maschine or on my home media server or when doing something with build infrastructure (jenkins -> git -> cli)
Like I said, super-rare situation.
GUI for partial commits and reviewing my change, and then command line for basically everything else (merge, checkout, branch, etc).
I use one or more GUIs for visualizing branches, and old branch cleanup, and yes, committing single lines from hunks that can't be split.
However for everything else CLI is fairly close to optimal, including interactive adding/rebasing, and don't want to use whatever shitty editor your tool has in it, I want to use vim with syntax highlighting so I can properly format my commit messages. Even something as simple as viewing a full commit is faster in the CLI because you can just pipe it to less or send it to an editor versus whatever tradeoffs a GUI has to make to stay performant, make use of screen space, etc.
One last tool is Fugitive. This blows away anything else I've ever seen for interactively traversing history at the line level.
Could you elaborate here? Personally I've always been able to commit just the pieces I need via `git add -p`. Never had problems staging a single line before.
Since this is text I should say: I'm not doubting you, I just like to know the limitations of the tools I'm using.
E.g. if you have two consecutive lines changed, it's not possible to split them, they are one "hunk".
(Waiting for someone to chime in with how to split a hunk and change my life).
You can also use 'e' option to edit the hunk to e.g. remove one of the added line.
Nothing as easy as clicking a line in a GUI though.
In there you can remove added lines (prefixed by '+') by removing them, and re-adding removed lines (prefixed by '-') by replacing the '-' with a space ' '.
Sorry if I'm being think, but how do you do that? Are you talking about Gblame?
> Fugitive
That's interesting. I switched back from emacs to vim (neovim), and fugitive was recommended. it just looked like :commands for the normal git cli... maybe I missed something.So even though I edit in vim, I jump back to emacs for magit for bigger commits or multiple smaller commits (where I need to see diffs to be sure I capture my changes).
I have desired something as useful in vim, but I didn't think there was anything. I'll take another look at fugitive.
All that said, I don't really use it for committing, mostly because I have a shell open right next to the editor anyway.
As soon I started to work with git, I installed fugitive. My learning curve of fugitive has been slow, and I have never be able to stage efficiently with it.
And then, a colleague showed me magit: I waited for a year that something similar comes to vim, trying to push this idea to fugitive https://github.com/tpope/vim-fugitive/issues/569 , without success.
Finally, some first experiments showed that partial hunk stage was feasible, and I created vimagit.
As you will see, it is far from whole magit features. For the moment, it "only" focuses on stage/unstage and commit feature (which is the main use case to me). The current workflow is quite robust: you can easily navigate through all the diffs to review them, stage by file/hunk/line/part of line, write the commit message (or amend the last commit), jump to the diff locations in their files... I continue to use fugitive for Gblame and Gdiff.
Next major features should be git stash (be able to prepare a stash like a commit, by file/hunk/line) and some git log related feature (to easily git commit --fixup a chosen commit in a log for example).
I typically use git gui to commit changes, the cli for other operations, and occasionally source tree to visualize branches and compare with remote repos.
Nah, it’s just a lot easier than you make it out to be. GUIs are fine too, but if you read the documentation and don’t just memorize a fixed set of commands there’s nothing dangerous, slow, or inconvenient in going about a standard workflow using the CLI.
And yes, lots of people don’t have time for this. Totally okay. Don’t generalize to “anyone who uses the CLI is trying too hard”.
And you can also learn useful things by reading the console sometimes. There is no magic.
On the opposite side gui users can often be unaware of the actual model and instead be working with imperfect internal models with be GUI being a crutch.
In both cases there is lack of desire to learn but I'm often more sympathetic to the latter where people want just enough information to do their work well as oppossed to the former who often make things harder than they have to be in all areas and have lost touch with true expertise in favor of appearance of expertise.
Or just couldn't be bothered with leaving terminal. I refuse to reach for mouse for any repository operation when everything else I do from console.
- It's a live dashboard. A GUI gives me live, persistent information organized well on the screen. I appreciate the power of the CLI for accomplishing tasks, but I've never understood how people prefer it when it comes to simply viewing and understanding the state of something. I don't see why I'd want to run a bunch of commands to see stuff scroll by in my format-constrained terminal when I can have a live, all-up view of multiple aspects of a repo all at once, with relevant, context-sensitive commands on whatever I click on.
- It's discoverable. Most of what I've learned about git has been through clicking around in Git Extensions.
- The structure and organization of the UI helps me to understand how git operates. When I open the "Pull" dialog, for example, the way the controls in the UI are grouped and the kinds of controls that are used help me logically understand what "Pull" can do.
[0] https://github.com/robbyrussell/oh-my-zsh/wiki/Plugin:git
It has many of the advantages that you describe; makes it easier to get an overview of what's going on, makes it easier to stage individual files, folder, lines of code, hunks, etc.
There are a couple of cases in which I need to fall back to the Git command line, but it's not very often, and I do find it substantially improves my life.
(full disclosure: as of last week I actually work for the company behind gitkraken but I started using it far before I realized they were local)
Seriously though, I'm somewhat new to git and any problem I come across (which are many as a new learner) are solved with command line options. I'm not even familiar with the best GUI options out there and have been trying to learn what seemed to be the "standard" way of git'ing.
Right click on any commit and I can create a new branch there, copy the SHA, do a mixed reset to that location, rebase on it, etc. SO much easier to visualize the actual tree of commits you're working with.
I'm sure some people do do all that from the command line. But every CLI coworker of mine has really only known the basics of branching and committing. The GUI unlocks the repo and all of its branches and commits as something you can play with and explore.
Here's a few handy ones:
alias currentbranch='git rev-parse --abbrev-ref HEAD'
alias gpush='git push origin $(currentbranch)'
alias gsync='git pull origin $(currentbranch)'
alias ga='git add -A'
alias gc='git checkout'
alias gcm='git commit -m'
alias gca='git commit --amend'
# and my personal favorite (list recent branches)
alias gb='git for-each-ref --sort=-committerdate refs/heads/ --format="%(HEAD) %(color:yellow)%(refname:short)%(color:reset)" | head -n 20'The GUI is said to be a major leap forward in human conputer usage, in the context the CLI just strikes me as either (elitist?) jargon, or brogrammer bravado. In either case, not really a step forward but certain macho. I still don't get it.
I haven't looked back because I haven't found the need.
Do you mean that as "not committed", or "not pushed"?
If you mean not committed, then why is it a good thing? You should be committing often. Then you push after you are satisfied. It is much easier to revert mistakes that way.
I often see files that clearly shouldn't have been committed. I always bring up using Sourcetree or something else, but everyone seems to think that it's okay the way it is. I can't force it on them and to each their own. It is really frustrating though, because there's this stigma against using a git GUI, but the end results of using one are (in my experience) significantly better.
I've suffered a lot of git GUI bugs. The admittedly large repositories I sometimes deal with cause things to hang and stall, breaking my flow. I keep filing bug reports - truncated diffs because new files were "too large" (presumably someone trying to fix the hang and stall issue), a client that only renders the top half of the window consistently when on a portrait 4K monitor, etc.
The git CLI is simply second nature enough to me at this point that waiting for a GUI to load, refresh, etc. is rarely faster. It does happen, but it's not the common case. Getting a good summary of a set of changes is sometimes one of them. Picking individual hunks/lines is sometimes another - although I prefer to commit with such frequency when using git, that it's extremely rare I have changes that belong in different commits.
Then, looking at perforce, I'm finding more and more cases where I'm dropping out of P4V and into command line tools. Any kind of mass move/edit seems easier to do through the command line. Command line diffs were way easier to review than P4V's file based diff interface when I had changes involving 1 or 2 line tweaks spread across dozens to hundreds of files (such as verifying function rename changelists didn't accidentally pick up other changes.)
I think anyone who's swayed by the beauty of a git GUI has much more patience than me.
"Sourcetree (Not Responding)" - I typed this out while waiting for my Visual Rust tab to focus. Euhg.
I could've made a commit from the command line in that amount of time.
Friends don't let friends (especially those who don't learn how to use their tools) rewrite shared git history. If you don't understand rebase, amends, etc can do to your (and everyone else's) repo, DON'T DO IT.
$ pushd ..
$ cp -a my-project my-project-before-I-did-git-surgery
$ popd
Then relax. This is extremely important before playing with nasty Git surgical tools such as huge rebases. Borked it up? $ pushd ..
$ rm -rf my-project
$ cp -a my-project-before-I-did-git-surgery my-project
$ popd
Undo is a great thing, and it's also important to triple check the entire state of the repository before you push, because pushing is basically committing to whatever surgery you've done. If you're having to fix stuff with -f, you're going to run into trouble; try to avoid -f ever.I disagree. I don't have much experience using git with big teams, but at least for small team where a developer usually owns a feature branch, force pushing to the branch to take into account criticism on commits can be helpful. Of course, in that case, feature branches are considered non shared.
Git own "next" branch is actually force pushed to all the time, to remove patches which didn't make the cut for example.
Hm? Criticism on commits should be additive. The commit was made, response was made, and a new commit addresses the response. Rewriting history breaks a lot of things and removes context. Another approach:
1) Add commit addressing criticism.
2) Squash when merging feature in to master, which is one of the only cases where I think rewriting history is OK.
Much cleaner master history, no rewriting history (which you should never do once another checkout sees your branch, including GitHub), and a number of other benefits. If you're routinely force pushing feature branches, something is broken in your workflow, IMO.
This, in contrast with just reviewing the latest commit, potentially going back to the rest of the changes with an eye towards the latest commit.
It frankly bugs the piss out of me when people rebase and ask me to review their latest changes - it feels disrespectful of my time.
If it is committed, it is safe. You can go back to it. If you messed up your branch, just reset it to something that was good. No need to do manual backups.
When you commit in git, that saves the whole project as a "snapshot". If you find yourself lost in some rebase hell or whatever, just reset HEAD back to a previous commit. It's simple as that! (git reset --hard <commit>)
Why I decided to reply to your comment was because this is a very crucial part of learning git. When you realize that you can always go back to what was before, you can start experimenting more freely.
Unless part of your surgery involves files that do not yet live in the history, or you're working on a detached HEAD in a mid-merge state, or... git reset --hard is a very dangerous operation unless you're 100% sure of the entire state of the repository. That is a very rapid way to lose work if you're not perfectly diligent.
And sure, you shouldn't have to back up .git or your workspace, but sometimes, it's a hell of a lot easier to ripcord out and say "screw it" if you have a complete workspace from before you decided to launch down the rebase hole or whatever.
Sometimes it's okay to take liberties with good practices - especially when learning, or when the world is on fire and a push needs to happen now.
The unwanted reality we live in.
But to enable this "revert-first" culture, you have to design your commits to basically be super easy to revert. That means no merges in the master branch, you want to keep your revision history as clean as possible. One commit, as little dependencies as possible. Rebase is the right tool to use for this. The goal is a tidy linear history.
How are these concepts related to each other? Merges don't make reverting any harder.
After a revert, all the commits that were merged, are still merged, but then they're deleted. The next time you pull, git will delete the changes in your working branch.
In a merge workflow, you have to either fail forward (fix the problem, rather than backing out the merge), or reset/rebase the shared branch, and email repair instructions to everyone on the team.
When you say, it’s not safe, it sounds like you could lose work or someone could be hurt, when it’s more likely that the removed ancestors could be merged back in by someone not using ‘git pull —rebase’, or other devs being put out by having to resolve some conflicts. It’s not great, but it’s a far cry from unsafe or DANGEROUS! MUST AVOID! PUBLIC SHAMING!
If you have one rebase with a force push a week, people will quickly stop asking "who did the force push", since it has become normal. They'll instead just let the force push come through to their local repo, just to find out that the force push rolled the repo back a year. Now productivity is halted dead until someone goes in and fixes it and makes yet another force push.
The worst part to me is that it makes the repo lossy. The entire purpose of having version control is actively subverted in the name of "clean".
I don't understand the business requirement for a non-lossy repo. In my experience, we need to be able to link a release to a specific commit, and we need to show that the changes were reviewed & tested before they were deployed. We use tags for this.
I also think the entire purpose of source control is to be able to answer question like "who changed this? when was it changed? why?".
> Now productivity is halted dead
Because of a bad push to a single repo? I really like the distributed nature of git, which lets me stay productive even when other repos and branches elsewhere are having issues. I would avoid treating git as 'SVN but newer'.
And, frankly, since all rebase does is re-write history, I fail to see how it's inherently productive, especially in the context of re-writing the history of previously shared commits. Yes, it is capable of cleaning up and reducing the number of commits you have to read through when looking at history, but that's such a rare event that optimizing for it (especially by normalizing dangerous commands like `git push -f`) seems, well, premature.
Then they used the resulting variable in 'make clean'. That was more of an, 'oh shit, git pull' sort of thing though.
But you can still chop off your thumb in your local history, and that's safe to fix - you just have to know where the duct tape is.
"It is impossible to make anything foolproof because fools are so ingenious."
Yes, Git is a sharper tool with fewer blade guards than other version control systems, including HG. That sharpness and relative lack of safety mechanisms, however, lets you do things you can't in other systems. The real problem is that folks use these tools without attempting to understand them and cargo-cult onto a workflow which leaves them open to screwing things up.
To continue the "git off my lawn" moment - I've had to use the reflog exactly zero times in the past few years, despite using rebase locally on a fairly frequent basis (and sadly remotely to fix other's bungles as well). This is only because I respect git for its sharp edges, and when it comes time to re-write history with rebase, I work carefully.
No judgment, nobody is born knowing this stuff, just that I'm surprised to hear this is still out in the wild.
these shops don't understand the benefits version control offers when it comes to code review and maintenance patches on old versions of the software, or vendor-specific streams for your software.
I have seen it as files on a shared drive. I have seen it as files on a sharepoint drive. I have seen it as files inside of an SVN repository.
You mean a force push. `git push --force` is one of my favorite commands. I've aliased `git yolo` to `git push --force --no-verify`.
If they have, you can fetch, see if you still want to overwrite that branch, and if so run it again.
I hope you do not work on missiles or on passenger aircrafts!
I don't think it provides the most consistent UI or helpful help, though. Once you move away from "learning git commands" to "learning how git works" and kind of figuring out which parts the commands refer to has helped also. That's still terrible though.
I had trouble with Git until I discovered "git add -p".
I'll grant that Git could do with a revision of its commands and args.
But when a carpenter stashes and unstashes their things, they don't suddenly find out they're magically planning to do a lot of things that they weren't previously planning to do.
The syntax is "git reset -- <file path>". What does that do? Well, it tells git not to change the head pointer. Of course, it wasn't going to do that anyway, but as a side effect of not doing anything, it makes a decision about what to do with all the staged files. The default resolution is to unstage everything so that everything that happened between the old head and the new head can go in the stage. When you add the "--", you're telling it to only apply that resolution to the specified files.
So what you're actually telling Git is, "don't do anything, but when you don't do anything, move these files out of the stage so that you have room for all the files that you're not going to stage."
And this is why I used Git for an entire year without actually knowing what "git reset" does.
The neat thing is that Git is an expression of that UNIX philosophy in which tools have various layers that are separated. You can have the crazy Git syntax but you can also write another command (or a GUI) that wraps Git and gives you the set of sane commands you wish it had, and which covers 90% of your use-cases, while still keeping the original around in case you need it.
[Disclaimer: I've spent the past couple years doing exactly this (the GUI part) for a digital archives application. And to lmm's point up above my app does hide the staging step from the end-user.]
Understatement! Git is one of the most user-hostile tools I've ever seen. And I've used Sendmail.
That reminded a video where Linus Torvals is been interviewed and he says that if he ever have to make good UI to get out of a desert island, he would die there.
In a similar vain to `git checkout`, `git reset --hard` is also an excellent way to loose uncommitted work.
git reflog is your friend
How can you blame git for deleting stuff if you blindly pass --force to it?
* commit to an itermediate branch as storage
* git stash && git stash apply (repeat last to recover stuff)
git log -p --all --first-parent --remotes --reflog --author-date-order -- somefile
I accidently screwed up a rebase and dropped a test file. It managed to get merged as a blank file (always review after rebase!), I noticed a few days later when a PR was passing which I swore would of failed some tests I had written. Since then I couldn't exactly remember when I made the commit to the file, so trying to search through reflog became difficult. The above command makes it pretty easy as it will show you every change made to a file.I'm sort of kidding, but not really. By using it, I can operate on a git repo using the mercurial CLI, which I am more comfortable with and have built tooling around.
Once you have the extension installed, it's a matter of prepending 'git+' to the beginning of eg a github url to clone it, and then you can use native mercurial commands.
Obviously, this is an extra layer with all of the problems that involves (eg you're going to be managing git branches through an hg interface. Which works surprisingly well most of the time.) So this makes NO SENSE WHATSOEVER unless (1) you are comfortable with the hg interface, (2) you aren't that comfortable with the git interface, and (3) you don't need to do complex operations that would require thinking through the layers of what is happening.
Honestly, though, if I want to contribute to a github repo, this gives me everything I need 95% of the time. So far, the only time I ran into trouble was when the active branch was renamed in the github repo. Things got very tangled up, and I had to re-clone and import my patch stack. Judging by the number of people talking about making "backups" of git repos in this comment section, it doesn't sound like that's an unexpected operation in git-land. With mercurial's immutable and append-only nature, I very very rarely need to do this, so it felt kind of awful.
(Admittedly, my main hg repo that I work on is 6GB and I'm normally near the limit of my disk space, so my habits don't really match your typical megabyte-sized github repo in some noncompiled language.)
Instead of saving a 6 command list for some use cases, why not just get used to the simple but kinda unintuitive way of how revisions and branches work? If you know that, you can solve any problem with `commit`, `checkout`, `reset`, `reflog`, and occasionally `cherry-pick`.
That Perforce and SVN don't get such things should also tell you something.
(Which isn't to hate on git--it's a great tool.)
Git has eleventy million blog posts trying to explain how simple it is to use. That's a clear sign that it is, in fact, not simple or easy.
Unrelated topic (falling cats), same logical fallacy: http://www.radiolab.org/story/102525-vertigo/ (Starting around 14:20)
That should tell you something: these articles don’t resonate with the crowd. That should tell you something.
That's why I replied.
I can't really address p4 because I haven't used it for any real world use cases. Only to prepare for an interview. With that limited use, I can't come with any reason to think it's superior.
I made exactly one claim:
These git cheatsheets on how to get out of a bad state get a lot of traction on Hacker News. That is a pretty good indicator of something. Let's think about what that is. The fact that you consider it a serious indictment of git should also tell you something.
I'll make another claim now though:
When someone criticizes git, some users sure get defensive about it. That should also tell you something.
Silliness aside, I guess Git suffers from the trait that it is very hard for many people to internalize and visualize how it works in their heads. Totally different but related: the Azure CLI is for some reason 10x easier to work with than the AWS CLI, while I’m 10x more experienced with AWS. I guess CLI design is also design.
A constant, instant backup of all files, independent of the repo, has been my saving grace for small projects.
— Isaac Wolkerstorfer (@agnoster)
At the very least, if you are going to have a long lived branch, make granular commits and push to a remote repo frequently. That will give you a distributed backup strategy.
I find cherry-picking to be easier in this case. Just checkout the branch and cherry pick commits from 'wrong' branch.
Of course, rewriting history is only feasible immediately after the mistaken commits, before anyone builds on top of them. If they've lingered, reverting is the right way.
And again, if this is a repeating problem, fix it upstream (no pushing to master, only PRs).
I realised that treating a git repo like an immutable collection, where existing commits are NEVER mutated makes it far easier to reason about history and nearly impossible to do serious damage.
Devs can do whatever they please with their own local pulls (such as squashing 50 rambling commits during dev), but once a commit is on remote, it never changes.
This site makes a game out of learning git: https://learngitbranching.js.org/
It's a great way to learn without putting your real repository at risk.
I've browsed through a few git guides, but can't seem to find anything that would let me:
1) Do something like "du -s *|sort -n" for the entire Git history
2) Let me "rm -rf --from-history-too", that would cause the remote repo to actually shrink in size.
git filter-branch
This won't be a terribly fun exercise, and could be very painful if your history contains a lot of merges. (should be easier with the cactus/rebase development model)And of course everyone will have to hard-reset to the new branch.
I should mention I'm far from an expert on this. I've only ever used git filter branch on a handful of commits, and only based on examples provided by kind internet people. I certainly haven't done anything nearly as far-reaching as you're about to embark on.
The BFG program in this guide [0] seems reasonably close to #2. I don't know if you would need to manually trigger garbage collection in the remote repo, or how you'd do that.
https://help.github.com/articles/removing-sensitive-data-fro...
https://rtyley.github.io/bfg-repo-cleaner/
I've used it in the past, and it's pretty straightforward and does the job well :)
I'm a bit of a git naif, there are doubtless better ways to do this. This was mine:
0. Back up my repo.
1. Save the entire commit history as patch files.
2. Use BFG (amazing tool) to scrub all references to the unwanted files [0]
3. Create new repo from the commit just before unwanted files.
4. Apply the patches.
5. Use a custom Perl script to apply the dates in the patch files to the new history. [1]
Technically, your repo will be fully reconstructed at step 4. Also, be advised the patch files themselves may have to be massaged to remove references to the file(s) in question. If the filenames themselves are not unwanted, you can add them to .gitignore for good measure.Step 5 merely preserves the dates of the original commits. Keep in mind that for this last step, your script will have to work in reverse chronological order as the history will be altered from that point forward.
[0] https://rtyley.github.io/bfg-repo-cleaner/
[1] http://eddmann.com/posts/changing-the-timestamp-of-a-previous-git-commit/
EDIT: Swap steps 1 and 2. Add advisement that patch files may require manual alteration. Add hint regarding .gitignore. Title case "Perl".Which for part 2 then leads to the BFG repo cleaner (which I haven't used)
But even after nearly 10 years, the pressure from the aint-nobody-got-time-for-that crowd is still there. I really, really hope that the git devs don't feel pushed to simplify and therefore depower git. Thinking turning VIM into the Windows text editor.
That is not trolling btw. It's really possible not to know what you can do with it if you haven't learned it in depth.
The "Git Book" is what you should read. And you read it once, you read it indepth, and then you're done. After that it's also only 5 minutes of googling, but you can do a lot more. At that point you can even program a simplified git if you want.
[1]: https://github.com/git/git/blob/master/Documentation/howto/r...
What can't you do in Mercurial that you can in git these days?
BTW, I think we are talking about the same book.
If you've experienced that once consciously, then you can regonize it and you know when you experience it you've hit someting really good in your life that moves you forward.
Sadly it seems you must take that hurdle in anything until a certain age or you will always believe this is impossible and therefore never invest the energy to reach it.
The thing is that this is not possible to achieve with any random software. For instance no matter how much you learn MS Word, you probably won't experience that. But when learning Vim or Emacs there's a chance you get there. Same is with git. And once you've achieved it once consciously, you will always want to be in that state in everything important you do.
That's why the really good stuff only has a few followers, most simply don't get the appeal because they never would invest the energy to get "there" even if they knew exactly how much it would take. But for those who have achieved it there is no going back. You cannot go back from controlling (almost) any bit of your repository to Mercurial.
But that's also why I think for most users something like Mercurial should be The VCS. Most people don't know the reward they are missing, so they don't feel the pain of missing it, and therefore have no logical reason to go through the pain of really learning git.
What I'm saying is that most people are blind when it comes to skill, because they never make it over the hurdle once. But because most people don't have any skill, it is general consensus in our society to declare skills based on interest rather than the ability to solve hard problems or win competitions. I mean if one person is unable to judge if another person is good at solving merge conflicts, how could he criticize that person declaring himself as Git Expert Of The Team. And then again of course most people feel it is inappropriate to tell other people they are unskilled, so posts like this one get hated a lot on. But actually it's just calling out the facts. Sky is blue, grass is green, most people are too unskilled to even recognize what would enhance skills.
You seem to be under the impression that doing hard things has some intrinsic value, when it's not the case. You could be rolling rocks uphill all day and be the best in the world at it. So what? A keyboard going clicketyclack* for 5 minutes while typing git commands (and possibly stackoverflow queries) is the opposite of work, it's actually a waste of time. Sure, at the end of the day you solved the problem git presented you; you're smart, and feel satisfied with you amazing display of intelligence and skill. However, this ignores the fact that you should not have had to solve that problem to begin with, because your version control system should just magically work (unless you get a bonus for each git commit/merge).
> how could he criticize that person declaring himself as Git Expert Of The Team
I have no problem with someone being a git expert - I actually will even admit that I am not a git expert and that there are people extremely skilled at git. The issue here is that there are some people really skilled at, for example, typing using the backs of their fingers. Potentially impressive, but entirely useless. Saying you're skilled at git is like saying you're skilled at using Jira or editing Wikipedia; good for you, but in all but most extreme cases this doesn't actually generate value and it also doesn't make you a better developer.
> one person is unable to judge if another person is good at solving merge conflicts
Just out of curiosity, is this somehow relevant to git? Shouldn't solving a merge conflict be a simple matter of looking at a diff tool presenting you two inputs and one output screen? Or better yet, wouldn't it be better if you were automatically told you are editing a file someone else is working on, so that it prevents conflicts from happening?
And you don't know mercurial if you think that.
Both are great and powerful and both have pros/cons.
> The "Git Book" is what you should read. And you read it once, you read it indepth, and then you're done. After that it's also only 5 minutes of googling, but you can do a lot more.
The problem with git on this is it is actually often sort of hard to find "the right" way to do things. This is in large part because of the popularity of git. There is so much content and a good deal disparate (e.g. Stack Overflow).
Mercurial on the other hand has far less content and it is maybe a little more consolidated and thus IMO slightly easier to find.
> At that point you can even program a simplified git if you want.
.... are you sure you are not trolling...
They could have had every feature they do today without creating weird differences in options and terminology between sub-commands, and they could have set better defaults.
There needs to be an official “git 3” rethinking of options and defaults to solidify the foundation for the years to come and promote widespread adoption. Anything that simply tries to improve “git” as a layer on top will fail due to obscurity.
git checkout name-of-the-correct-branch
# grab the last commit to master
git cherry-pick master
# delete it from master
git checkout master
git reset HEAD~ --hard
The two lines in the middle can be git cherry-pick -
git checkout -
, and voila, it suddenly is name insensitive.So if git is the tool you use to get your job done - don't hesitate to spend a day or 2 on reading how it works and how you're supposed to use it.
$ git status --short
## master...origin/master
M include/uapi/linux/netfilter/xt_connmark.h
M include/uapi/linux/netfilter/xt_dscp.h
M include/uapi/linux/netfilter/xt_mark.h
M include/uapi/linux/netfilter/xt_rateest.h
M include/uapi/linux/netfilter/xt_tcpmss.h
M include/uapi/linux/netfilter_ipv4/ipt_ecn.h
M include/uapi/linux/netfilter_ipv4/ipt_ttl.h
M include/uapi/linux/netfilter_ipv6/ip6t_hl.h
M net/netfilter/xt_dscp.c
M net/netfilter/xt_hl.c
M net/netfilter/xt_rateest.c
M net/netfilter/xt_tcpmss.cEdit: To add, how is git supposed to handle two files with the same name -- as is the case -- with a case insensitive file system? You can't have two files with the "same" name.
git checkout file1
Is entirely different than git checkout FILE1
In any other platform ls file1 FILE1 would show two different files, but on OSX, it'll show the same file twice.-----------------------
Here are some minor failure modes I’ve seen with Git:
1. a branch that stays open for many months, perhaps even a year (for instance, at Maternity Neighborhood)
2. data is erased for good because someone makes a mistake while using rebase
3. a developer introduces a new bug while trying to resolve a merge conflict
4. widespread but fine-grained cherry picking leaves the team unclear about what’s been merged and what has not been merged
5. a developer makes a change in the wrong branch because they forgot what branch they were in
6. a developer is unable to recover a stash because they forgot where they were when they created the stash, or they simply forget that they have work in a stash
7. developers confused by working in an unattached commit, after a botched attempt to revert
8. a developer feels the need to delete the repo from their harddrive and clone it again, because the whole repo got into a state that they seemed unable to resolve
9. the “blame” command is nearly useless — maybe its because we never know in which branch a given change was made, finding who made a mistake is very difficult
10. developers get confused about which branch will be deployed (I see this especially in shops that have lots of repos for lots of small apps, and use different Git workflow strategies for the different repos, often because different programmers or different teams control the different repos)
11. developers push their changes to “origin” but forget to push to “upstream” or vice versa.
But all of that stuff is trivial compared to the major flaw:
Graphic designers, writers, HTML/CSS frontenders, managers, data analysts and QA staff can’t use Git, even though they all used Subversion.
http://www.smashcompany.com/business/business-productivity-h...
No. Just no. Please stop spreading FUD like it's candy. Git only deletes commits after a GC, which won't erase commits from reflog and will keep unreferenced commits for at least a month before deleting them. And rebasing generates new commits, leaving the old ones exactly how they were. If somebody lost a commit after a rebase, and nobody nearby could help them recover it, they should consider spending a few hours learning about git.
I've been using git for 4 years both at work (with a team of 40+ people) and at home, without ever having any of the problems listed here (except 3 which has nothing to do with git). It takes a few hours, maybe a few days to understand how git works and how to use it. Instead of blaming the tools, you (and your team) should probably learn how to use them.
From the essay:
--------------------
And Git is intimidating, not just to non-technical staff, but also to inexperienced programmers. In How To Destroy A Tech Startup In Three Easy Steps I talk about Sital, and his unwillingness to commit things to Git. He was learning a great deal about many other technologies, and he didn’t have any spare energy to learn about Git. He went a month without making a commit, and then he only did so because I insisted. After I put a lot of pressure on him, he got to the point where he would make one commit a day, at night, when he was stopping for the day. He would commit to the master branch, because he was confused how to handle different branches. When there was a merge conflict, I would resolve it for him. We worked together for 6 months, and in that time he learned a great deal about a lot of important topics, but he never really learned how to use Git, because it was a low priority, for both him and our CEO.
Git is something that you can use on almost any project, with any team, at any company. It's something you need to use if you want to contribute to open source. Aside from your programming language of choice, it's probably the second most useful tool you should be learning as a software developer.
You're telling me a developer was too busy learning "other technologies", and in 6 months he couldn't be bothered (or was too afraid) to spend one or two hours going through a simple course about git? By that argument, he probably couldn't be bothered to learn how separate concerns into classes or how to use refactoring or write tests. What other things didn't he have time for? Unwillingness to learn is not an excuse.
> he never really learned how to use Git, because it was a low priority, for both him and our CEO.
I think it was more of a lower priority for your CEO than Sital. Learning git was something that benefited him more than it benefited the company.
I still have issues with your attitude, because it can be applied to anything useful in software development, but management might take issue with. Writing tests? Who needs them? The CEO doesn't care so they're low priority. Refactoring? Waste of time. Management wants shiny features not code quality. Developers have tried really hard to convince management that some overhead is needed to keep the quality high and maintenance easy. Your attitude is the exact opposite.
You setting your theory against my lived experience. If you want to understand the situation more fully, you can read How To Destroy A Tech Startup In Three Easy Steps:
https://www.amazon.com/Destroy-Tech-Startup-Easy-Steps/dp/09...
I did my best to re-create the extent to which decisions were driven by panic and the pressure of time.
Please note, every company in the world has a finite amount of time, and a finite amount of money. You can argue that a company should hire people with more experience, but people with more experience will be more expensive, so you will end up with less people. Or you can argue that a company should hire more people, of less experience, and then train them. Training takes time, so in this case you are trading time for money.
All of these strategies work, but in different circumstances. In the circumstances that I faced in 2015, described in the book, I advocated for the strategy of less people, of a higher skill level. I was, however, outvoted, which is a reality of corporate life.
It is relatively rare that a company follows an ideal strategy. What I see instead is constant course correction, often with a bit of a lag, so that the company ends up having the ideal strategy for dealing with the situation that it faced 6 months ago, which is not necessarily the ideal strategy for what it is facing now.
Business tends to be chaotic. The Platonic Ideal of computer programming needs to be adjust to the real realities that businesses face.
To be clear, Sital's attitude was a major problem, and myself and co-workers advocated that he be fired. But management kept him on, and I was given the responsibility of covering for the gaps in his knowledge. I was not happy about this, but this is a reality of business: we often have to accept that a decision has been made that we strongly disagree with, and then we need to somehow make the best of it.
The issue you have with git, is that untrained developers have a hard time using it. Which brings me back to my original comment. It really doesn't take long to train someone to use git. And you can choose whatever flow you want. That's the beauty of it. If the company hires lower skill people, you can just guide choose a branching mode suited for their needs. They don't even need to use branches. Or just teach them to use an UI. But please don't teach them SVN.
But please don't teach them SVN
Why would you say this?
You also say:
If the company hires lower skill people, you can just guide choose a branching mode suited for their needs
If the company has lower skill people, why not go with the technology that requires less skill? This seems like an obvious step.
"The issue you have with git, is that untrained developers have a hard time using it."
Please re-read my first post, up above, which started this thread. I wrote:
"But all of that stuff is trivial compared to the major flaw:
Graphic designers, writers, HTML/CSS frontenders, managers, data analysts and QA staff can’t use Git, even though they all used Subversion."
> Graphic designers, writers, HTML/CSS frontenders, managers, data analysts and QA staff can’t use Git, even though they all used Subversion.
Why is it hard for them to use git? For simple use cases, git can be as easy as commit & push. No need for branches. There are even UIs which allow you to easily make commits and see the log [1]. If more people work together and conflicts arise, I honestly don't know how SVN is better at solving them.
All I can do is quote what you wrote in a different comment:
"If you're an artist, git is not for you."
Would it be the best if Sital never committed his changes? That way he would not be able to hurt your project and you would be able to fire Sital sooner.
GIT is the only source control system where you can completly loose commited data by actions (or commands) available the non-admin user. It's funny to see that this is considered a "feature" and not a design failure.
Except the whole point is that you can't completely lose commited data, even if you tried really hard. And the solution to the problem was `git reflog` which shows the history of the HEAD.
"No. Just no. Please stop spreading FUD like it's candy. Git only deletes commits after a GC, which won't erase commits from reflog and will keep unreferenced commits for at least a month before deleting them."
It is frustrating that you continue to take your advanced skills for granted. It is frustrating that you can not see what should be an obvious fact: that your skills are above average and therefore it is a mathematical fact that most people have less skill than you, and their lack of skill is a real world business situation that needs to be dealt with realistically. And more so, for the rest of your career your skills will continue to develop, so the gap between you and the average will continue to grow, and therefore the damage that you can do will continue to grow, if you fail to recognize that you are above average.
I can assure that I've seen data lost forever because of "git rebase". It doesn't matter that someone with your skills could have saved the situation. You were not there, therefore your skills don't matter! It is very important that you see this, or you will never be able to give accurate advice to business leaders.
If the leadership of a company decided to hire people with a skill level of x, then they should not also use a technology that requires a skill level of x + 1. You can reasonably tell them "For what you are trying to do, you should hire people with a skill level of x + 1." That is exactly what I did in the situation that I describe here:
https://www.amazon.com/Destroy-Tech-Startup-Easy-Steps/dp/09...
But sometimes the business leadership will disagree with you. They may have terrible reasons, but if you can not get them to change their minds, then you need to deal with the consequences of their bad decisions. At which point it makes sense to advocate for a technology that only requires a skill level of x.
[ EDIT TO ADD ]
I'll point out that you are demonstrating a classic case of the Dunning–Kruger effect. In particular:
"the miscalibration of the highly competent stems from an error about others."
That is, you have above average IQ and skill, therefore you perceive things to be easy, which are in fact not easy for the average.
https://en.wikipedia.org/wiki/Dunning%E2%80%93Kruger_effect
You are an elite programmer. Try to avoid acting like the kind elite programmer that I criticized in "Business productivity has been undermined by the hubris and power-grabbing of elite computer programmers".
Then there's this:
> Graphic designers, writers, HTML/CSS frontenders, managers, data analysts and QA staff can’t use Git, even though they all used Subversion.
What rubbish. The features of subversion are a subset of git, and the git equivalents are easy to learn. For a svn user, there's literally only a single additional command they need to know: git push.
That doesn't mean that I'd go back to subversion, but I don't think it's fair to say it's as easy to use.
Well, except for locking, which I hear is useful for people working with hard-to-merge files.
If you read the whole essay, you will see that "distributed repositories are bad for business" is exactly the argument being made.
> 1. a branch that stays open for many months, perhaps even a year (for instance, at Maternity Neighborhood)
This is more of a workflow question than a VCS question, and would be true of any VCS that allows branching (i.e. anything remotely close to a modern VCS)
> 2. data is erased for good because someone makes a mistake while using rebase
Data isn't permanently removed from rebasing, you can still get at it with the reflog. If you discovered the problem months later, I suppose that could happen. checkout and reset --hard can irrecobably destroy uncomitted data (as can clean, but that's more obvious and has appropriate guardrails)
> 4. widespread but fine-grained cherry picking leaves the team unclear about what’s been merged and what has not been merged
Overuse of cherry-picking feels like a workflow smell to me, but even still, you shouldn't need to care. Merging the entire branch will work fine if some of the contents have been cherry-picked previously.
> 5. a developer makes a change in the wrong branch because they forgot what branch they were in
True of any VCS with branching.
> 6. a developer is unable to recover a stash because they forgot where they were when they created the stash, or they simply forget that they have work in a stash
I'll agree with you here, I think stash is a bit of a footgun and almost never makes sense to use if the stashed contents are going to live for longer than a minute or two. But this is easily addressable with workflow, don't use stash for anything other than an extremely temporary holding place.
> 7. developers confused by working in an unattached commit, after a botched attempt to revert
Git is generally not great about warning you about dangerous operations or things you shouldn't be doing. Running against a detached HEAD is not one of those things, you'd have to be willfully ignoring what it's telling you to not realize that this isn't a safe thing to do.
> 8. a developer feels the need to delete the repo from their harddrive and clone it again, because the whole repo got into a state that they seemed unable to resolve
I will agree that git could make it easier to say "just get me back to origin, i give up"
> 9. the “blame” command is nearly useless — maybe its because we never know in which branch a given change was made, finding who made a mistake is very difficult
Blame isn't great, but it sucks in precisely the same way it sucks in any VCS. Just seeing who last committed a line often isn't enough information. It would be cool to see an alternative here, but I don't see many better alternatives around.
It sounds like in general, this is more a concern with dealing with branches and branching, which is totally fair. If simple trunk-based development works for you, branches are an unnecessary addition. But there's no reason you have to use all these git features. You can happily have everyone just work against master and never need to think about branches (in that mode the various Git GUIs will probably be more than adequate as well).
I do agree that git tutorials tend to focus on a more advanced branching / rebase focused workflow, and that simpler resources for less technically minded folks would be handy.
If you are not using all of the Git features, then why use Git? Why not use something simple, like Subversion? As I wrote in the linked essay:
-------------------
When I list these complaints for developers, most of them respond “You are complaining about Git’s power. The stuff you list isn’t really a flaw, rather those are all examples of how amazing Git is. It is flexible enough that you can do almost anything with it.”
I agree, Git is amazing and very powerful. What I’m suggesting is that we should recognize that it has a very high cost. It might empower complex workflows for sophisticated teams of experienced computer programmers, but it exiles the rest of the staff, and this has significant productivity costs. And Git is intimidating, not just to non-technical staff, but also to inexperienced programmers. In How To Destroy A Tech Startup In Three Easy Steps I talk about Sital, and his unwillingness to commit things to Git. He was learning a great deal about many other technologies, and he didn’t have any spare energy to learn about Git. He went a month without making a commit, and then he only did so because I insisted. After I put a lot of pressure on him, he got to the point where he would make one commit a day, at night, when he was stopping for the day. He would commit to the master branch, because he was confused how to handle different branches. When there was a merge conflict, I would resolve it for him. We worked together for 6 months, and in that time he learned a great deal about a lot of important topics, but he never really learned how to use Git, because it was a low priority, for both him and our CEO.
Git is very powerful? I’m willing to go along with that line of thought so long as we all understand that using a tool that is more powerful than needed can lead to problems.
http://www.smashcompany.com/business/business-productivity-h...
You're right about the joy that end users feel when they learn TortoiseSVN and are able to put what they see as "infinite undo" into practice so easily.
There was a sarcastic list of git koans, too, somewhere, which I found funny.
The argument is focused on those who can not learn how it works. See some of the other excerpts from the essay that are in this thread.
Also, it's important to note that everything on that list is something that actually happened. Be careful about comparing your advanced skills to people with less skill than you.
If you're a software developer who uses branches and merges, you absolutely should learn how it works.
If you're an artist, git is not for you. It can neither store large binary files efficiently, nor merge them. There are other VCS that supposedly can, but I haven't tried them.
> Also, it's important to note that everything on that list is something that actually happened.
I can assure you, no data was permanently lost. What did happen is somebody couldn't find it, because they didn't know where to look. And I argue they should have, because git is not really that hard to learn (as a developer).
Exactly. That is the entire argument. From the essay:
------
I agree, Git is amazing and very powerful. What I’m suggesting is that we should recognize that it has a very high cost. It might empower complex workflows for sophisticated teams of experienced computer programmers, but it exiles the rest of the staff, and this has significant productivity costs.
...Git is very powerful? I’m willing to go along with that line of thought so long as we all understand that using a tool that is more powerful than needed can lead to problems.
http://www.smashcompany.com/business/business-productivity-h...
[ EDIT ]
Also, this bit from the essay might make the argument more clear:
For many years, I had a refrain which I gave as advice to each client I worked with: “Your software developers are expensive, so try to shift work away from them.” Ideally, software developers should only do work that relies on skills that no one else has. If a task can be done by a graphic designer, then it should be done by a graphic designer, because generally graphic designers are paid less than software developers (obviously not in all cases, but most of the time). I co-founded a startup in 2002, and I stayed with it till 2008, and we ran a team of 8 people using this principle: push work to the less skilled people, if they can handle it. Save the tough stuff for the computer programmer. We had great success with this style of work.
It’s all “choose your abstraction”, so you’ll be filling your head with something whether it’s which button to push or what git checkout does. GUI or not, no button alt text is going to tell you what rebase means.
> This site is not intended to be an exhaustive reference, nor is it a beginner's tutorial.
> Disclaimer: I am not, nor do I even remotely claim to be, an expert at git. This site is not intended to be an exhaustive reference, nor is it a beginner's tutorial. And yes, there are other ways to do these same things with more theoretical purity or whatever, but I've come to these steps through trial and error and lots of swearing and table flipping, and I had this crazy idea to share them with a healthy dose of levity and profanity. Take it or leave it as you will!
> This site is not intended to be an exhaustive reference, nor is it a beginner's tutorial.
But beyond learning Git itself, you need to develop suitable habits for using Git that are appropriate for your development workflow.
One habit I've consciously developed is to use 'WIP' commits (i.e. a regular commit with "WIP: Rebase me!" on the first line of the commit message) instead of stashing. All too often a stash lives for much longer than you'd naively expect and stashes are much harder to work with than commits. Even if the modifications are applied right away, commits are nearly as easy to 'apply' as a stash anyways.
I'd like to contribute my list of git booboos: https://github.com/1337/yesterday-i-learned/blob/master/git....
Your answer there is just doing git pull --rebase by hand. I don't like that style at all, but if you must do it surely use the command that's designed for doing it.
> I pushed stupid things onto the remote server
Worth saying you can branch before fixing - that might be a little less intimidating than "access by commit ID"
> I already made my changes in multiple commits, but the repo owner wants me to rebase it to a single commit
Disagree with "you should do it", though that's probably a political question.
I think I would rebase my PR comment history away only if "the repo owner wants me to rebase it to a single commit". In that case, I'm just doing whatever the repo wants the repo to be structured.
Shouldn't it be easy for Git to remove objects created after a given time, and then remove all objects that refer to those objects iteratively?
(Which is why I've almost exclusively switched to `git checkout -b <newbranch>` for creating. How often do I want to create but not switch to the branch?)
I added a file and wanted to diff it, and this command helped! However, I made some changes in the file, and when I tried this command a second time, the changes don't show up :\ Only the original file that was added shows up in the diff. Now what? It's not the end of the world of course, as I can just look at the file in my editor, but I usually use diffs as a personal code-review before I commit.
* the most recent commit
* the staged files
* the working directory
`git commit`, as you might already know, takes "the staged files" and turns it into a commit, making that the latest commit. `git add` adds a snapshot of a file in your working directory to the staged files. The important bit here is that the copy of the file in the staging area is separate from the file in your working directory. So, if after `git add`ing a file you make more changes, you will need to `git add` those subsequent changes if you wish to commit. `git status` will tell you this:
» git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: foo.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo.txt
"Changes to be committed" is the staged files. "Changes not staged" is stuff that has been modified, but not `git add`'d. You can see here that I've changed foo.txt after git adding it; if I want those changes, I need to git add it again.I can look at the diffs, too:
# diff between the last commit, and the staged files
# (i.e., what will be committed)
git diff --staged
# diff between the staged files and the working directory
# (unstaged changes)
git diff
# diff of all changes since the last commit:
# (stage+working dir, essentially)
git diff HEAD
That should be all the various combinations.I find that a lot of newcomers find the staging area weird, and usually ask some variant of "why would I not want to commit all of the files I've changed?" The staging area, used effectively, can really help you break out things into logical chunks of changes that can then be adequately described with a message in a commit. This can help others later: if your change is a bug fix, and someone wants to cherry-pick it to production, they might not want your new feature, or your lint fixes: they want a minimally risky fix. To that end, the stage/working dir separation acts as a sieve of sorts, letting the stuff that's "ready to go" get filtered out into a commit.
I want to mention the extremely useful `git add -p`: this command will interactively prompt you, hunk by hunk, for whether or not you want to stage that hunk. It will even let you edit the hunks prior to staging. So, for example, if I run across a spelling error, or a minor bug, I can very quickly add it (and just it) to the stage w/ `git add -p`, and then commit it, even if there are other modifications, even in the same file.
> * the most recent commit
> * the staged files
> * the working directory
This is weird. The staging area is like a commit but not a commit. They're changes that git is aware of and has a record of but not quite a permanent record.
Why not just make it a commit? You can always keep editing commits, or throw them out, or whatever. That's what I do with Mercurial. I write a commit and I keep adding stuff to it if I think it needs more stuff (or less stuff).
Gregory Szorc has a more extensive analysis of the situation in first subsection here: https://gregoryszorc.com/blog/2017/12/11/high-level-problems...
My other guess is that the "index" (the other name for the staging area) is also used for conflicts during merges & rebases, and that somehow plays into the problem of making it an actual commit. (But again, this comes across more as an excuse than a reason: I don't any viable reason why the staged changes can't still be an actual commit, and the merge conflict data just stored as a separate structure.)
That, or the person who added it just didn't think of it, or couldn't do it due to backwards compatibility.
git pull —-rebase
& git log
git rebase -i HEAD~n
So basically I want to make sure my work is pushed to remote as a separate commit before attempting to run any commands except the ones above. But you can do pretty much anything with the set above.I also use `git merge-base` quite a bit so that I do not have to count commits when working with really simple branches.
Add individual files, and, if possible, use `git add -p`, which lets you review each chunk before adding it to the index. Otherwise, diff and add individual files.
In those cases, it's better to use `git reflog $BRANCH_NAME`, which has the additional advantage of not including your switching from one branch to another.
# Oh shit, I've changed 200 files and want to revert to the state of this morning
$ git add . && git commit # often. Very often.
$ git reset --hard commit_idI guess you could rely on the reflog, but I don't think that's good practice.
It's purely commiting often to easily have checkpoints to revert to, nothing fancy (yet, incredibly useful).
1. ‘git add .’ is dangerous and should be avoided IMO, in case you ever have files around that you don’t want to commit. I frequently do. It’s better to ‘git commit -a’, and to just remember to run ‘git status’ frequently and ‘git add’ any new files.
2. ‘git reset —-hard’ is dangerous as well for newbies, since it’s destructive. Better to ‘git revert’ or to ‘git checkout <sha>; git checkout -b <newbranch>’, such that you can always get back to where you were.
I visit this page every few weeks. :)
PLEASE add a note to check if you have anything interesting in stashes/branches before doing the rm -rf, I've lost some work so many times because of the "fuck this noise" approach.
Git golden rule: Never push -f if you don't know what you are doing.
Interactive staging, eg git add -p or git checkout -p
You’ll be asked, for each change, if you want to stage it. This helps tremendously in preventing commits with stray marks, console logs, etc. Try it!
`git log` tells you all the commits that are part of the branch. More generally, they are the commits who are children of the current commit (the commit your branch points to).
`git reflog` tells you where your HEAD has been. When you change for branch to branch, the HEAD moves around. That history is recorded in the reflog. If you botch a rebase, your HEAD will sit on top of the newly created (and botched) commits. You can still access your previous commit by looking where the HEAD was before moving to the new commits made by the rebase.
If any of those commits with confidential information is reachable from any of those commits, then they'll never be garbage collected from Github.
| Oh shit, I do before I think
For these users, git is perfectly useable and easy to use.
like, how do you even exit vim? You need a guide for that. Or to get it closer to git / this guide, how do you undo / redo?
[1] https://dementiagaming.files.wordpress.com/2010/08/learning_...