rel:: [[distributed version control|DVCS]]
# git
## Reference
- [git-sim](https://initialcommit.com/blog/git-sim) - visually simulate git operations
- [inside .git](https://jvns.ca/blog/2024/01/26/inside-git/)
- [git tips and tricks](https://blog.gitbutler.com/git-tips-and-tricks/)
- [common git config options](https://readwise.io/reader/shared/01hpsftrsssp238jeaqr35ntnq) ([[Julia Evans]])
- [bfg](https://rtyley.github.io/bfg-repo-cleaner/) - repo cleaner
## Machete
For stacked branch workflows.
It's worth going through [a git machete tutorial](https://medium.com/virtuslab/make-your-way-through-the-git-rebase-jungle-with-git-machete-e2ed4dbacd02) and learning its model. git doesn't have a concept of branch hierarchy itself, so machete brings its own mapping (visible with the status and edit commands).
### My workflow
#### `.gitconfig` Aliases
```
[alias]
m = machete
sync = "!sync() { git machete traverse -yW --push; }; sync"
cpr = "!cpr() { git machete github create-pr --draft && git machete anno $(git machete anno) update=merge; }; cpr"
```
#### Common Actions
```
# register current branch with machete
# it will try to infer the "parent" branch and it nearly always guesses right
git m add
# see status and tree relationships of your branches
git m s
# creates a PR from the current branch, marking it to merge instead of rebase whenever I sync
git cpr
# pulls latest trunk and recursively rebases dependent branches
# if a branch has a PR associated with it (the update=merge annotation in the 'cpr' alias), the sync will merge instead of rebase
git sync
# edit the machete branch relationship tree
# only need this on occasion, the format is just plain text with child branches indented under their parents
git m e
```
## Cookbook
### Recovering from a `git push -f` with [[GitHub]]
> [!note]
>If you've force-pushed to a branch only you are working on, the easiest is to use `git reflog` and `git reset` followed by another force push.
This procedure is useful if you've force-pushed to a shared branch and your local branch was out-of-date.
```bash
# First, populate the GITHUB_TOKEN env var with an access token from https://github.com/settings/tokens
# find good sha from previous events, look for recent changes to <BROKEN_BRANCH>
curl --header "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/repos/:owner/:repo/events
# create a remote branch with good sha from event log
curl --header "Authorization: Bearer $GITHUB_TOKEN" \
-X POST -d '{"ref":"refs/heads/<FIX_BRANCH>", "sha":"<SHA FROM_EVENT_LOG>"}' \
https://api.github.com/repos/:owner/:repo/git/refs
# fix
git fetch
git checkout <BROKEN_BRANCH>
git reset --hard origin/<FIX_BRANCH>
git push -f origin <BROKEN_BRANCH>
```