Git blows at sharing file permissions! Git blows at being able to mark or tag a subset of files. No custom attribute capability. Tagging tags an entire branch revision. "Staged" means changes "added" but not committed, 1st column of "status -s". REMEMBER!: git restore # like svn revert git show [rev]:./path # like svn cat from working dir. N.b colon + some path both required! ??? "staged" and "cached" seem to mean same thing? GOTCHA: some commands, definitely 'diff' and 'restore' work on unstaged by default. NO support for RCS keywords. .git directory only at the top level. They have man pages with man page names of the form git-. NORMAL BRANCH CREATION done from work area in existing parent branch. This doesn't seem to work now! git branch git switch # new Git command git push -u origin New method: git checkout -b git push --set-upstream origin git branch --show-current git branch # Only informative, local git branch -r # Only informative, remote Very little and insufficient support for copying artifacts (and tracking that). I have read several times how smart Git is about automatically recognizing file moves and copies, but I have seen very little evidence of that. Seems that the only tracking you get is if you run "git mv..." as shown by a "git status..." run after. Even with this though, I have yet to see how to see that transaction detail historically in "git log" (after it's committed). Can't move directories. Create destination directories then "git mv" files. Remove directories with: git rm -r dirpath Config Settings JUST DO ONCE ON THE COMPUTER, SINCE STORED TO $HOME/.gitconfig: git config --global user.name "Blaine Simpson" git config --global user.email blaine.simpson@admc.com git config --global push.default simple git "config " are project-specific. Add the "--global" switch to add to $HOME/.gitconfig instead of to "/.git/config". To start off, you must either "git init" or "git clone". HEAD virtual tag is just like svn. Unfortunately can't pick and choose and change elements of the tag because it's a single point-in-time across the entire repository. It's last commit to CURRENT branch == TIP of current branch (I believe COMMITS! not ADDs). Revisions are just like Subversion revisions in that a single revision corresponds to a single commit so it may span multiple artifacts, as shown by "git log --summary". N.b.! --summary only shows files added or removed-- NOT CHANGED! Use --stat to see each file changed. Revision ranges: X..Y = what is between X and Y, including nether X nor Y. Consequently "X..X" will always be empty. Suffix ^ means 1-previous. Therefore range HEAD^..HEAD means last commit. CONCEPTS. These things are VERY DIFFERENT from CVS and Subversion. Local branch names (branch and checkout commands) Remote repository aliases (remote commands) Remote branch aliases (merge and log commands): RMTALIAS/RMTBRANCHALIAS MAJOR DIFFERENCES Does not support simple tracking of empty directories. You must add a .gitignore file. No partial checkouts. It's the entire project or nothing. Submodule support is very complicated. Revert is done completely differently and is complicated. If you want to revert anything in any way, then see the suggestions shown by "git status". (but search for "revert" in this file for a couple examples). "git add" does not just set a state that the contents of the file will be committed when 'commit' (with no file spac) is run; but actually snapshots the exact contents that will be committed (with no file spec). I.e. echo 1 > file; git add file; echo 2>> file; commit Would commit contents "1". N.b.! It also commits file REMOVALS (changes are added, not 'additions'). N.b.! Committing with file spec ignores the snapshotted comments and will commit the current contents. Consequently "commit" is very different from "commit .". BUT "git commit -a" does an add+commit of all modified + previously added files, similar to a plain "svn commit". N.b. you must still add files (but not "git rm"!). "commit" only commits to your local repos. For sharing without direct push privs, you need to have your changes "pull"ed or "push"ed. I think no ability at all to list anything about remote repositories without a work area. Once you have a work area, you can list remote branches, references, directory listings, file contents. There is no 'git mkdir'. You make new dirs with OS then add them. PUSH Need local access, ssh, or http w/ webdav. GOTCHA! When using remote branches in any way, when you create remote tracking branches, ALWAYS GIVE THE TRACKING BRANCH THE SAME NAME AS THE REMOTE BRANCH. If you do not, some things will not work as you would expect, and it's likely that you will accidentally create new branches. HOSTING Usually want to use a bare repository. If remote, clone with --bare before uploading. It's also troublesome to push to a non-bare repos. Convention is to name the .git bare directory like .git, and that directory will by default clone to . Branches are not upstream (in origin) until "git remote show origin" shows 'em. To get a new branch definition upstream, need to push the branch (would this be possible while the branch is empty?... probably). Clones are always kept aware and updated about upstream branches (incl. additions) by virtue of default "git fetch" behavior. Just "checkout" to the upstream branch and it will be automatically added. No problem creating the bare repos empty and cloning it. You'll get a warning when cloning it (to work repos). Just add to the clone and push when done. Check output of "remote -v". "git push -u..." By just running (even without -u), some defaults get saved, maybe more for origin. (Can see some of these defaults by "branch -a"). But, explicitly: git push [:REMOTEBRANCH] (where REMOTEBRANCH defaults to same name as local branch). !! CURRENT BRANCH IS IRRELEVANT. Can safely push all branches from current branch, and default is sometimes 'master' (Won't get any warning since you're pushing to a bare repository). Definitely safe to just 'git push' if there is only one branch both in your work area and the origin. As noted elsewhere, need extra work to allow for pushing to, but for reading... Either git-daemon w/ git-daemon-export-ok marker files peer to .git dirs. READ-ONLY (no auth) http daemon with special per-repos commands. (READ ONLY unless special services) ssh R/W Gitify existing code: cd root/dir git init # makes .git dir git add . # writes snapshot to staging area "index". # . means parent and descendant dirs and files, not peers. # (Unlike "bzr" you must specify some target after "git add". git commit # commits index to repository. ALL indexed files/dirs from prj! GOTCHA git branch NEWBRANCH OLDBRANCH # DOCUMENTED INCORRECTLY? Make sure to "add" new files, because "commit -a" will not pick them up othewise. BRANCHES: git branch [-t] NEWBRANCH [STARTPOINT] git checkout It IS SAFE to have both untracked and tracked but uncommitted changes and to switch from branch to branch. Git will warn/refuse to switch if the changes represent incompatibilities which would hose things if committed. git checkout -b X == git branch X && git checkout X The first "master" branch gets created when you make your first commit. "git branch -a" shows all branches, local and remote. Beware of "-f" switch to "git checkout...". It will zap added mods! git status -s (skip -s to get tips) Lists 1st col is staged changes; 2nd col is unstaged changes. Untracked files (not "added") new files (added) (Does add log and classes directories and files by dflt) Changed but not updated Changes to be committed (must "add" them!) git rm -f file... # to completely wipe NEW "add"s # (whether ever committed before or not) git rm --cached file... # to tell index that file's removed, but leave it there I think new feature: Revert: [git checkout -- file... # to undo unadded changes ] git restore file... # to revert unstaged changes git restore --staged file... # just un-stages (allowing unstaged restore) Generally, to undo something before committing, "git status" will tell you how to revert. git reset HEAD file... # to un-add NEW "add"s git reset HEAD file...; git checkout -- file... # to un-add/revert # "rm"s or added MODs git reset --hard HEAD~1 # Undo last commit (before pushing) Wipe branches: branch -d BRANCHNAME # will only succeed if branch work all merged elsewhere branch -D BRANCHNAME # aborts the branch work DIFFS git diff [rev path] # non-staged mods git diff --cached # staged mods git diff HEAD # all mods git diff ^ # previous-to vs. COMMIT COMMENTS: <50 chars on first line + blank line + details <=72 chars. (Convention) GRAPHICAL: gitk I don't know how to use it. CHECKING OUT from a remote repository git clone source [dest] # EXCEPT that you get entire repository w/ history # dest directory will be created. Does not otherwise effect $PWD. Subsequence "git pull"s or "fetch"es will re-pull from the original source. # The clone will create a local branch as clone of the CURRENT (or other # as specified with -b) branch of the source repos. Can thereafter create # any other local branch clones by checking out. "git fetch [alias]" only updates local "knowledge" of remote branch(es). Plain "git fetch" definitely updates local knowledge of ALL tracked remote branches. The output from the command shows all effected branches, remote and local. The "git fetch" operation displays the remote name and the alias/branch_alias for each remote branch with a mod. GOTCHA! It is tricky because sometimes it only fetches what tracks to the current branch. Therefore, always checkout to desired target branch and then fetch to it. "git merge [--no-commit] ALIAS/RMTBR # this called fast-forwarding if other is an ancestor !!! GOTCHA!: ALWAYS SUPPLY RMTBR unless there is only one remote branch or you really know what RMTBR will be used! Remember that merge will auto-commit if it pulls in the wrong thing! OR "git merge [--no-commit] LOCALBRANCH" GOTCHA: (For remote merging, should pull from remote branch corresponding to your current branch by default, but seems it often does not. If cloned, then you can specify just the rmt alias). Specify full RMTALIAS/RMTBRANCH. (I think unnecessary). THESE PARAMS SEEM TO ALWAYS WORK: "fetch" or "fetch ALIAS" merge ALIAS/RMTBRANCH [into current branch] "git [--no-commit] pull" = "git fetch" + "git [--no-commit] merge". Except that other non-active branches are merged and committed with fetch. MERGE DOES A COMMIT by default! excepting conflicts. To allow for checking, do: git merge --nocommit LOCALBRANCH git status -s will show the ready updates, which are staged to see the actual changes, you must unstage: git restore --staged file.txt At this point you can presumably 'git diff file.txt', 'git add file.txt' Post-merge conflict resolution. After done, just "git add" the mod (and commit with no path arg). fetch somehow adds (or updates?) a virtual revision tag FETCH_HEAD. Just re-ADD the resource after resolving the conflict. Looks like there are "merge -X ours|there" like svn's resolution options. GOTCHA: When pushing a merge, DO NOT SPECIFY FILES. Remote repository branch. It's a local tracking of a branch in a remote repository, since Git doesn't let you work with branches of remote repositories directly. THINGS GET VERY CONFUSING if you do not use matching names for local and remote branches. Avoid that! git checkout -b REMOTE_BRANCH origin/branch # Primary/initialized one e.g.: git checkout -b b1 origin/b1 # checks out remote branch b1 git remote add NEW_ALIAS remote_repos_ur_or_path Can then fetch/pull/merge with REMOTE_BRANCH. git remote # lists remote repositories, but nothing about branches git remote show remote/repos # lists available branches and default push/pulls (does not show default merge sources) git show # gets details of "git log"; or display/cat resources, samples below ^x means not-in-x for "git log": git log --oneline branch1 ^branch2 Need --follow switch to follow history across artifact renames. git log --summary -2 shows files changed with last 2 commits THIS NOW WORKING FOR UNKNOWN REASON: git log sha1..sha2 Following just like "svn cat -r REVISION file/path" or "svn ls -r REVISION dir/path" but requires a working directory (must use 'git archive' if no working dir). # (relative file/paths must start with ./ otherwise start with / and relative to the workspace/repository root dir) git show [REVISION]:a/path (Revision like HEAD or HEAD^ or SHASTRING) git show [REVISION]:./path Must specify some "path", not just a file name. CONTRIBUTION MODES CVS MODE. Individual developers "git push" to central repository. Better if the central repository is a bare repository. INTEGRATOR MODE. Developers email patches to Integrator w/ "git send-email --to=a@b.com revabc...". Integrator applies email patches with "git am". (how does "am" compare to "apply"?). There doesn't need to be an integrator person since "git am" can be run by a mail handler. To do same thing with files directly, use "format-patch" in place of "send-email --to=a@b.com". FROM http://git-scm.com/course/svn.html Repositories normally located with a "working copy". Excl: bare repository. Branches and tags do not correspond to directories with the repos like in svn. svn trunk ~ git master. Revision id's are not decimal numbers but SHA1 ids. Only need to enter enough to make specify the revision uniquely. (Sometimes) calles SHAs. Revision keywords: HEAD, HEAD^ (parent-of), HEAD^^ == HEAD~2 JUST DO ONCE ON THE COMPUTER, SINCE STORED TO $HOME/.gitconfig: Colorize output with: git config --global color.diff auto git config --global color.status auto git config --global color.branch auto IGNORES (more convenient than svn:ignore) Generally, start by copying my $HOME/templates/gitignore to .gitignore in the root directory of your new project. Add to that. File .gitignore just like .cvsignore, except applies to subdirectories too. They all merge together just like you would want. Paths beginning with / are relative to the dir containing that ignore file. Start pattern with / to prevent applying to subdirs. Can put a file under proj/.git to indicate for your work area only. Global FOR YOU, add [core]...excludesfile to $HOME/.gitconfig. TIP: Great thing is that you can override ignores. Use ignores to set general rules, then you can still add resources with ignored paths by just using "git add -f filepath". There are commands to repair or erase previous commits (perhaps just the last). Tags for entire repository are much more intuitive than CVS or Subversion; but you can't tag invidual files, only the entire repository (where the tag just references a commit). "git tag" lists all available tags. "git [push] -d LABEL # push for remote tag "git tag -a -m 'The comment' LABEL [SHA]" and "git branch...". "git push --tags [origin master]" # is local until you do this! "git show LABEL" displays the annotation comment (plus much else). Switch branches or revisions with "git checkout ". like svn switch "git cherry-pick" is a fine-grained merge. mv's are just guessed, not really tracked atomically FREE+OPEN SOURCE HOSTING SERVICES github.com The standard and probably safest for longevity. bettercodes.org also has lots of free project services codaset.com Ditto only 1 proj free Gitorious (in Ruby) Used by OpenSUSE. Web site slow! Uses Markdown. I don't know if any Graphical editor. berlios the chaw? projectlocker # cipherhive Git + Webdav NOT AVAILABLE LOCAL BRANCHES Merges must still specify the parent branch (perhaps only if there is another ancestor branch?) HOW TO WORK WITH MULTIPLE REMOTE BRANCHES FROM A SHARED REPOS clone. This will create a local branch tracking active origin branch (w/ local name matching remote name). For each branch that you will work on, create tracking branch of same name, like git checkout -b X origin/X or git branch X origin/X To update: git fetch # from any branch. Does not matter. Fetches all upates. By default "git push rmtAlias" will push ALL changes linked to that repos. To narrow down use a 2nd param to push: "git push rmtAlias localBranch". (or see http://stackoverflow.com/questions/948354/git-push-current-branch for more fanciness). To push, it's troublesome unless the target repos is bare. ECLIPSE You must own the friggin' Eclipse installation to install the plugin. Add software site http://www.jgit.org/updates . Select the non-source items for both JGit (Java port of Git) and EGit (the Eclipse plugin). See http://wiki.eclipse.org/EGit/User_Guide for required post-install setup. You can not make a new project based on an existing git repos and have it live in the normal workspace directory. You have it live in an external git work area (i.e. non-bare git repository). Github DOES NOT SERVE straight HTML files as HTML. Must create repositories using the web interface. Though you can create an empty repos and then populate it, you can't push to create the repos itself. Each created repository has basic name of github.com{:/}/.git. I think that this also applies to commercial Github accounts. May be accessed 3 ways: SSH: git@github.com:/.git HTTPS: https://@github.com//.git HTTP: http://github.com/unsaved/tst.git (RO) git-daemon: git://github.com//.git Though the repos URL ends with ".git", default clones will (by default) name new directory just . WEB PAGES: Magic project name ".github.com" is automatically published to http://.github.com Magic branch name "gh-pages" is automatically published to http://.github.com/ SETUP To get sample page, use web interface at Admin / GitHub Page: Generate... Of don't want sample page, then Until know Git better, best use a clean clone and follow verbatim the example commands under "Project Pages" at http://pages.github.com/ . By default, everything piped through Jeckyll, which is a "blog aware site generator". Defeat with "/.nojeckyll". Magic page /404.html serves the obvious purpose. Magic page "/CNAME" containing "your.domain" for the obvious purpose. Need real corresponding DNS change. For top-level: A record -> 207.97.227.245. Otherwise: CNAME -> normal http URL as above. Wiki at https://github.com///wiki FUCKING AMAZING!!!! No control over access. Anybody in the world can just delete all of your pages. No WYSIWYG!!!! Can choose any one of several wikitext languages. Can work locally on a git repository of the wikitext files. [PRETTY USELESS "git cat-file" (not "git cat"). Seems to not support non-HEAD?] git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt git-show HEAD:full/repo/path/to/my_file.txt # displays last commit of the file ROOT BRANCHING From Github site sample and http://book.git-scm.com/5_creating_new_empty_branches.html : $ cd /path/to/fancypants $ git symbolic-ref HEAD refs/heads/ $ rm .git/index $ git clean -fdx ! Do not do this when uncommitted changes are present! Detached HEADs. "git branch -a" shows: * (no branch) Checkout a tag like: git checkout res/tags/ # how to with rev.? To save work done to the detached head, branch it. refs: refs/heads/ refs/tags/ refs/remotes// To push to a non-bare repository. ONE-TIME On target repos: git config --list git config receive.denyCurrentBranch ignore Thereafter, each time to update from client to server, on client: git push And on server: git reset --hard Configs git config --list git config --get var.name Automatic file processing. Very useful automatic file processing doc'd at http://progit.org/book/ch7-2.html Attributes git check-attr -- file/path attrs: text, eol, ident, filter, diff, merge, whitespace, export-ignore, export-subst, delta, encoding EOLs For ASCII files not recognized as ascii, set a .gitattributes entry like: file*glob text To prevent an ASCII file from having EOLs translated, set file*glob -text I don't fucking get how to change files that Git already has made a determination about. .gitattributes seems to make no difference. Things seem to "just work" if you add files to repository with the native EOLs for that platform. See above for the few that Git mis-diagnoseds or that you want to force as binaries. Set a .gitattributes in exactly the same way as a .gitignore file. To have all \n for text files in the repository, set contents the file to: * text=auto I THINK NOT. This seems to be the default. But maybe the setting itself is platform-dependent. Default behavior (core.eol) is to get platform EOLs for work areas. But see what I said just before. Cloning or moving a repository to a remote host. (This example to make the remote repository bare. This is a fantastic use case for starting with a local repos then making it permanent afterwards; and for moving a permanent repos to be hosted elsewhere). Git program needs to be installed on the new remote host. First create the new (remote) target bare repository. # sourcerepos may be bare or work. Even if you are working from a local # source repository, the temp repos is necessary. # It gets rid of the remote branch references as listed by "branch -a". git clone --bare old/sourcerepos[.git] tmp-repo.git cd tmp-repo.git git push --mirror username@host:.../newhome.git # Wipe out the tmp-repo Awesome-looking server-management program: Gitolite Forking, per http://mechanicalrobotfish.com/posts/127-checking-out-open-source-git-project-right-way Wish I documented the goals of this better. I think the goal here is to have a fork 'project' with 'master' branch linked to a side-branch of original project. $ git init --bare fork.git $ git clone .../source.git xfer $ cd xfer $ git remote add fork .../fork.git $ git fetch fork $ git checkout -b source_b1 origin/b1 $ git branch -d master $ git checkout -b master # xfer/master is the new fork work branch $ git push fork master $ git config branch.master.remote fork # So by default will push to fork # Can't figger out how to set default for merge, so until do, always # specify merge source directly. # POSTNOTE: Try changing config value branch.master.merge. $ git push # to push $ git merge fork/master # Must specify master even though there is just 1 $ git merge origin/b1 REMOVING BRANCHES Per http://www.gitready.com/beginner/2009/02/02/push-and-delete-branches.html (incl. comments). git push origin :deadbranch # Wipe it remotely git branch -d deadbranch # Wipe it locally git remote prune origin # On all other clients. Per gitHub: git push origin :branchname (I guess source branch here no-name?) BROWSER HELP (Subversion doesn't have this) beyla$ git config --global help.format web beyla$ git config --global web.browser konqueror # I haven't yet figured out how it determines default, but it won't # hurt to check if the default is what you want before setting this # explicitly. Currently there is a bug with OpenSUSE rpms. I have registered a BugZilla bug. #675392 Work-around is to create sym link: beyla# pwd /usr/share/doc beyla# ln -s packages/git-core git-doc git stash [push] [-m 'save message'] # Store off the stash (stored internally) git stash pop # Apply and drop the last stored stash # (use "apply" and "drop" to do just either half of that). git stash list # Obviously... git stash clear # Clears the whole stack of stashes TODO: Learn git cat-file # Seems that "git show" is closer to what you would expect # from "git cat". GIT NOT WORKING AT FANNIE MAE Proxy for http and https. Since Curl used for these transports, you configure Curl according to Curl man page. !!NONE WORKING!! Set ALL_PROXY or For http, set http_proxy For https, set HTTPS_PROXY subtree MOD Quirky point here is that with the merger repos you can't do simple merges from master into the split branch. Just copy git-subtree.sh script from Github project to /usr/lib/git/git-subtree and make it executable (drop the ".sh" suffix). Usage for the user case of read-only usage of a directory of a super-project: I call 'merger' the project that just mirrors the super-project and manages the forking. This will push nothing to super-project but we will pull in updates in final repos. It manages the branch for the subdirectory. I call the bare repository that new work will be committed to the 'final.git' repos. Generally, since subtree can manage many independent subtrees, you must specify via a --prefix (or -p) switch for every subtree command, like git subtree SUBCMDL --prefix=... EQUIVALENT TO: git subtree SUBCMDL -P ... In the merger work area, must add a remote for the super-project in order to be able to get updates from it: git remote add upstream .git Make a remote for the final.git: git remote add final .git In merger project, create branch to include the filtered resources: git subtree split --prefix= --annotate='(split)' -b The annotation string is a persisted commit prefix which I guess must be same for all splits Save changes to the merger bare origin: git push origin splitBranch Then push the new branch to an empty final.git repository. Something like: git push final :master UPDATE: "git subtree merge --prefix= master does not work for this use case (being unable to run from the branch, and adding with no filter). Therefore... TO MERGE UPSTREAM MODS: # In master branch git fetch upstream # Pull in mods to super git merge upstream/master git push origin master Repeat the subtree split command. (Should APPEND new super mods) Apply changes to final repos with: git checkout NEWBRANCH git fetch ../final.git git merge FETCH_HEAD # re-add and commit conflicts git push origin NEWBRANCH git push final :master Generally, start by copying my $HOME/templates/gitignore to .gitignore in the root directory of your new project. Add to that. Generally, start by copying my $HOME/templates/gitattributes to .gitattributes in the root directory of your new project. Add to that. Whenever init a project that will contain UNIX scripts or DOS scripts or any other text files with fixed EOL delimiters, commit a .gitattributes to the root directory like *.bash -text *.cmd -text *.bat -text (Each line in .gitattributes may have only one pattern token). These patterns are applied to subdirectories too. EMAIL NOTIFICATIONS Write provided "post-receive-email"[.sh] script in bare repository as hooks/post-receive. Set recipient emails by a single hooks.mailinglist setting. Multiple addrs separated only by commas (can run in bare repos. Don't know bout work areas): git config --add hooks.mailinglist hsqldb-git@lists.sourceforge.net git config --add hooks.emailprefix '[Git hsqldb/tmp] ' ("--add" just adds to the current value) Syncing upstream and local branches. Always using same branch names. If you do this, you never have to specify remote repos or branch when fetching or pushing. Verify fetch and push output text, and with this command: git remote show origin Sync a local branch to a new upstream branch: git push --set-upstream origin b1 Check out remote branch: git checkout -b b1 origin/b1 # checks out remote branch b1 Merging will work perfectly if you have previously run either: git config merge.defaultToUpstream true # In this project or anywhere: git config --global merge.defaultToUpstream true No flat file export function. Closest is: git archive [--remote URL] master [relative/to/repos/root] | tar -xvC /dest/dir Can set export-ignore attr in .gitattributes to fine tune. And the archive task is highly customizable. -o option can tell zip vs. tar etc. from extension, but does not understand .gz, .bz. "git fetch" and "git merge" apply to the entire repository. Doesn't matter what subdirectory you are in. Change/Update/Reroot origin URL: git remote set-url origin git.iscm:code-templates Simple creation of new empty repository. git init ---bare path/to/parent/newrepos.git cd path/to/parent/newrepos.git git symbolic-ref HEAD refs/heads/default [to rename dflt branch to 'default'] cd somewhere git clone path/to/parent/newrepos # Don't need to specify .git suffix cd newrepos cp -av ~/code-templates/gitignore.txt .gitignore cp -av ~/code-templates/gitattributes.txt .gitattributes git add .gitignore .gitattributes git commit -m 'Added .gitignore and .gitattributes' . && git push Changing default branch. MY DEFAULT FOR default branch IS "default". To set default: git config --global init.defaultBranch x At github, just change the global setting for default repos branch before creating the repository. For non-github, cd to the bare repository directory x.giţ, and do: cd /path/to/x.git git symbolic-ref HEAD refs/heads/ If brand new empty repos, try this sequence (TODO: Verify) do the above. refs/branch/ remains empty for now cd some/tmp git clone /path/to/x cd x create some newFile git add newFile git checkout -b newDefaultBranch git commit... git push --set-upstream origin newDefaultBranch # FAILS VERIFY ls /path/to/x.git/refs/branch/ cd some/tmp git clone /path/to/x trial cd trail git branch --show-current To un-commit (after comit but before push): git reset HEAD~ At this point things are as if you did not commit, so you can then: git restore... To undo commits to local repository that you do not want to promote∵ Totally revert UNPUSHED updates after specified version: git reset --hard I don't understand difference between no-switch and --soft switch. Docs to me indicate that in both cases it will revert but leave the local changes uncommitted??? DETACHED checkouts = check out a point-in-time shown with "git branch -a" git checkout REVISION_SPEC revert the DETACHED: git checkout - (ambiguous, may need 'git checkout '