Readit News logoReadit News
anyfoo · a year ago
`git reflog`, which the article prominently mentions, really should be the VERY FIRST thing to teach everyone who is learning git.

If you don't know about it, it is well worth checking it out now.

It is your one ticket to getting to whatever previous, good (or bad!) state you were at any point before[1]. The only thing it cannot help you recover is locally made changes that you never committed to anything at any point, and have since locally deleted. This is surprisingly rare, at least for me, as I just tend to `git stash` stuff I don't want anymore.

With `git reflog` in your backpocket, you can rebase, merge, branch, delete branches, cherry-pick, rewrite history, whatever, all to your heart's content. `git reflog` keeps a journal of every single action, and tells you the HEAD before and after each action, which you can then simply checkout or `reset --hard` your branch to.

I never even use any arguments with it, I literally just `git reflog`.

[1] Unless garbage collection has deleted the commit you were pointing to, I guess, but I've never had to use `git reflog` that far in the future.

idoubtit · a year ago
Over the last decade, I think I've only used `reflog` twice. The only case I remember clearly was to help a co-worker that had created a local mess, starting with a `git pull` (meaning a merge) on the wrong branch then piling onto that.

If you use Git in a terminal, a much simpler alternative to the reflog is having the commit hash in the prompt. Then comparing/reverting to a previous state just requires scrolling the terminal to find the commit id. It's much easier to read than the reflog. With the help of the shell prompt, the terminal can help with the questions "what did I do to get there and how to get out?".

I also think that Git has become much more error-proof. It's been a long time since I've seen anyone lost in their own repository like I'd seen years ago. There are better GUIs. In the command line, modern Git often displays hints, has warnings for some dangerous commands, and sometimes explains how to rollback.

anyfoo · a year ago
For me, it‘s usually not about somehow „breaking“ my repository so that it‘s in a „weird“ state, but about messed up rebases, filter-branches (or modern equivalents), and other branch manipulations that leave my branches in a now unwanted state.

When working on big projects with many people, multiple release branches, and constant updates to those release branches, there‘s bound to be situations where you try to juggle multiple local branches for the same change(-set) to massage conflicting changes into place, only to after a while go „no, that went bad, let‘s start over“.

Having the commit ID displayed by the prompt is a good idea, and it solves the problem in a similar way. However, I prefer my prompt to be on one line, and it‘s already pretty long. Plus, I often do lots of stuff between git commands, so I‘d have to „hunt“ for the prompts. I need git reflog on average probably about once a month, and just typing „git reflog“ and seeing what git operations I‘ve performed is perfect for me.

compressedgas · a year ago
I'd also recommend turning off reflog expiration with:

  gc.reflogexpire=never
  gc.reflogexpireunreachable=never

dabber · a year ago
Defaults for each option of anyone is curious:

> gc.reflogexpire

90 days

> gc.reflogexpireunreachable

30 days

anyfoo · a year ago
I didn‘t know about that. Good idea, thanks.
lucasoshiro · a year ago
Even though I find reflog very useful, I don't think it should be the first thing.

What I think that should be one of the first things and most people don't know is written in "What is Git?" chapter from Pro Git: https://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3...

ezst · a year ago
> `git reflog`, which the article prominently mentions, really should be the VERY FIRST thing to teach everyone who is learning git.

Top that up with `log` showing all branches at all times (except if you ask otherwise) and you end up pretty much where mercurial is. Detached heads is such nonsense. Git missing phases and obsolescence (to denote if and how history eventually got rewritten) is another.

anyfoo · a year ago
Oh, I actually make heavy uses of detached heads. The projects I work on frequently require you to look at a „snapshot“ of how the code was at a certain time when diagnosing issues, and it‘s good to be able to „look without touch“, i.e. being able to check out a specific state without it cluttering up my branches (though honestly, they‘re pretty cluttered already).
vbezhenar · a year ago
I'm creating local tmp1 tmp2 branches before I'm doing anything sketchy. Branches will keep the commit visible and I can always return to the previous state if necessary. Tags would be more appropriate, I guess, I just got used to branches more.
anyfoo · a year ago
You can see „git reflog“ as a sort of automatic tmp-branch creation at every step. Of course your way works as well, and I tend to do the same when I know it‘s getting hairy, but it‘s nice to just be able to do git stuff knowing you can always go back without much precaution.

The only thing I need to remind me to be careful about is, as said, uncommitted changes. With some luck, Time Machine can help for that, but to be safe I practically always stash away changes instead of somehow undoing them.

joshka · a year ago
I'd replace that with giving someone a link to Git Fix Um[1]

[1]: https://sukima.github.io/GitFixUm/

Dead Comment

donatj · a year ago
> People who say "just delete the repo" when things go wrong really frustrate me

YES. Go be a baker or something! If you're going to be a developer you should generally speaking be willing to figure out what's wrong and how to fix it.

Know how your tools work. Bad carpenter what have you...

Also speaking of `git reflog` and such - I still stand by this article I wrote a few years back - https://donatstudios.com/yagni-git-gc

99% of people should just turn automatic `git gc` off. You don't need it. Turn it off and you never have to worry about losing work. It's there, you just have to find it.

zvrba · a year ago
Git is an abysmal tool for many (most?) uses of it, but that unfortunately has become "standard". The sheer awfulness of git is witnessed by the amount of posts about it and little consensus on "best practices" (e.g., rebase vs merge).

So, I don't judge, but sympathize with people who just "delete the repo and start from scratch". Unintuitive, user-hostile tools call for heavy-handed solutions.

IME, most people are willing to learn something when they're shown the value for invested effort. That "delete the repo" is standard answer for fixing f*up, tells more about the tool than the people using it. (I.e. it requires disproportionately big investment of time for little value.)

DexesTTP · a year ago
I really don't agree with that. Git is a powerful tool with very few actual downsides, and the unwillingness of some developers to spend an hour learning how it works hurts them in the long-term.

It's like sticking to the text editing feature of your IDE because you can't be bothered to learn how it works. Sure, you _technically_ can do that, but you're losing on everything that makes an IDE useful and probably losing actual days or weeks worth of work because of that.

compressedgas · a year ago
Instead of turning off the automatic git gc, turn off the reflog expiration with:

  gc.reflogexpire=never
  gc.reflogexpireunreachable=never

jimmaswell · a year ago
I could spend hours of my workday on some uninteresting, irrelevant bullshit because the local repo is fucked, or just delete it and move on to solving actual problems and producing value. The choice is clear.
Zambyte · a year ago
Or you could spend an hour or so learning to use git (or a git compatible vcs like Jujutsu) and then you never bork your repos, and instead spend your time solving actual problems and producing value.

What kind of pastries do you like?

usr1106 · a year ago
I have never deleted a repo because it's messed up. In the early days understanding what was wrong was sometimes challenging. But once I learned it it's just routine to clean it up. I do occasionally search stuff from my reflog or trial branches from years ago, no way I want to lose that opportunity.

One needs to learn full branch names and how the abbreviations used in daily life really work. A local branch called origin/foo can be confusing, especially after being pushed. And of course one needs to understanding the concept of remote branches in the first place, they are not really remote, typical poor git terminology.

For mass mess-ups in the work tree git status -s | grep ... oneliners are your friend.

matheusmoreira · a year ago
Or you could actually learn git once and enjoy using a powerful tool without experiencing any of this friction. If you understand git you'll just know what to do when some weird thing happens.
cedws · a year ago
I haven’t done that since my junior days. Do people really do this? I know Git’s UX is bad but wow.
alganet · a year ago
To me, commit messages really shine on file histories and `git blame`.

Opening an unknown file and having the option to see all it went through is powerful. The commit messages and history will tell you which files are related, which files change together, why they do, etc.

It's a superpower that a team can cultivate.

lucasoshiro · a year ago
I strongly agree.

Git isn't only code sharing that you commit and forget. It is a database of code that tracks what changed, why changed, who changed and when changed.

Want to know why a piece of code exists? Find the commit that introduced it, read the message. If it's not enough, you can search the commit and find the discussion on GitHub/GitLab/etc.

A new bug suddenly appeared? Use git bisect to find what was the commit that introduced it.

Some months ago I posted some tips about using Git as a debugging tool, if you want to read more about it: https://news.ycombinator.com/item?id=39877637

PaulDavisThe1st · a year ago
See also:

    git log -L:funcname:file
funcname will be matched after wrapping it in a "function declaration identifying" regexp.

Get the entire history of a given function (as long as it was in <file>). Not a daily driver, but sometimes unimaginably valuable.

vbezhenar · a year ago
I'm using git history may be one time a year. And even those times might be just of pure curiosity: who's that dumb who did that bug. Basically it's useless for me. So I don't care much about commits. Git for me is a collaboration tool and code backup tool, and that's about it. Nobody will look at my 1-year old commit and I'm not going to look at anyone's 1-year old commit.
lucasoshiro · a year ago
> who's that dumb who did that bug

You can find more than that, e.g. what was the context of the introduction of a code, find the discussion about that introduction, what was the situation of the project when the code was introduced, etc. But even if you only want to blame, it is enough to keep a good commit history.

> Nobody will look at my 1-year old commit and I'm not going to look at anyone's 1-year old commit.

If you commit history isn't good no one will. And no one will benefit of using git. And then you don't need to use git.

> Git for me is a collaboration tool and code backup tool, and that's about it.

If you don't see the point of having a commit history, there are other tools that fit it better. For code collaboration, JetBrains' Code With Me and VSCode's CodeTogether. For code backup, Google Drive or Dropbox.

RadiozRadioz · a year ago
Well, it completely depends on your job and work style. Personally I'm a site reliability engineer, so when something breaks it's an invaluable step to look at the commit history to see what changed, when, how, why, and by whom.

I'm searching through commit histories several times per hour.

rudasn · a year ago
Good commit messages can be used in lieu of official documentation, and that makes them veey helpful.

Whether or not relying on git commit messages for source of truth documentation is a good idea is debatable, but personally, when people do it I'm glad they did.

JelteF · a year ago
The most effective way I've found to get other people to "write" good commit messages is by changing the "Default commit message" for squash merges on the GitHub repo to "Pull request title and description". [1]

That fixes the "Squashing, when you have 100 crap commits, and then not re-editing the message is a crime" item, because suddenly not re-editing will give you a fairly useful message. This ofcourse assumes the PR description is useful, but I've found it much easier to convince people to write a decent PR description than to write decent commit messages.

[1]: https://github.blog/changelog/2022-08-23-new-options-for-con...

praash · a year ago
I love giving examples and context in a PR description. Squash-merged PRs can become cumbersome snowballs, but the final commit message should elaborate in proportion.
rudasn · a year ago
I also like to include before and after tables, either with stats (eg. perf) or with screenshot with UI changes.

First I head about automatic squash messages, and if they include the whole title and description I should look into it a bit more!

NotBoolean · a year ago
This is what we have resorted to in my team. It was just too difficult to get everyone to keep good commit hygiene and follow a best practice like conventional commits.
ericrallen · a year ago
Having been through the pain of getting teams to adopt conventional commits a few times, I found that integrating a wizard like commitizen helped folks who were annoyed by commit linting learn and get comfortable with the rules and format so there was less friction when their commit was rejected by the linter.

It also really helps if you can wire up some continuous deployment to automate something tedious like properly incrementing the version number in the semantic version, updating the changelog, and deploy out a new `latest` or `next` tag to the package registry.

Even the most reticent users are often inspired to follow conventional commits once they see the possibilities that open up.

lucasoshiro · a year ago
If you want more controversial things about squash, here are two that I posted here last week:

1. "How squash merge can break Git repos with submodules", about a situation where squash merges silently broke a repository: https://news.ycombinator.com/item?id=40846596

2. "Git: please stop squash merging!" giving some technical explanation about what squash merges actually are under the hood and how the misconceptions about Git leads to invalid "pros" about squash merging: https://news.ycombinator.com/item?id=40840572

fmorel · a year ago
The first is solvable with a PR check. You can do whatever you want with the submodule on your branch, but if you want it to merge to `main`, then your changes to the submodule have to merged to its `main`. We have a check that makes sure the referenced commits is on `main`, and not older than 10 PRs.
jenadine · a year ago
It frighten me how some contributor to my open source repo just don't care about their git history. They do 100 of "crap" commits (author's wording) and merge commits. Sometimes I'd write a comment like: "can you please rebase your branch" and even very senior software engineer are clueless and can't do it even if I give the exact git command i'd use. In the end it's simpler for me to do it myself.

Some developers don't even use git and just use some UI on top.

I wish GitHub would have an interface to do interactive rebase and edit commit messages.

jonathanlydall · a year ago
I consider myself very knowledgeable on using Git even though I almost exclusively use it through GUI tools, however my particular GUI wrapper of choice, TortoiseGit on Windows is incredibly powerful. I very regularly do rebasing, squashing, use worktrees extensively, etc.

When I occasionally have to work on Linux or macOS for our Electron based cross platform product, I haven’t yet found a GUI tool I feel comes remotely close to TortoiseGit in terms of advanced features. So much so that if I need to do things like rebasing or dealing with slightly complicated merges, I push first to a branch and then do the Git work on my Windows machine.

I could work out all the Git command line arguments for these advanced use cases, but for something like rebasing with some squashing or skipping, I can’t see how anything except a well designed GUI could be anything except a seriously clunky and much slower experience.

My feeling is that (good) GUIs in general make a lot more sense for Git, instead of having to read the entire manual upfront to know the available tools, the GUI can show relevant options based on context and you don’t get bogged down having to type out/paste commit references and other things into your terminal.

I occasionally use the built in Git tools on VS Code and Visual Studio 2022 (the latter of which only in the last couple of years didn’t completely suck), but generally only for simple pulls, commits and pushes, which is generally more convenient in the IDE than having to switch to TortoiseGit.

Of course a tool is just a tool, if you don’t “get” how Git works, no tool will save you, but I do think TortoiseGit’s rebase UI helped me get to the point where Git “clicked” for me sooner.

philwelch · a year ago
> I could work out all the Git command line arguments for these advanced use cases, but for something like rebasing with some squashing or skipping, I can’t see how anything except a well designed GUI could be anything except a seriously clunky and much slower experience.

That’s just an interactive rebase; on the command line it opens a text editor. It’s pretty easy.

gpderetta · a year ago
magit.
metadat · a year ago
> Do the work up front to make your history atomic

Is this saying 1 feature / main "idea" per commit?

Overall this post is gold, but also probably preaching to the choir. IME it's challenging to convert non-believers to the faction of Orthodox Git.

For me, learning the ins and outs of Git felt like uncovering a part of myself which has always been there. Nothing new was created, only revealed.

jcoder · a year ago
Not the author, but when I use the phrase I mean each commit accomplishes a single important thing, but also that each commit is complete: it includes necessary tests for example. IMO every commit that lands on `main` must pass the test suite (this means intermediate commits should be squashed into that atomic commit).
epage · a year ago
The more I've been doing open source maintenance and contributions where there isn't as much context between the code author and reviewer, the more I've been pushing for a little more than this.

- Add tests in a commit *before* the fix. They should pass, showing the behavior before your change. Then, the commit with your change will update the tests. The diff between these commits represents the change in behavior. This helps the author test their tests (I've written tests thinking they covered the relevant case but didn't), the reviewer to more precisely see the change in behavior and comment on it, and the wider community to understand what the PR description is about.

- Where reasonable, find ways to split code changes out of feature / fix commits into refactor commits. Reading a diff top-down doesn't tell you anything; you need to jump around a lot to see how the parts interact. By splitting it up, you can more quickly understand each piece and the series of commits tells a story of how the feature of fix came to be.

- Commits are atomic while PRs tell a story, as long as it doesn't get too big. Refactor are usually leading towards a goal and having them tied together with that goal helps to provide the context to understand it all. However, this has to be balanced with the fact that larger reviews mean more things are missed on each pass and its different things on each pass, causing a lot of "20 rounds of feedback in and I just noticed this major problem".

As an example of these is a recent PR of mine against Cargo: https://github.com/rust-lang/cargo/pull/14239

In particular, the refactors leading up to the final change made it so the actual fix was a one line change. It also linked out to the prior refactors that I split out into separate PRs to keep this one smaller.

jraph · a year ago
> Make sure you review your own code changes

The author says he reviews himself on a GitLab MR / GitHub PL, I rely on two things for this:

- git add -p, which also helps me split stuff in several commits if needed. It bothers me that it doesn't work for new files.

- git difftool dir-diff for changes with several commits

I like that it would work on any git hosting, and that it works locally. And that I can just amend my commits if I see something.

JNRowe · a year ago
`git add -p` can also work for new files, it just requires you to call `git add --intent-to-add` first. After using -N/--intent-to-add you'll see that the file is registered in the status output, and -p will work exactly how like you expect.

I often find myself spiking things then breaking them back down with -N and repeated `git commit -p` to form a reasonable history. The workflow seems to really suit my mind. However, it does require some testing vigilance if you're manually editing the hunks for clarity on top of simply splitting them up.

ydant · a year ago
Thanks for the hint about `--intent-to-add` / `-N`.

There's constantly new things to learn about git. I use `git add -p` extensively, but never thought to check for an option like that.

arcanemachiner · a year ago
> - git add -p, which also helps me split stuff in several commits if needed. It bothers me that it doesn't work for new files.

Lazygit is an amazing tool that can definitely do this (and many other useful things).

Deleted Comment