9 ms·
Learn Git Branching
- l5870uoo9y 2y agoI have these Git shortcuts stored in my .zshrc file: # https://stackoverflow.com/questions/4298960/git-add-a-git-commit-in-one-command 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 2y agoI 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 2y agoI 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.
- deleted 2y ago[deleted]
- alkonaut 2y agoI 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.
- deleted 2y ago[deleted]
- alkonaut 2y agoIt’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 2y agoYou 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 2y agoI’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 2y ago> 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?
- drmohundro 2y agoI 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 2y agoThere’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 https://github.com/junegunn/fzf-git.sh
- tecoholic 2y agoI so want to do this, but I am always scared that I will accidentally put in a wrong character and do something that will cause me hours of rework. Sure question, why have it in zshrc and load it every time a new shell starts? It’s all in the .gitconfig after the first run anyways right?
- actinium226 2y agoDon't live in fear. Embrace the chaos.
- Cthulhu_ 2y agoMy git status is `git s` aliased to `git status -sb`, don't need all the extra clutter. I also have a few .zshrc aliases, like `gap` which is `git add -p` or `gam` which is `git commit --amend --no-edit`. But also some typo fixing ones that I end up doing a lot, some because I type in half a command and get distracted / check something, then start over with a partially filled in command: alias gigit="git" alias gitgit="git" alias ggit="git" alias qgit="git" alias ght="git" alias got="git" alias cleear="clear" alias gits="git s" Another trick, in your .gitconfig, add this [alias]: git = !git That way, if you accidentally do `git git commit` or whatever (like above) it just works. Also, some typo fixes there: commmit = commit comit = commit
- hnben 2y agoyou should add a dog for pretty logging git config --global alias.adog "log --all --decorate --oneline --graph" https://stackoverflow.com/a/35075021 https://stackoverflow.com/a/35075021
- srameshc 2y agoThis 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 2y agoIt's a really great resource to come back to for those of us who have been using git over over a decade, too!
- shagie 2y agohttps://onlywei.github.io/explain-git-with-d3/ https://onlywei.github.io/explain-git-with-d3/ is another one that I've used to demonstrate the repository state after various operations.
- fluorinerocket 2y agoI always send this to new hires who don't know git. Pretty common in mechanical engineering
- leetrout 2y agoI 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-graphs http://stackoverflow.com/questions/1057564/pretty-git-branch...
- TomK32 2y agotig is a really nice tool for a very similar view https://jonas.github.io/tig/ https://jonas.github.io/tig/
- deleted 2y ago[deleted]
- petepete 2y agoI use tig for staging individual lines and hunks. Haven't found a faster or easier way in more than a decade. Such an underrated program.
- rgoulter 2y agoTig looks like a wonderful tool for all kinds of git interaction. I'm not too familiar with tig, but it looks like it does a lot of what Emacs' magit does. AFAICT, there are some things I find useful in magit that tig doesn't have: e.g. magit allows for committing/amending/rewording with just a few strokes; afaict, tig doesn't support the equivalent out of the box. e.g. in magit's status view, you'll get to see the diff for each change alongside the status entry. (Whereas tig limits itself to one view at a time; and viewing the diff is a different view than the status view).
- arunix 2y agoThere's also lazygit which does have features like this https://github.com/jesseduffield/lazygit https://github.com/jesseduffield/lazygit
- cryptonector 2y agoGit _is_ branching. Every clone is a[n unpublished] branch.
- dailykoder 2y agoFor 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 2y agoI 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 2y agoThis 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 2y agoI 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.
- imron 2y agoAnd now I'm on my computer, here is the modified version. Put this in: .git/hooks/prepare-commit-msg #!/usr/bin/env bash BRANCH=$(git symbolic-ref --short HEAD 2> /dev/null) # fail gracefully if we don't have a branch if [ -z "$BRANCH" ]; then exit 0 fi # add a git trailer with the branch git interpret-trailers --in-place --where before --if-exists addIfDifferent --trailer Branch="$BRANCH" "$1" And if you add the following alias to your ~/.gitconfig you'll be able to see the branch names in the logs by typing git lb (for log branch): [alias] lb = log --color --graph --pretty=format:'%Cred%h%Creset %C(bold)%(trailers:key=Branch,valueonly,separator=%x2c)%Creset - %s %Cgreen(%cr)%C(bold blue) <%an>%C(nobold yellow)%d%Creset' --abbrev-commit
- lainga 2y agoHas anyone used `git describe` in anger?
- benbristow 2y agoDon't git describe in anger, I heard you say.
- talkingtab 2y agoI'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 2y agoexcellent tutorial, thank you for that.
- dev1ycan 2y agogreat tutorial!
- DavidWoof 2y agoOne 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 2y agoI 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.
- aulin 2y agoPR should be sent to review in a state that author considers ready to merge. Assuming it will be squashed and taking that as a reason for submitting dirty history is just sloppy and unrespectful. Merging is for keeping track of a group of commits that has been taken from a feature branch and included in the mainline. Why would you clutter the feature branch with periodic main merges when you can cleanly rebase it and keep it tidy?
- Blackthorn 2y ago> Merging is for keeping track of a group of commits that has been taken from a feature branch and included in the mainline. Merging is for bringing a group of commits from branch A into branch B. It is, quite literally, the original way to perform this operation. It's not "clutter", it's a correct picture of how the code was developed.
- 2y ago
- TheHippo 2y agoNothing about the content of the site, but please stop determining the language of the user based on geolocation. If the browser says he wants English, serve English.
- Filligree 2y agoIf the browser says English, chances are pretty good that's because the user didn't configure it. ... that's the explanation I've heard, but I agree that it's obnoxious.
- troad 2y agoThat just doesn't seem to follow for me. Aren't most browsers auto-configured to request the language they were configured in? And don't most browser installs / setups default to the language of the user's system? I feel like if the browser requests English, odds are overwhelming that the user wants English. Assuming otherwise strikes me as someone trying to get a bit too clever with their heuristics. (And ending up in a worse place than if they hadn't bothered - location is a terrible, terrible heuristic for language.) I think the real issue here, though, is that the language button at the bottom of this page isn't interactive until several dialogues have been clicked though. Dialogues that are likely totally incomprehensible to the person trying to change language.
- Filligree 2y ago> Aren't most browsers auto-configured to request the language they were configured in? This may be true now. It was less true in 90s, where this logic originated.
- troad 2y agoI don't recall browsers behaving all that differently in the 1990s. Per W3, re MSIE 4.0, in 1997: > The Accept-Language header defaults to the current System User Locale ID but can be overridden by user.
- 2y ago
- actinium226 2y agoIt seems whenever I show someone this site, they're like "oh this is cool!" and never look at it again. I wonder if there's something about it that makes it forgettable? I don't know if I can present it any differently, maybe there's a better way of presenting it to make it more appealing.
- enriquto 2y agoMaybe explaining why would you ever want to have branches in your code? I'm a longtime git user and never felt a need for them.
- executesorder66 2y agoI'm curious, are you a solo dev, or do you work on a team where multiple people are working on different features at the same time?
- enriquto 2y agoMostly solo dev. I only use branches when working with some colleagues who are "branchists". It's not that I don't understand branches, but they always look unnecessarily cumbersome to me. The worst offenders are "feature branches"... I want my tests to try the program with/without the new feature and compare the results. Thus any feature is better implemented in the master branch, and activated using a flag. No need for a branch. If your feature is hidden in another branch, how can you test it? Does your test suite run git commands?
- actinium226 2y agoDo you push your code to a repository where you have some CI set up? Or is it just local? If it's the latter and you just run tests on the command line then yea maybe you don't need branches. On the other hand I find branches can be useful if I have a larger refactor going on and I'm not too sure what it's going to look like in the end. Then I can keep it on a branch and compare it to "last known stable commit," and if something else comes up that needs to be fixed right away I can put my larger refactor on hold and fix it, and come back to the larger refactor.
- hnuser123456 2y agoWhy do the arrows point backwards? (I get it points to the parent, but I'd rather point forward chronologically, any commit history viewers that allow this?)
- actinium226 2y agoIn theory one could amend the parent commit such that its timestamp is after its child commit. In practice I do occasionally edit one of the commits in my branch if a particular change fits better with that commit (most often typos). As such pointing to the parent is more stable than pointing to when the parent.
- hnuser123456 2y agoI see, thank you.
- neves 2y agoThis is an excellent resource. The animations really help to understand Git concepts. I successfully used it for an internal Git course.
- sakesun 2y agoI've finished all levels of the tutorial several times. Yet when in real work, I'm still often struggle with git. :(
- codingminds 2y agoSadly I'm not able to enter any command. Even after disabling the ad blocker
- rpigab 2y agoSame here, tried clicking near the prompt, nothing. Maybe I'm bad at git, can't even perform a simple commit. edit: right after typing this, I clicked the title of the MacOS styled window to the left and somehow it worked, even though clicking everywhere inside it didn't.
- __jonas 2y agoI had this issue, a page refresh helped
- Gepsens 2y agoSharing a few of my own : # https://github.com/Igosuki/dotfiles/blob/master/git/.gitconfig https://github.com/Igosuki/dotfiles/blob/master/git/.gitconf... grep = grep -Ii lalias = "!git config -l | grep alias | cut -c 7-" done = "!f() { git branch | grep "$1" | cut -c 3- | grep -v done | xargs -I{} git branch -m {} done-{}; }; f" assumed = "!git ls-files -v | grep ^h | cut -c 3-" lasttag = describe --tags --abbrev=0 lt = describe --tags --abbrev=0 dr = "!f() { git diff "$1"^.."$1"; }; f" lc = "!f() { git ll "$1"^.."$1"; }; f" diffr = "!f() { git diff "$1"^.."$1"; }; f" lb = " !f() { git branch -a | more; }; f" cp = cherry-pick st = status -s cl = clone ci = commit br = branch diff = diff --work-diff dc = diff --cached r = reset r1 = reset HEAD^ r2 = reset HEAD^^ rh = reset --hard rh1 = reset --hard HEAD^ rh2 = reset --hard HEAD^^ sl = stash list sa = stash apply ss = stash save logtree = log --graph --oneline --decorate --all lmine = "!f() { git log --branches --author=igosuki@gmail.com; }; f" purgeforever = "!f() { git filter-branch --prune-empty -d /dev/shm/scratch --index-filter "git rm --cached -f --ignore-unmatch $1" --tag-name-filter cat -- --all }" updaterefsafterpurge = "f() { git update-ref -d refs/original/refs/heads/master; git reflog expire --expire=now --all; git gc --prune=now }" ec = config --global -e up = !git pull --rebase --prune $@ && git submodule update --init --recursive cob = checkout -b cm = !git commit -m save = !git add -A && git commit -m 'SAVEPOINT' wip = !git add -u && git commit -m "WIP" undo = reset HEAD~1 --mixed amend = commit -a --amend wipe = !git add -A && git commit -qm 'WIPE SAVEPOINT' && git reset HEAD~1 --hard bclean = "!f() { git branch --merged ${1-master} | grep -v " ${1-master}$" | xargs -r git branch -d; }; f" bdone = "!f() { git checkout ${1-master} && git up && git bclean ${1-master}; }; f" pr = pull --rebase I'd advise binding things like pr, po, cp, --rebase, --continue, to keyboard shortcuts though if you are in an IDE.
- kwar13 2y agoLove this tutorial. Thanks!
- deleted 2y ago[deleted]