Git: Difference between revisions

From Bitpost wiki
No edit summary
(44 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"
! git new shared central bare repo
! New shared central bare repo
|-
|-
| On central server (aka bitpost):
| 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 bitpost.com:development/mynewthang.git
  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, then use git to add them, commit them and push them
# TO CREATE MASTER BRANCH (this is the only way):
# that will create remote-tracked master branch for you
  # 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 31: Line 31:
  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 45: Line 58:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git merging conflicts after diverging
! 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"
! gitflow
|-
| Gitflow is awesome, using it myself and everywhere I work these days (2020).
* Devs work out of develop branch
* Devs create feature branches off develop for any decent-sized work
* Once develop is stable and you are ready for a release:
git tag -a -m "#MAJOR#.#MINOR#".0 #MAJOR#.#MINOR#.0
git checkout -b release/release_#MAJOR#.#MINOR#
git push --set-upstream origin release_#MAJOR#.#MINOR#
git checkout master && git merge release/release_#MAJOR#.#MINOR# && git push
git checkout develop # and get back to it!
* Do hotfixes as needed in release branch, tagged #MAJOR#.#MINOR#.++, merged back into master and develop
|}
{| 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 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"
! Push any branch from bare to origin
|-
| Good for when you are force-pushing a branch rebase.
git push [-f] origin mybranch:mybranch
|}
{| class="mw-collapsible mw-collapsed wikitable"
! 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 53: Line 122:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git create and push a feature branch
! 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 64: 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"
! getting upstream commits into your GitLab 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.
Add the remote, call it something specific:
git remote add someauthor-upstream https://gitlab.com/someauthor/theprojectiforked
Fetch all the branches of that remote into remote-tracking branches, such as upstream/master:
git fetch someauthor-upstream
Get on the branch where you are tracking the rebase.  Typically your master branch but can be whatever:
git checkout tlsv12 # or master or next or...
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
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 GitLab. You only need to use the -f the first time after you've rebased:
git push -f origin master
ELSE if the branch you merged into is a new creation, set its upstream when you push:
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:
[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 96: Line 220:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git create new branch on server, pull to client
! Create new branch on server, pull to client
|-
|-
|  
|  
Line 115: Line 239:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git remove old branches
! 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 143: Line 274:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git pull when untracked files are in the way
! 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 150: Line 281:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git create new branch when untracked files are in the way
! Create new branch when untracked files are in the way
|-
|-
|
|
Line 168: Line 299:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git recreate repo
! Recreate repo
|-
|-
|
|
Line 179: Line 310:


{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git connect to origin after the fact
! Connect to origin after the fact
|-
|-
|
|
Line 193: Line 324:


{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git ignore local and remote changes to a file  
! 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 211: Line 342:
         -----------------------------------------
         -----------------------------------------
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git branch rebase to keep master intact
! 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)
|-
|-
| Basically you want to rebase your branch using masterSimple enough, devil in the details. You should maintain a clean master branch that can be updated at any time, and a branch for your custom work that can be rebased at any time.
| To add and push a tag to HEAD:
git tag -a 1.2.0 -m "1.2.0"
  git push origin 1.2.0


Example:
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"
        # on other: update the master branch with other users' changes
git push origin 1.2.0
 
        # on gold:
        git checkout master && git pull # should always be a ff
        git checkout US290016
        git rebase -i master # you'll possibly get merge conflicts
            git mergetool # fix it up - this will show you REMOTE head, LOCAL head, and BASE common ancestor
            git rebase --continue # AHA this will tell you you are only partially through, see the commit #comments for details
            git push --force # AHA this fails if remote does not allow it!
                # change remote config, if you get: remote: error: denying non-fast-forward refs/heads/US290016
                # then you need to go to remote and change config
                # see https://stackoverflow.com/questions/10544139/how-to-force-push-a-reset-to-remote-repository
                git config receive.denynonfastforwards false
 
        # on other: reset US290016
        # reset to the commit for the last known base ancestor (or earlier, doesn't hurt)
        git reset --hard 96ba297
        git pull --rebase # rebase should not be needed, it should be a ff, but just in case use it


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"
{| class="mw-collapsible mw-collapsed wikitable"
! git changing branches in a project with submodules
! Changing branches in a project with submodules
|-
|-
|
|
Line 247: Line 381:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git hard-reset a misbehaving submodule to parent commit version
! Hard-reset a misbehaving submodule to parent commit version
|-
|-
|
|
Line 256: Line 390:
=== CONFIGURATION ===
=== CONFIGURATION ===
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git visual difftool and mergetool setup
! 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"
! 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 301: Line 443:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git convert to a bare repo
! 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 318: Line 460:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git convert bare to a mirror of remote (github, facebook, etc)
! 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 330: Line 472:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git create merge-to command
! 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 338: Line 480:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git fix github diverge from local bare repo following README.md edit
! 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 355: Line 497:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git windows configure notepad++ editor
! Windows configure notepad++ editor
|-
|-
|  
|  
Line 361: Line 503:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git fix push behavior - ONLY PUSH CURRENT doh
! Fix push behavior - ONLY PUSH CURRENT doh
|-
|-
|
|
Line 367: Line 509:
|}
|}
{| class="mw-collapsible mw-collapsed wikitable"
{| class="mw-collapsible mw-collapsed wikitable"
! git multiple upstreams
! 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 376: Line 518:
|}
|}


=== 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


* [[Track your changes to an open-source project with git]]
Read more [https://medium.com/goodtogoat/simplified-git-flow-5dc37ba76ea8 here] and [https://gist.github.com/vxhviet/9c4a522921ad857406033c4125f343a5 here].
* [[Using git on Windows]]
* [[Portable git]]


From [http://nvie.com/posts/a-successful-git-branching-model/ 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]]

Revision as of 13:52, 22 December 2023

TASKS

New shared central bare repo
On central server (aka morosoph):
cd development(...)
git init --bare --shared mynewthang.git

On development box

cd development(...)
git clone morosoph:development/mynewthang.git
# this will create a new empty repo with no branch yet
# TO CREATE MASTER BRANCH (this is the only way):
# create files, git add, git commit, git push

Back on bitpost

git clone mynewthang.git # to create a working copy on server, if desired
create shared central repo for existing code
Create a bare repo with .git suffix
git init --bare --shared mything.git

Go to existing code and clone the repo next to it, with a temp name. Move .git into the existing code. Add code, add a .gitignore as needed, and you're all set.

cd mything/..
git clone (bare-repo-host-and-path)mything.git mything-temp
mv mything-temp/.git mything/
rm -rf mything-temp
cd mything
subl .gitignore # as needed
git add (whatever you want to track)
git commit -a -m "init repo" && git push
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 git fetch --all would do it but does not (it fetches the active branch from all origins - seriously wtf, who ever wants THAT??).

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
Set default branch of a bare repo
If you want the default branch of a bare repo to be something other than master:
git branch
 * master
   moodboom-quick-http
git symbolic-ref HEAD refs/heads/moodboom-quick-http
git branch
   master
 * moodboom-quick-http
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#
gitflow
Gitflow is awesome, using it myself and everywhere I work these days (2020).
  • Devs work out of develop branch
  • Devs create feature branches off develop for any decent-sized work
  • Once develop is stable and you are ready for a release:
git tag -a -m "#MAJOR#.#MINOR#".0 #MAJOR#.#MINOR#.0
git checkout -b release/release_#MAJOR#.#MINOR#
git push --set-upstream origin release_#MAJOR#.#MINOR#
git checkout master && git merge release/release_#MAJOR#.#MINOR# && git push
git checkout develop # and get back to it!
  • Do hotfixes as needed in release branch, tagged #MAJOR#.#MINOR#.++, merged back into master and develop
Interactive rebase with squash
Excellent to do when on your own feature branch. Illegal to do if branch is shared AT ALL!
git rebase -i myparentbranch
# work through squash and merge - gitlens may help with squash if you use vscode for EDITOR
git push -f
Push any branch from bare to origin
Good for when you are force-pushing a branch rebase.
git push [-f] origin mybranch:mybranch
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/*

Merging conflicts after diverging
Revert local changes in a file to HEAD
git checkout -- path/to/file.txt

Discard ALL LOCAL COMMITS and get the (possibly diverged) remote instead

git reset --hard origin/master
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).
git checkout -b feature/whiz-bang

# Do this ONCE: git config --global push.default current
# From then on:
git push -u

# OR, if you don't want the config, you have to be more specific:
# git push -u origin feature/whiz-bang
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!)

getting upstream commits into your GitLab 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.

Add the remote, call it something specific:

git remote add someauthor-upstream https://gitlab.com/someauthor/theprojectiforked

Fetch all the branches of that remote into remote-tracking branches, such as upstream/master:

git fetch someauthor-upstream

Get on the branch where you are tracking the rebase. Typically your master branch but can be whatever:

git checkout tlsv12 # or master or next or...

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

If you haven't done so, in GitLab, go to 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 GitLab. You only need to use the -f the first time after you've rebased:

git push -f origin master

ELSE if the branch you merged into is a new creation, set its upstream when you push:

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:

[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
getting upstream commits into your GitHub fork
From so...

Add the remote, call it something specific:

git remote add someauthor-upstream https://github.com/someauthor/theprojectiforked.git

Fetch all the branches of that remote into remote-tracking branches, such as upstream/master:

git fetch someauthor-upstream

Get on the branch where you are tracking the rebase. Typically your master branch but can be whatever:

git checkout tlsv12 # or master or next or...

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

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 GitHub. You only need to use the -f the first time after you've rebased:

git push -f origin master

ELSE if the branch you merged into is a new creation, set its upstream when you push:

git push --set-upstream origin tlsv12

Now master has the latest commits from the fork origin. You can rebase onto it, if you've been working in a branch (good):

git checkout mybranch
git rebase master
Clone a bare repo (eg github, gitlab, bb) into a bare repo
Say you want a bare repo to be shared by all your dev environments, but you need to push/pull THAT from a central bare repo, too.
git clone --bare --shared git@bitbucket.org:equityshift/es-demo.git
cd es-demo.git
git config remote.origin.fetch "+*:*"
git fetch --all

I was surprised that this was difficult at all, and may still have some lessons to learn...

Create new branch on server, pull to client
# ON CENTRAL SERVER
git checkout master # as needed; we are assuming that master is clean enough as a starting point
git checkout -b mynewbranchy

# HOWEVER, use this instead if you need a new "clean" repo and even master is dirty...
# You need the rm because git "leaves your working folder intact".
git checkout --orphan mynewbranchy
git rm -rf .

# ON CLIENT
git pull
git checkout -b mynewbranchy origin/mynewbranchy
# if files are in the way from the previously checked-out branch, you can force it...
git checkout -f -b mynewbranchy origin/mynewbranchy
Merge changes in a single file
Explanation is here.
git checkout mybranch
git checkout --patch develop my/single/file.cpp
Remove old branches
Explanation is here.

Remote:

git push origin --delete <branch>

Local:

git branch -d <branch>
git fetch <remote> --prune # Delete multiple obsolete tracking branches
Work with two local repos
Set up a remote, then fetch it as master.
cd repoToChange
git remote add otherplace ../../wherever/../gitrepo
git ls-remote otherplace # verify it looks ok, figure out which branch you like (if not master)
git fetch otherplace # gets it all
git checkout --track otherplace/master # or other branch as needed; this creates the branch and sets remote in one step, cool

Set up a remote, then fetch it into a non-master branch, and push it to the active origin.

cd repoToChange
git remote add otherplace ../../wherever/../gitrepo
git ls-remote otherplace # verify it looks ok, figure out which branch you like (if not master)
git fetch otherplace # gets it all
git checkout otherplace/master # creates it detached, good because we need to name the new branch something other than master
git checkout -b new_otherplace_branchname # creates new local branch with a good name
git push --set-upstream origin new_otherplace_branchname # takes the branch from the OLD origin and pushes it to the ACTIVE origin, cool!
Pull when untracked files are in the way
This will pull, forcing untracked files to be overwritten by newly tracked ones in the repo:
git fetch --all
git reset --hard origin/mymatchingbranch
Create new branch when untracked files are in the way
  git checkout -b bj143 origin/bj143
     git : error: The following untracked working tree files would be overwritten by checkout:
     (etc)
  
  TOTAL PURGE FIX (too much):
     git clean  -d  -fn ""
        -d dirs too
        -f force, required
        -x include ignored files (don't use this)
        -n dry run
  
  BEST FIX (just overwrite what is in the way):
     git checkout -f -b bj143 origin/bj143
Recreate repo
git clone ssh://m@thedigitalmachine.com/home/m/development/thedigitalage/ampache-with-hangthedj-module
cd ampache-with-hangthedj-module
git checkout -b daily_grind origin/daily_grind

If you already have the daily_grind branches and just need to connect them:

git branch -u origin/daily_grind daily_grind
Connect to origin after the fact
git remote add origin ssh:// m@bitpost.com/home/m/development/logs
git fetch
    From ssh:// bitpost/home/m/development/logs
     * [new branch]      daily_grind -> origin/daily_grind
     * [new branch]      master     -> origin/master
git branch -u origin/daily_grind daily_grind
git checkout master
git branch -u origin/master master
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 my SO answer.
       PREVENT COMMIT OF CHANGES TO A LOCAL FILE
       -----------------------------------------
       git update-index --skip-worktree apps/views/_partials/jsIncludes.scala.html

       RESET TO GET CHANGES AGAIN
       --------------------------
       git update-index --no-skip-worktree apps/views/_partials/jsIncludes.scala.html

       LIST SKIPPED FILES
       ------------------
       git ls-files -v . | grep ^S
       S app/views/_partials/jsIncludes.scala.html
       -----------------------------------------
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
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 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
Changing branches in a project with submodules
# always reset the @*$ submodules to proper commits
git checkout develop && git submodule update
Hard-reset a misbehaving submodule to parent commit version
git submodule deinit -f .
git submodule update --init

CONFIGURATION

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]"
Visual difftool and mergetool setup
Meld is purdy, let's kick its tires. Hope it actually works...
git config --global diff.tool meld
git config --global merge.tool meld
git config --global --add difftool.prompt false

I used to set up kdiff3 manually, like this... (gross)

  • LINUX - put this in ~/.gitconfig
[diff]
    tool = kdiff3

[merge]
    tool = kdiff3
  • WINDOZE
[difftool "kdiff3"]
    path = C:/Progra~1/KDiff3/kdiff3.exe
    trustExitCode = false
[difftool]
    prompt = false
[diff]
    tool = kdiff3
[mergetool "kdiff3"]
    path = C:/Progra~1/KDiff3/kdiff3.exe
    trustExitCode = false
[mergetool]
    keepBackup = false
[merge]
    tool = kdiff3
  • LINUX Before - What a ridiculous pita... copy this into .git/config...
[difftool "kdiff3"]
    path = /usr/bin/kdiff3
    trustExitCode = false
[difftool]
    prompt = false
[diff]
    tool = kdiff3
[mergetool "kdiff3"]
    path = /usr/bin/kdiff3
    trustExitCode = false
[mergetool]
    keepBackup = false
[merge]
    tool = kdiff3
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:
cd repo

Now you can copy-paste this...

mv .git .. && rm -fr *
mv ../.git .
mv .git/* .
rmdir .git
git config --bool core.bare true
cd ..

Don't copy/paste these, you need to change repo name...

mv repo repo.git # rename it for clarity
git clone repo.git # (optional, if you want a live repo on the server where you have the bare repo)

Then you can clean up old branches like daily and daily_grind, as needed.

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.

If you did NOT specify --mirror when you first created the bare repo, you can convert to a mirror by adding these last two lines to config, underneath url:

[remote "origin"]
   url = git@github.com:facebook/proxygen.git
   fetch = +refs/*:refs/*
   mirror = true

Now you can fetch from the bare repo:

git fetch
Create merge-to command
Add this handy alias command to all git repos' .config file...
[alias]
    merge-to = "!gitmergeto() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $1 && git merge $tmp_branch && git checkout $tmp_branch; unset tmp_branch; }; gitmergeto"

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.

Fixing it is a PAIN in the ASS, you have to create a new local repo and pull github into that, pull in from your other local repo, push to github, pull to your bare...

git clone git@github.com:moodboom/quick-http.git quick-http-with-readme-conflict
git remote add local ../quick-http
git fetch local
git merge local/master # merge in changes, likely trivial
git push # pushes back to github
cd ..
mv quick-http.git quick-http.git__gone-out-of-sync-fu-github-readme-editor
git clone git@github.com:moodboom/quick-http.git --bare
cp quick-http.git__gone-out-of-sync-fu-github-readme-editor/config quick-http.git/

And that MIGHT get you on your way... but I would no longer trust ANY of your local repos... This is a serious pita.

Windows configure notepad++ editor
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
Fix push behavior - ONLY PUSH CURRENT doh
git config --global push.default current
Multiple upstreams
Use this to cause AUTOMATIC push/pull to a second origin:
git remote set-url origin --push --add user1@repo1
git remote set-url origin --push --add user2@repo2
git remote -v show

Leave out --push if you want to pull as well... but I'd be careful, it's better if code is changed in one client with this config, and then pushed to the multiple origins from there. Otherwise, things are GOING TO GET SYNCY-STINKY.

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 here and 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 here... 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