[HN Gopher] Learn Git Branching
___________________________________________________________________
Learn Git Branching
Author : dsego
Score : 136 points
Date : 2024-09-15 11:14 UTC (11 hours ago)
(HTM) web link (learngitbranching.js.org)
(TXT) w3m dump (learngitbranching.js.org)
| l5870uoo9y wrote:
| I have these Git shortcuts stored in my .zshrc file:
|
| # https://stackoverflow.com/questions/4298960/git-add-a-git-co...
|
| git config --global alias.ac '!git add -A && git commit'
|
| git config --global alias.acm '!git add -A && git commit -m'
|
| git config --global alias.ll '!git log --graph --full-history
| --all --color
| --pretty=format:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s"'
|
| git config --global alias.gst '!git status'
|
| git config --global alias.gca '!git commit -a --amend'
|
| git config --global alias.gp '!git push origin HEAD'
|
| git config --global alias.bd '!git branch -d'
|
| git config --global alias.bdd '!git branch -D'
|
| git config --global alias.mc '!git diff --name-only --diff-
| filter=U'
|
| git config --global alias.co '!git checkout'
|
| git config --global alias.po '!git push origin'
|
| git config --global alias.cp '!git add -A && git commit -m
| "Content" && git push'
|
| Out of those, I only - but often - use `git acm` and `git co` and
| `git po`.
|
| Edit: formatting (oh dear).
| cryptonector wrote:
| I have aliases like - `ls` for `ls-files`
| - `lo` for `git log --oneline`, then add a variety of letters
| in multiple combinations like - `r` for `--reverse`,
| - `s` for `--stat`, - `om` for `origin/master..`,
| - `1` for `-n1`, `2` for `-n2`, `3` for `-n3` (maybe up to 5),
| - `rbi` for `rebase -i`, - `rbiom` for `rebase -i
| origin/master`, - `rbc` for `rebase --continue` -
| `rba` for `rebase --abort` - `cp` for `cherry-pick`,
| - `cpa` for `cherry-pick --abort`, - `cpc` for `cherry-
| pick --continue`
|
| I also have _shell_ aliases like `gits` that works out to `git
| status -uno`, and `gita` that lets me add tracked files. I need
| a `gitca` for `EDITOR=true git commit --amend`.
|
| Notice I don't have aliases for merging. I use strictly rebase
| and cherry-pick workflows.
| samatman wrote:
| I went to the other extreme. I have a somewhat elaborate fish
| function which detects any use of -a and refuses to call Git
| with it.
|
| I had gotten lazy about good commits, basically, `git commit
| -a` was in my muscle memory. Forcing myself to treat staging as
| a step before committing, and getting in the habit of using
| `git add -p` when called for, has made a meaningful difference
| in the quality of my commit history.
|
| If one is disciplined about making changes in the first place,
| I suppose this matters less. But I'm not, and also don't want
| to be: if I spot something else which needs doing while I'm in
| flow mode, I'm not going to put it off just to keep commits
| nice, not when there are better options for doing that part.
| alkonaut wrote:
| I make one elaborate commit where I carefully stage things
| etc. But invariably I miss something, find 3 typos and so on.
|
| _that's_ when the aliases are handy. The alias for fixing a
| typo is using all, amend and no-edit. Super useful. But
| obviously needs to be used with care when you only do such a
| fix. I'd be perfectly happy for my git oops to refuse running
| if there is more than one changed line to commit, for
| example.
| alkonaut wrote:
| It's strange that git aliases can't accept multiple git
| commands. It gives a strange divide between single command
| aliases which go in your git config and multi command aliases
| which go in a shell config. Shells vary and some don't even
| have aliases (cmd is probably the most used shell of them all
| and it - almost - doesn't have aliases at all).
|
| Being able to define an && alias in .gitconfig would be great
| for being able to share snippets like these across shells and
| OS:es.
|
| My most used alias is by far "git oops" for git commmit --all
| ---amend ---no-edit
| stephenr wrote:
| You can absolutely put multiple commands in a single git
| alias. The comment you replied to even shows it.
|
| There's no reason any of those couldn't be in a .gitconfig
| file.
|
| Prepend the alias with ! it's executed via a shell. I use it
| to embed shell functions (which generally call git)
|
| Eg an alias to show commits missing (useful when using cherry
| pick) show-missing-commits =
| "!show_missing_commits() { local target=\"${2:-$(git rev-
| parse --abbrev-ref HEAD)}\"; printf -- 'Showing commits
| present in \"%s\" but not \"%s\"\n' "$1" "$target"; git log
| --no-merges \"$1\" ^\"${target}\"; }; show_missing_commits"
| alkonaut wrote:
| I'm pretty sure that it's shell specific whether it works
| precisely _because_ it defers it to the shell. For windows
| cmd in particular it's... not great.
|
| What I mean is I'd like git to do it natively. But git was
| written assuming a posix shell and it shows up here and
| there sadly.
|
| Example: git command1 ---flag1
| <some_separator> command2 ---flag2
|
| Should be possible for git to simply interpret
| sequentially.
| stephenr wrote:
| > But git was written assuming a posix shell and it shows
| up here and there sadly.
|
| Given that the entire point of POSIX is cross platform
| compatibility, this is one of the few times when I will
| say they (Linus/git) got it 100% right.
|
| > Should be possible for git to simply interpret
| sequentially.
|
| Simply? What should it do if the first command fails?
| Should it exit early? What if you want it to run the
| second only if the first returns error? What if you want
| to pipe the first to the second? Or use it as an
| argument?
|
| Aliases have a "simple" mode where they call exactly one
| thing. Anything beyond that can't be simple, without also
| being useless.
|
| If Microsoft can't ship a POSIX compatible shell that's
| on them, and if you insist on using an OS that doesn't
| have a POSIX compatible shell, that's on you.
|
| I don't start Linux and ask why it doesn't run whatever
| people use Windows for... malware I assume?
| alkonaut wrote:
| > Simply? What should it do if the first command fails?
| Should it exit early? What if you want it to run the
| second only if the first returns error?
|
| You'd eventually reinvent a shell. But for just these 2
| cases you'd just need 2 separators analogous to the & and
| && of the shell. But yeah it gets messy if you wanted to
| run a _non_ git command in the middle.
|
| The thing is, all those !a && b are perfectly valid in
| both posix and cmd. It just refuses to do the whole "if
| it starts with ! call the shell". I guess all that's
| missing is that it just needs to execute it. That would
| probably be the less complicated change. That at least
| doesn't seem like a big controversial addition (maybe
| this is already done now it was a couple of years since I
| tried and hit a brick wall with aliases under cmd)
| drmohundro wrote:
| I found these online and added them to my gitconfig at one
| point... I can't take credit for them. Integrating fzf with git
| makes working with branches even better (with fuzzy matches for
| checking out as well as deleting branches)...
|
| cob = !BRANCH=`git recent --no-color | fzf` && git checkout
| ${BRANCH}
|
| db = !BRANCH=`git branch --no-color | fzf` && git branch -d
| ${BRANCH}
|
| dbf = !BRANCH=`git branch --no-color | fzf` && git branch -D
| ${BRANCH}
| gcarvalho wrote:
| There's fzf-git.sh [1], which is a collection of bindings to
| invoke fzf for things like branches, commits, tags, etc. I
| use it pretty often.
|
| [1] https://github.com/junegunn/fzf-git.sh
| srameshc wrote:
| This is really great resource for someone getting started to
| understand what's going on. I see many have issues and try out
| different git commands without understanding the outcome.
| leetrout wrote:
| It's a really great resource to come back to for those of us
| who have been using git over over a decade, too!
| shagie wrote:
| https://onlywei.github.io/explain-git-with-d3/ is another one
| that I've used to demonstrate the repository state after
| various operations.
| fluorinerocket wrote:
| I always send this to new hires who don't know git. Pretty
| common in mechanical engineering
| leetrout wrote:
| I also recommend an alias like this (and l5870uoo9y has other
| examples and how to set them as git aliases)
| alias gitlg="git log --graph --all --format=format:'%C(bold
| blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold
| green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''
| %C(white)%s%C(reset) %C(bold white)-- %an%C(reset)' --abbrev-
| commit"
|
| From http://stackoverflow.com/questions/1057564/pretty-git-
| branch...
| TomK32 wrote:
| tig is a really nice tool for a very similar view
| https://jonas.github.io/tig/
| cryptonector wrote:
| Git _is_ branching. Every clone is a[n unpublished] branch.
| dailykoder wrote:
| For me, git is a prime example which shows that theoretical
| understanding of some problems is absolute beneficial. If you
| just keep in mind that it's (basically) just a directed graph,
| it makes the usage a lot easier.
| derriz wrote:
| I dunno - for me git doesn't really have branches. What it
| calls "branches" could more accurately be called version/commit
| pointers.
|
| A "branch" traditionally in SCM was a sequence of
| versions/commits. In those SCMs, the "main" (or master) branch
| was an identifiable sequence of versions/commits.
|
| There isn't a "main" branch in git, there's a current "main"
| version/commit. If your history is fully linear, a pointer to
| the "main" commit allows you, via parent following, to discern
| a "main" branch. But if you've been using merge, for example,
| there isn't a unique path from the current main commit to the
| root.
| PhilipRoman wrote:
| This does sometimes cause problems when trying to understand
| history. Would love if git recorded the current branch name
| (if any) somewhere in the commit
| imron wrote:
| I have a git commit hook that automatically adds a git
| trailer containing the jira ticket/issue number to the
| commit message.
|
| It gets this from the branch name which by my convention
| always contains the ticket ref.
|
| It would be trivial to modify this to use the full branch
| name instead.
| User23 wrote:
| Understanding refs is key to understanding Git. It's not
| really difficult and a lot of mystifying cargo cult stuff
| suddenly becomes intuitive once you realizing you're pretty
| much just manipulating pointers into a directed acyclic graph
| where each node has between 0 and 2 parents.
| dahart wrote:
| Meh getting too reductionist doesn't necessarily help
| anything. Branching is a concept, not an implementation
| detail. There is a "main" branch in git because that's how
| people talk about it, and what they usually mean when they
| refer to "main" or another branch; people are not usually
| referring to a singular tip-of-the-branch commit, but the
| whole branch and it's history. A branch is different from a
| tag or a commit because the branch is expected to move
| frequently (point to different commits) and tags/commits
| aren't. The implementation isn't different, but the usage and
| meaning is. Branches in other SCMs are really no different
| conceptually. Perforce doesn't identify any unique path from
| the tip of the branch to the root it came from, you can merge
| both directions. Same is true in other SCMs.
| derriz wrote:
| It's more than an implementation detail.
|
| Without changing the DAG, I can arbitrarily move "main" to
| point at any commit I like in git. This isn't some esoteric
| action - this is done constantly as part of normal git
| workflow.
|
| While what people understand as a branch in traditional SCM
| discussions can only grow by the addition of new versions.
| Commits/versions belong to a specific and unique branch and
| once added to the version tree, cannot "move" branches.
|
| While in git, a commit can belong to any number of (git)
| "branches" which makes presenting a true branch based
| history (if the DAG contains merges) impossible. Which is
| why we all end up using a workflow based on rebase instead
| of one based branch-and-merge.
|
| I've observed how much confusion using the name "branch"
| for what is a version pointer in git causes to those
| starting with git. The easiest way I've found to help
| people is to tell them forget about the word "branch" and
| think in terms of the DAG and pointers to elements in the
| DAG.
| dahart wrote:
| Sure git is a bit different than P4 or Svn or whatever;
| they all have unique implementation details. I don't
| disagree that git confusion sometimes exists nor that
| you've seen it, but it might make your point clearer to
| give a specific example, one that knowing a branch is a
| pointer fixes. I'm not sure if it's useful to think of
| commits as immovable; they can be rebased and cherry
| picked, the "version" (SHA) is another implementation
| detail. Moving the content of commits around is common
| standard practice with git. That's a different type of
| move than a branch move, not what I was referring to
| above, but I guess I'm arguing that branching is more
| about workflows, conventions, and conceptual
| understanding than how it works technically. You're right
| that it's sometimes useful to know that a git branch is a
| pointer and super lightweight, but that doesn't help you
| differentiate branches and tags, for example. Git has a
| bunch of features that are 'just' a pointer. Knowing that
| is good for advanced workflows, but not really necessary
| for basic version control.
| cryptonector wrote:
| Opinionated branching is super obnoxious. It's much
| better to let you see the truth with a thin traditional
| branching veneer, and you can choose to enforce "fast-
| forwards"ness or not.
| Zambyte wrote:
| Jujutsu is a great interface to the git data structures, and
| it makes all of this obviously true.
| cryptonector wrote:
| A proper branch in Git is just a name for a commit with the
| rule that when you commit to a branch you move the name to
| point to the new commit, and similar rules on push.
| lainga wrote:
| Has anyone used `git describe` in anger?
| talkingtab wrote:
| I'm one of those "I don't want to read the manual" people and
| have long used git. However, this was very helpful to easily
| understand some cargo-cult things I was doing. Shame on me! And
| thank you!
| mediumsmart wrote:
| excellent tutorial, thank you for that.
| dev1ycan wrote:
| great tutorial!
| DavidWoof wrote:
| One of my biggest pet peeves about modern development is just how
| many people don't know jack about git even though they use it
| every day. It really annoys me when I see a pull request with 20
| random commits (with messages like "temp" or "checkpoint") or
| when people merge main into their personal feature branch instead
| of just rebasing their branch (yes, sometimes that's not right,
| but I'm not talking about the corner cases).
|
| I always think about using "clean up a pull request" as a
| fizzbuzz-ish screen in interviews. It just seems like a decent
| proxy for "do you care at all?".
| Blackthorn wrote:
| I agree with you in spirit (people need to learn their tools
| more) but your examples...not so much. Merging main into the
| feature branch was the original intent on how to do it. PRs are
| sent the way you describe because GitHub literally offers the
| maintainer a squash option and it's a lot easier to review a
| pull request when history is unedited.
___________________________________________________________________
(page generated 2024-09-15 23:00 UTC)