Git: Difference between revisions
No edit summary |
No edit summary |
||
(37 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=== TASKS === | === TASKS === | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! New shared central bare repo | ||
|- | |- | ||
| On central server (aka | | On central server (aka morosoph): | ||
cd development(...) | cd development(...) | ||
git init --bare --shared mynewthang.git | git init --bare --shared mynewthang.git | ||
On development box | On development box | ||
cd development(...) | cd development(...) | ||
git clone | git clone morosoph:development/mynewthang.git | ||
# this will create a new empty repo with no branch yet | # this will create a new empty repo with no branch yet | ||
# create files, | # TO CREATE MASTER BRANCH (this is the only way): | ||
# create files, git add, git commit, git push | |||
Back on bitpost | Back on bitpost | ||
git clone mynewthang.git # to create a working copy on server, if desired | git clone mynewthang.git # to create a working copy on server, if desired | ||
Line 28: | Line 28: | ||
rm -rf mything-temp | rm -rf mything-temp | ||
cd mything | cd mything | ||
code .gitignore # as needed | |||
git add (whatever you want to track) | git add (whatever you want to track) | ||
git commit -a -m "init repo" && git push | git commit -a -m "init repo" && git push | ||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Fetch a branch from remote without checking it out | |||
|- | |||
| Good for when you are rebasing a feature branch. | |||
git fetch origin develop:develop | |||
You would think <code>git fetch --all</code> would do it but does not (it fetches the active branch from ''all origins'' - seriously wtf, who ever wants THAT??). | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Completely reset an out-of-sync branch to 100% match the remote | |||
|- | |||
| Sometimes some other idiot rebased the remote branch on you. Make sure you are on the right branch, locally. Then to completely force-reset it: | |||
git reset --hard origin/thebranchname | |||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
Line 43: | Line 56: | ||
master | master | ||
* moodboom-quick-http | * moodboom-quick-http | ||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Find a file across branches | |||
|- | |||
| It's clunky, two steps, and you have to glob out the whole fucking name: | |||
# get the commits that involved the filename | |||
git log --all -- '**/*namebits*' | |||
# even better, get the filenames too, and see if it was added or removed: | |||
git log --all --stat -- '**/*namebits*' | |||
# now find the branch with one of those commits: | |||
git branch -a --contains #commithash# | |||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
Line 59: | Line 83: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Interactive rebase with squash | ||
|- | |- | ||
| | | Excellent to do when on your own feature branch. Illegal to do if branch is shared AT ALL! | ||
git | git rebase -i myparentbranch | ||
# work through squash and merge - gitlens may help with squash if you use vscode for EDITOR | |||
git push -f | |||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
Line 72: | Line 97: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! git | ! Fetch from one origin (eg gitlab) and push to another | ||
|- | |||
| My GitLab is usually a mirror, and therefore a push target. But if you edit a file in GitLab, you may need to pull it from remote "gitlab" and push it to remote "sc", like this: | |||
git fetch gitlab develop:develop | |||
git push sc | |||
This assumes you have something like the following in your config: | |||
[remote "sc"] | |||
url = git@shitcutter.com:the-digital-age/rad-scripts.git | |||
fetch = +refs/heads/*:refs/remotes/origin/* | |||
[remote "github.com"] | |||
url = git@github.com:moodboom/rad-scripts.git | |||
fetch = +refs/heads/*:refs/remotes/origin/* | |||
[remote "gitlab.com"] | |||
url = git@gitlab.com:moodboom/rad-scripts.git | |||
fetch = +refs/heads/*:refs/remotes/origin/* | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Merging conflicts after diverging | |||
|- | |- | ||
| Revert local changes in a file to HEAD | | Revert local changes in a file to HEAD | ||
Line 80: | Line 122: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Create and push a feature branch | ||
|- | |- | ||
| This will move recent commits AND uncommitted changes into a new branch (but you probably want to finish by cleaning out commits from starting branch, and repulling after you merge the feature). | | This will move recent commits AND uncommitted changes into a new branch (but you probably want to finish by cleaning out commits from starting branch, and repulling after you merge the feature). | ||
Line 91: | Line 133: | ||
# OR, if you don't want the config, you have to be more specific: | # OR, if you don't want the config, you have to be more specific: | ||
# git push -u origin feature/whiz-bang | # git push -u origin feature/whiz-bang | ||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! getting upstream commits into your GitLab GITFLOW fork | |||
|- | |||
| NOTE: This doesn't work from a bitpost bare repo, so you need to make a new direct clone of your GitLab fork, first, if you don't have one yet. | |||
This is very easy if you have left the master branch alone for the parent's commits, and keep your add-on commits in a release-x.x branch, as we have for SWS and SWSS. | |||
cdl | |||
# Clone local repo directly from GitLab (already done on cobra) | |||
git clone git@gitlab.com:moodboom/Simple-Web-Server.git SWS-gitlab-moodboom | |||
cd SWS-gitlab-moodboom | |||
# make sure master is checked out | |||
git branch | |||
# add parent as remote | |||
git remote add ole-upstream git@gitlab.com:eidheim/Simple-Web-Server.git | |||
git fetch ole-upstream | |||
git rebase ole-upstream/master | |||
git push -f origin master | |||
You can now delete the fresh clone, it has done its job. Or leave it for ease-of-use for next rebase. | |||
Now update your bare repo on bitpost, to keep things in sync. | |||
git fetch origin master:master -f | |||
Next, go to dev repo, pull master. Check out release, create a new release from that, and rebase master. (or just create a new release branch off master if that's what you want) It is the gitflow way! | |||
Push your new branch to bare, then push bare to GitLab via something like: | |||
git push --set-upstream origin release/abt-0.0.3 | |||
To complete SW(S)S rebase, update mh-install-sws to use the new branch. Then run it on all your dev boxes, whoop. (Then, code up any fixes, sigh... and push em.. .sigh... and get on with it!) | |||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
Line 104: | Line 176: | ||
Rewrite your branch so that any commits of yours that aren't already in upstream are replayed on top of that other branch (if you do a straight merge instead of rebase you'll screw up the upstream!): | Rewrite your branch so that any commits of yours that aren't already in upstream are replayed on top of that other branch (if you do a straight merge instead of rebase you'll screw up the upstream!): | ||
git rebase someauthor-upstream/master | git rebase someauthor-upstream/master | ||
If you haven't done so, in GitLab, go to [https://gitlab.com/moodboom/Simple-WebSocket-Server/-/settings/repository#js-protected-branches-settings the "Protected Branch" settings] and remove protection from master - it's just a fact that you're going to need to force-push to master. | |||
IF the branch that was the target of the rebase existed, force the push in order to push it to your own forked repository on | |||
IF the branch that was the target of the rebase existed, force the push in order to push it to your own forked repository on GitLab. You only need to use the -f the first time after you've rebased: | |||
git push -f origin master | git push -f origin master | ||
ELSE if the branch you merged into is a new creation, set its upstream when you push: | ELSE if the branch you merged into is a new creation, set its upstream when you push: | ||
git push --set-upstream origin tlsv12 | git push --set-upstream origin tlsv12 | ||
You will want to force-fetch to update the bare repo you may have on bitpost, DO THIS NOW or you will screw things up badly later: | |||
git | [Simple-WebSocket-Server.git] git fetch origin master:master -f | ||
You should also force-update ALL your dev repos, NOW, for the same reason: | |||
git reset --hard HEAD^^^^^^ && git pull | |||
NOTE that you may need to remove a remote-tracking branch if you don't need it any more. It's stupidly painful to get right, eg: | |||
[Simple-WebSocket-Server.git] git branch -rd eidheim/Simple-WebSocket-Server/master | |||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
Line 144: | Line 220: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Create new branch on server, pull to client | ||
|- | |- | ||
| | | | ||
Line 163: | Line 239: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! git | ! Merge changes in a single file | ||
|- | |||
| Explanation is [https://stackoverflow.com/a/11593308/717274 here]. | |||
git checkout mybranch | |||
git checkout --patch develop my/single/file.cpp | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Remove old branches | |||
|- | |- | ||
| Explanation is [https://stackoverflow.com/a/23961231/717274 here]. | | Explanation is [https://stackoverflow.com/a/23961231/717274 here]. | ||
Line 191: | Line 274: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Pull when untracked files are in the way | ||
|- | |- | ||
| This will pull, forcing untracked files to be overwritten by newly tracked ones in the repo: | | This will pull, forcing untracked files to be overwritten by newly tracked ones in the repo: | ||
Line 198: | Line 281: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Create new branch when untracked files are in the way | ||
|- | |- | ||
| | | | ||
Line 216: | Line 299: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Recreate repo | ||
|- | |- | ||
| | | | ||
Line 227: | Line 310: | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Connect to origin after the fact | ||
|- | |- | ||
| | | | ||
Line 241: | Line 324: | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Ignore local and remote changes to a file | ||
|- | |- | ||
| This is helpful for conf files that need local-specific modifications that shouldn't be pushed. You have to toggle it on/off as needed to get updates! See [http://stackoverflow.com/questions/4348590/how-can-i-make-git-ignore-future-revisions-to-a-file/39776107#39776107 my SO answer]. | | This is helpful for conf files that need local-specific modifications that shouldn't be pushed. You have to toggle it on/off as needed to get updates! See [http://stackoverflow.com/questions/4348590/how-can-i-make-git-ignore-future-revisions-to-a-file/39776107#39776107 my SO answer]. | ||
Line 260: | Line 343: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! git | ! Replace name and email of last commit | ||
|- | |||
| Reset the name and email of the last commit, when you realize you forgot to set them first: | |||
git commit --amend --author="First Last <email>" --no-edit | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Simple tagging (when not using git-sync) | |||
|- | |||
| To add and push a tag to HEAD: | |||
git tag -a 1.2.0 -m "1.2.0" | |||
git push origin 1.2.0 | |||
To add and push a tag attached to a commit with current time as timestamp: | |||
git tag -a 1.2.0 1bc92e2f -m "1.2.0" | |||
git push origin 1.2.0 | |||
To tag a commit while ensuring the timestamp matches is slightly more complicated (but not bad). More details [https://stackoverflow.com/a/21759466/717274 here]: | |||
# Set the HEAD to the old commit that we want to tag | |||
git checkout 9fceb02 | |||
# temporarily set the date to the date of the HEAD commit, and add the tag | |||
GIT_COMMITTER_DATE="$(git show --format=%aD | head -1)" \ | |||
git tag -a v1.2 -m"v1.2" | |||
# push to origin | |||
git push origin --tags | |||
# set HEAD back to whatever you want it to be | |||
git checkout master | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Remove a tag | |||
|- | |||
| This has a long clumsy history, but these instructions should be good into the future. | |||
To remove remote tag(s): | |||
git push --delete origin tag YOUR_TAG_NAME TAG_NAME_2 ... | |||
Remove tag(s) locally: | |||
git tag -d YOUR_TAG_NAME TAG_NAME_2 ... | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Changing branches in a project with submodules | |||
|- | |- | ||
| | | | ||
Line 267: | Line 391: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Hard-reset a misbehaving submodule to parent commit version | ||
|- | |- | ||
| | | | ||
Line 276: | Line 400: | ||
=== CONFIGURATION === | === CONFIGURATION === | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! git | ! Set name and email | ||
|- | |||
| Globally on one machine (note the machine name at end of user name): | |||
git config --global user.email m@thedigitalmachine.com; git config user.name "Michael Behrns-Miller [cast]" | |||
Override for a repository: | |||
git config user.email mbm@equityshift.io; git config user.name "MBM [cast]" | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Set default root to main not master | |||
|- | |||
| I love the idea of a kinder root name, suck it up alt-right down-punchers, lol. | |||
Configure it to always happen: | |||
git config --global init.defaultBranch main | |||
Fix it for a newly initialized repository: | |||
git branch -m main | |||
|} | |||
{| class="mw-collapsible mw-collapsed wikitable" | |||
! Visual difftool and mergetool setup | |||
|- | |- | ||
| Meld is purdy, let's kick its tires. Hope it actually works... | | Meld is purdy, let's kick its tires. Hope it actually works... | ||
Line 321: | Line 462: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Convert to a bare repo | ||
|- | |- | ||
| Start with a normal git repo via [git init]; add your files, get it all set up. Then do this: | | Start with a normal git repo via [git init]; add your files, get it all set up. Then do this: | ||
Line 338: | Line 479: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Convert bare to a mirror of remote (github, facebook, etc) | ||
|- | |- | ||
| You need a bare mirror repo if you want to take someone else's repo and create your own bare to work from. | | You need a bare mirror repo if you want to take someone else's repo and create your own bare to work from. | ||
Line 350: | Line 491: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Create merge-to command | ||
|- | |- | ||
| Add this handy alias command to all git repos' .config file... | | Add this handy alias command to all git repos' .config file... | ||
Line 358: | Line 499: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Fix github diverge from local bare repo following README.md edit | ||
|- | |- | ||
| Yes editing the README.md file on github will FUCK UP your downstream bare repo if you meanwhile push to it before pulling. | | Yes editing the README.md file on github will FUCK UP your downstream bare repo if you meanwhile push to it before pulling. | ||
Line 375: | Line 516: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Windows configure notepad++ editor | ||
|- | |- | ||
| | | | ||
Line 381: | Line 522: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Fix push behavior - ONLY PUSH CURRENT doh | ||
|- | |- | ||
| | | | ||
Line 387: | Line 528: | ||
|} | |} | ||
{| class="mw-collapsible mw-collapsed wikitable" | {| class="mw-collapsible mw-collapsed wikitable" | ||
! | ! Multiple upstreams | ||
|- | |- | ||
| Use this to cause AUTOMATIC push/pull to a second origin: | | Use this to cause AUTOMATIC push/pull to a second origin: | ||
Line 396: | Line 537: | ||
|} | |} | ||
=== Git branching strategies === | |||
==== Simplified Gitflow ==== | |||
This is awesome, tight, and well-capable of handling any app with a single primary release (like a website). | |||
RELEASE TAG | |||
o----------------------------o-----------------o------------o------> MASTER | |||
\ / \ \----------/ HOTFIX | |||
\ / \ \ | |||
\----------------------/ \--------------------o-----o------> DEVELOP | |||
\ / | |||
\----------------/ FEATURE | |||
Read more [https://medium.com/goodtogoat/simplified-git-flow-5dc37ba76ea8 here] and [https://gist.github.com/vxhviet/9c4a522921ad857406033c4125f343a5 here]. | |||
==== Gitflow ==== | |||
I was a die-hard believer in gitflow for a while. It's very capable. Too capable. You MIGHT need it if you are supporting multiple versions in production... but in all my cases, it is overkill, compared to Simplified Gitflow. The classic diagram, originally from [http://nvie.com/posts/a-successful-git-branching-model/ here]... | |||
[[File:Git for nice release planning.png]] | [[File:Git for nice release planning.png]] | ||
=== LFS === | |||
Just don't use it. It's shite. If you get stuck working with a repo that requires it, and you are using ssh on linux which just won't work with LFS... you will probably end up with a damaged repo. Fix it with this: | |||
git read-tree HEAD && GIT_LFS_SKIP_SMUDGE=1 git checkout -f HEAD | |||
After that, use '''GIT_LFS_SKIP_SMUDGE=1''' during any git command: | |||
GIT_LFS_SKIP_SMUDGE=1 git pull # etc. | |||
=== My git pages (older) === | |||
[[Track your changes to an open-source project with git]] | |||
[[Using git on Windows]] | |||
[[Portable git]] |
Latest revision as of 16:15, 30 November 2024
TASKS
ExpandNew shared central bare repo |
---|
Expandcreate shared central repo for existing code |
---|
ExpandFetch a branch from remote without checking it out |
---|
ExpandCompletely reset an out-of-sync branch to 100% match the remote |
---|
ExpandSet default branch of a bare repo |
---|
ExpandFind a file across branches |
---|
Expandgitflow |
---|
ExpandInteractive rebase with squash |
---|
ExpandPush any branch from bare to origin |
---|
ExpandFetch from one origin (eg gitlab) and push to another |
---|
ExpandMerging conflicts after diverging |
---|
ExpandCreate and push a feature branch |
---|
Expandgetting upstream commits into your GitLab GITFLOW fork |
---|
Expandgetting upstream commits into your GitLab fork |
---|
Expandgetting upstream commits into your GitHub fork |
---|
ExpandClone a bare repo (eg github, gitlab, bb) into a bare repo |
---|
ExpandCreate new branch on server, pull to client |
---|
ExpandMerge changes in a single file |
---|
ExpandRemove old branches |
---|
ExpandWork with two local repos |
---|
ExpandPull when untracked files are in the way |
---|
ExpandCreate new branch when untracked files are in the way |
---|
ExpandRecreate repo |
---|
ExpandConnect to origin after the fact |
---|
ExpandIgnore local and remote changes to a file |
---|
ExpandReplace name and email of last commit |
---|
ExpandSimple tagging (when not using git-sync) |
---|
ExpandRemove a tag |
---|
ExpandChanging branches in a project with submodules |
---|
ExpandHard-reset a misbehaving submodule to parent commit version |
---|
CONFIGURATION
ExpandSet name and email |
---|
ExpandSet default root to main not master |
---|
ExpandVisual difftool and mergetool setup |
---|
ExpandConvert to a bare repo |
---|
ExpandConvert bare to a mirror of remote (github, facebook, etc) |
---|
ExpandCreate merge-to command |
---|
ExpandFix github diverge from local bare repo following README.md edit |
---|
ExpandWindows configure notepad++ editor |
---|
ExpandFix push behavior - ONLY PUSH CURRENT doh |
---|
ExpandMultiple upstreams |
---|
Git branching strategies
Simplified Gitflow
This is awesome, tight, and well-capable of handling any app with a single primary release (like a website).
RELEASE TAG o----------------------------o-----------------o------------o------> MASTER \ / \ \----------/ HOTFIX \ / \ \ \----------------------/ \--------------------o-----o------> DEVELOP \ / \----------------/ FEATURE
Gitflow
I was a die-hard believer in gitflow for a while. It's very capable. Too capable. You MIGHT need it if you are supporting multiple versions in production... but in all my cases, it is overkill, compared to Simplified Gitflow. The classic diagram, originally from here...
LFS
Just don't use it. It's shite. If you get stuck working with a repo that requires it, and you are using ssh on linux which just won't work with LFS... you will probably end up with a damaged repo. Fix it with this:
git read-tree HEAD && GIT_LFS_SKIP_SMUDGE=1 git checkout -f HEAD
After that, use GIT_LFS_SKIP_SMUDGE=1 during any git command:
GIT_LFS_SKIP_SMUDGE=1 git pull # etc.