1. how to add as a submodule an existing, locally available git repo
  2. In January 2024 I followed this approach with good results:

    $ git submodule add <url> <path>
    $ git submodule absorbgitdirs <path>

  3. git branches: intuition & reality
  4. git cherry picking & 3-way merge
  5. what can go wrong in a rebase? (Julia Evans)
  6. PDF version
  7. confusing terminology (Julia Evans)
  8. PDF version
  9. where do files lives in a git repository (Julia Evans)
  10. source (Julia Evans blog)
    PDF version

  11. how to undo a git commit --amend and on the difference between HEAD@{1} and HEAD^ (or HEAD~1)
  12. This answer is very deep; in my case I only used the first incantation:

    git reset --soft HEAD@{1}
    … but not the second one:
    git commit -C HEAD@{1}
    Instead, I typed the commit message anew. Note, in particular the answer's caveat that HEAD@{1} is pointing to different things in the two incantations. Like I said, pretty deep.

  13. how to cleanly solve conflicts during git stash pop without a commit
  14. I've used the following (source) with great success:
    git stash pop
    // manually resolve conflicts and save the files (NB: don't use "git add" !!)
    git restore --staged .
    git stash drop
  15. sample ~/.gitconfig file
  16. These are the contents of the ~/.giconfig file on my Ubuntu 20.04 ThinkStation machine as of November 2022:

    [core]
    	excludesfile = /home/mperdikeas/.gitignore_global
    	editor = emacs
    [alias]
    	lgb = log --color  --graph --pretty=format:'%C(yellow)%h%Creset -%C(bold red)%d%Creset %s %Cgreen(%cr) %C(bold blue)%Creset' --abbrev-commit
            lg  = log --color --graph --oneline --decorate
            sstatus = status -s --ignored
            ppush = "!sh -c 'git push --all && git push --tags'"
            df = difftool
            branchdate = !git for-each-ref --sort='-authordate' --format='%(refname)%09%(authordate)' refs/heads | sed -e 's-refs/heads/--'
    [color]
    	ui = true
            diff=always
            status=auto
            branch=auto
    [diff]
    	tool = vimdiff
            external = git-meld
    [user]
            name = mperdikeas
            email = mperdikeas@gmail.com
    [push]
    	default = current
    [credential]
            username = mperdikeas@gmail.com
            password=ghp_kdflk328DtBTa3KvS_obviously-mangled # I've put the PAT here, obviously mangled
    	helper = store
    [gc]
    	auto = 0
            

  17. how to merge a github pull request locally in order to test it before accepting it
  18. source

    I followed the below workflow recently:

    git fetch origin pull/7/head:pr7
    git checkout -t -b origin_master origin/master
    git merge pr7
    git push origin HEAD:master

    Following the above I also did:

     git checkout -B master origin/master
    … whereupon I got the following message:
    Branch master set up to track remote branch master from origin.
    Switched to and reset branch 'master'
    Your branch is up-to-date with 'origin/master'.

  19. how to cleanly rebase contributions from a collaborator
  20. This is supposedly useful when I also have commits in my local repo that I haven't pushed for a while while the collaborator has pushed his commits to github. Rebase also results in a linear history in contrast to merge. That was the theory at least; I tried that circa September 2020 and it didn't work too well …

    $ git fetch -v
    $ git pull --rebase origin master

    NB: there should be no slash between origin and master

    So failing the above I had to resort to the familiar:

    git fetch -v
    git merge origin/master 

    In both cases you obviously still have to deal with the merge conflicts.a

  21. how to edit / view description on branches
  22. To edit the checked-out branch's description:

    git branch --edit-description

    To view a branch's (say awesome-new-feature) description:

    git config branch.awesome-new-feature.description

    NB: simply increasing the verbosity of the git branch command doesn't display the branch description:
    git branch -vv

  23. how to show all commits that have affected a particular file
  24. source
            git log --follow -- path/to/file
  25. how to resolve conflicts during rebase operations
  26. source

    In a recent rebase operation (where I was following the script given here), I had the following output:

    $ git rebase master
    First, rewinding head to replay your work on top of it...
    Applying: < some commit message >
    Applying: < some commit message >
    Applying: < some commit message >
    Applying: < some commit message >
    Using index info to reconstruct a base tree...
    Mdocs/release-notes
    .git/rebase-apply/patch:46: trailing whitespace.
    
    warning: 1 line adds whitespace errors.
    Falling back to patching base and 3-way merge...
    Auto-merging docs/release-notes
    CONFLICT (content): Merge conflict in docs/release-notes
    error: Failed to merge in the changes.
    Patch failed at < some commit message >
    The copy of the patch that failed is found in: .git/rebase-apply/patch
    
    When you have resolved this problem, run "git rebase --continue".
    If you prefer to skip this patch, run "git rebase --skip" instead.
    To check out the original branch and stop rebasing, run "git rebase --abort". 

    Following the advice given in the linked source I did the following:

    1. identified files in conflict (in the above example, that was docs/release-notes)
    2. resolved the conflict by editing the files that are in conflict (examining and eventually removing the Git demarcation markers)
    3. git add the edited files. NB: be sure to not commit at this point, no commit is necessary
    4. did a git rebase --continue as that was the command Git said to do when you completed.
    5. at that point, given that the rebase was successful, I saw (as expected) a fast forward merge.

  27. how to show which files were changed as part of a commit
  28. source
    git diff-tree --no-commit-id --name-only -r bd61ad98
  29. how to selectively checkout particular files from older commits and then revert
  30. $ git checkout 855f48bd39cf56ef3ddb94389243ebd3e5b0bb8f ../../path/to/file
    $ echo 'do your tests'
    $ git reset --hard
    $ echo 'you are now back where you started (before the checkout)
  31. finding common ancestor between current branch and some other branch
  32. If the "other" branch is "master" you can do a:

    git merge-base HEAD master
    (the operation is obviously commutative)

    The following can also serve to graphically show the branch point:

    git log --graph --oneline --all

  33. how to stash untracked files without having to stage them
  34. git stash save -u
  35. examining file differences in commits
  36. workflow for rebase / merge
  37. Based on this and this, I am now resolved to using the following workflow:

    1. create feature branch by branching off master
    2. rebase on top of master
    3. merge feature branch with master (this should be a fast forward merge)
    4. remove merged branch

    E.g.

    $ git checkout -b cool-feature
    $ git rebase master
    $ git checkout master
    $ git merge cool-feature
    $ git branch -d cool-feature 
    Note that git will bark at the branch delete command if it thinks it's not fully merged so no worries.

  38. Show files changed in a branch
  39. source

    Say you branched off from master at some point in the past and you are now in a branch for a cool new feature. Given that in the meantime (i.e. since you branched-off) the master branch has also advanced doing (from your feature branch) the following:

    git diff --name-only master
    … will also show files changed in master.

    To actually only see differences since the point you branched off from master (and not to bother with subsequent master commits), you need to do (from your feature branch):

    git diff --name-only master...
    Note that there is no space between master and ...

  40. how to stash and apply unstaged changes in a new branch
  41. source
    git stash -k -u
    git checkout -b new-branch
    git stash pop
    git commit -m 'applied stashed changes in new branch'
    git stash drop
  42. how to stash unstaged changes
  43. This will stash all modifications that you did not git add:

    git stash -k

    Note that newly created (and non-added) files will remain in your working directory unless you also use the -u switch.

    git stash -k -u
    Also, your working directory must be clean (i.e. all changes need to be added) when you git stash pop later on.

  44. various capablities of git diff
  45. source

    git diff explanation

    git diff
    Shows the changes between the working directory and the index. This shows what has been changed, but is not staged for a commit.
    git diff --cached
    Shows the changes between the index and the HEAD (which is the last commit on this branch). This shows what has been added to the index and staged for a commit.
    git diff HEAD
    Shows all the changes between the working directory and HEAD (which includes changes in the index). This shows all the changes since the last commit, whether or not they have been staged for commit or not.

  46. how to update all submodules
  47. Assuming you've cloned your repository with git clone --recursive (which you always should), then do a:

    git submodule update --recursive --remote

    Then,

    for the upstream:
    you should add the submodule and commit the repository (that hosts the submodule) and push
    for the downstream:
    you should fetch in the repository that hosts the submodule and merge. It is not super-clear to me whether at the downstream you also need to do git submodule update --recursive --remote prior to fetching and merging the top-level repository.

  48. How to discover which commit deleted a file and resurrect it
    1. find the path to the file
    2. This is the first step in case you remember a few things about the file's name but have forgotten it's full path (which is necessary for the next step):
      git log --diff-filter=D --summary | grep delete | grep -i file-name-fragment
    3. find the commit that deleted the file
    4. This will be the last one (hence we are using the -1 flag below):
      git log -1  --stat -- full-path-to-the-file
    5. resurrect the file (you can also do this in some throwaway cloned repo and then copy it manually)
    6. To perform the resurrection use the previous commit than the one that deleted the file (hence the ^):
      git checkout commit-identifier^ full-path-to-file 
  49. How to publish a github project to GitPages
  50. source

    The gist of the idea is to create an orphan gh-pages branch which will include only the HTML pages you wish to publish, and then push it to the origin:

    1. git checkout --orphan gh-pages
    2. At this point a simple git branch fails to show that you are in the new, orphan branch so do instead the following to verify you in the correct branch:
      git symbolic-ref HEAD
    3. remove / add files …
    4. git add . -A
    5. git commit -m 'gh-pages initial'
    6. git push -u origin gh-pages
    7. return to master:
      git checkout master

    … following the above steps it may take a couple of minutes before your site becomes visible in:
    https://<your-github-id>.github.io/<repository-name>/dir/to/some/index.html

  51. How to remove a git submodule
  52. source
    git rm the_submodule
    rm -rf .git/modules/the_submodule
          
  53. how to add (clone) an external git repo as a submodule of my repo
  54. Execute a command like the following from the toplevel of the working tree:
    git submodule add https://github.com/fxbois/web-mode.git .emacs.d/web-mode
          
    The last argument is the path in which the submodule should reside. NB: obviously people that have already cloned the repo (prior to the addition of the submodule) would still have to do:
    git submodule update --init --recursive
    Otherwise (i.e. if the cloning happens after the addition of the submodule it is better to just do:
    git clone --recursive git://github.com/some/repo.git
          
    (see how to clone a repo including the submodules).
  55. how to configure git to save password in memory for sometime (when cloning via https)
  56. $ git config --global credential.helper 'cache --timeout=3600'
    # Set the cache to timeout after 1 hour (setting is in seconds)
          
    source
  57. console-based tool equivalent to gitk
  58. sudo apt-get install tig
    E.g. to view history on single file:
    tig [filename]
  59. undo commit before push
  60. The following has worked for me once:
    git reset --hard HEAD~1
          
    source.
  61. git list remote commits
  62. git delete pushed commits (SO)
  63. git workflow using 'rebase'
  64. original article hacker news discussion
  65. show files affected by a commit in SVN
  66. so
    quick and dirty:
    git diff-tree -r df7fc29
          
    long and clean:
    git diff-tree --no-commit-id --name-only -r df7fc29
          
    - consumed in my git-show-files script (in ~/tools)
  67. procedure I used to create an SVN mirror of my git project
  68. (based on the general instructions)
    1. created new repository dummy on github.com
    2. cloned it
    3. cd && git clone https://github.com/mperdikeas/dummy.git
    4. added a 'foo' file and pushed it
    5.     cd dummy && echo "foo" >> foo && git add . -A
          git commit -m "foo added" && git push
              
    6. created receptor SVN project in server-side SVN
    7. cd ~/svn-playground/ && svnadmin create svn-server/dummy/
    8. created a 'trunk' directory in receptor SVN project
    9.     cd ~/svn-playground && mkdir dummy-client && cd dummy-client
          svn co file:///home/mperdikeas/svn-playground/svn-server/dummy . 
          svn mkdir trunk && svn commit -m 'created trunk directory'
              
    10. configuring git svn mirror (ESAC use-case)
    11. add the following contents to the ~/dummy/.git/config file:
      [svn-remote "svn"]
          url = file:///home/mperdikeas/svn-playground/svn-server/dummy/trunk
          fetch = :refs/remotes/git-svn
              
    12. Do an initial fetch of the empty subversion remote, and check it out as a new git branch (called svn)
    13. cd ~/dummy/ && git svn fetch svn
      git checkout -b svn git-svn
              
    14. Merge in all your commits from master, and push them to subversion
    15. git merge master
      git svn dcommit
              
    16. check that the mirroring is effected by updating on the SVN repository
    17. cd ~/svn-playground/dummy-client/ && svn update
                
      (files 'foo' and 'README.md' should now be present in the dummy-client (in the trunk repository). working copy
    18. To allow pushing to svn from master, rebase master to the svn branch (which can then be deleted)
    19. cd ~/dummy && git checkout master
      git rebase svn && git branch -d svn
                  
    20. verify that you are on branch 'master' and only that branch exists
    21. cd ~/dummy
      git status
      git branch
                    
    22. verify the SVN read-only mirroring by removing a file, adding another and pusing the changes
    23. echo "zoo" >> zoo && rm foo && git add -A && git commit -m "zoo added, foo removed" & git push
                    
    24. confirm that the changes are not yet visible to the SVN repo
    25. cd ~/svn-playground/dummy-client/ && svn update
                    
      (nothing should be added)
    26. push to SVN from the git repo
    27. cd ~/dummy && git svn dcommit
                    
    28. view the changes in the SVN repo
    29. cd ~/svn-playground/dummy-client/ && svn update
                    
  69. How to do SVN read-only mirroring from a git repo
  70. NB: particularized instructions here.
    The instructions on this page worked well. Copied below in case the source goes off line:
    Create the subversion repository in the usual way, using svnadmin.

    Once you've got an empty repository to point to (we'll imagine it's at http://svn.example.com/foo), you also need to commit an initial version (I also created a trunk directory in this step, in case we later decide to mirror branches too):
    svn co http://svn.example.com/foo
    cd myproj
    svn mkdir trunk
    svn commit -m 'Created trunk directory'
            
    Once this is done, you can throw away the directory you checked out of subversion.

    Set up the subversion remote
    This step, and subsequent ones, need to be performed on whichever git repository you want to mirror from.

    In our case, we have a central repository running on a local installation of Gitorious. This is a bare repository, which makes things a little tricker, as git-svn requires a working copy. To get round this, we create a clone, which we’ll use as an intermediate step in the mirroring process. If you're not mirroring a bare repository, you can omit this step.

    The repositories we want to mirror are in ~git/repositories, and we’ve created a directory ~git/repositories/svn-mirror where we'll put the clones. For this example, we'll use a repository called foo/mainline.git.
    Create the clone:

    git clone ~git/repositories/foo/mainline.git ~git/repositories/svn-mirror/foo
    cd ~git/repositories/svn-mirror/foo
                
    Now add the following to .git/config (with the correct svn URI, of course):
    [svn-remote "svn"]
    url = http://svn.example.com/foo/trunk
    fetch = :refs/remotes/git-svn
                
    Now do an initial fetch of the empty subversion remote, and check it out as a new git branch (called svn):
    git svn fetch svn
    git checkout -b svn git-svn
                
    You can now merge in all your commits from master, and push them to subversion. You’ll probably want to go and make a coffee or something while the dcommit runs – if you haven’t used subversion for a while you’ve probably forgotten just how much slower it is than git.
    git merge master
    git svn dcommit
                
    To allow pushing to svn from master, rebase master to the svn branch (which can then be deleted):
    git checkout master
    git rebase svn
    git branch -d svn
                
    At this point you should be able to manually update subversion at any time by running git svn dcommit from the master branch.
  71. reconnect a detached head
  72. $ git log -1
    # note the SHA-1 of latest commit
    $ git checkout master
    # reset your branch head to your previously detached commit
    $ git reset --hard [commit-id]
                
  73. list tags
  74. git tag -l
  75. checkout remote tip
  76. git checkout origin/HEAD
  77. show remote tags
  78. git ls-remote --tags
  79. produce a git patch
  80. There are two ways: The git-format-patch method produces cleaner output.
  81. git add all files in a directory hierarchy except a particular one
  82. The following is the 'safe' version (echo):
    find . ! -type d  ! -iname nosecurity_mvn.zip -exec echo git add {} \;
  83. examine tree-ish objects (such as commits)
  84. git ls-tree

    or..

    git-ls-tree

    This, and many other commands are available at /usr/lib/git-core

  85. show git tags including messages of annotated tags
  86. git tag -l -n1
  87. useful git log alias (to show tags among others)
  88. git config --global alias.lgb "log --graph --oneline --color --decorate"
  89. move local changes to new branch
  90. git stash
    git reset --hard
    git clean -xf
    git clean -df
    git branch newBranch
    git checkout newBranch
    git stash pop
    git add . -A -n
    git commit -m "first commit on new branch"
                    
  91. change most recent git commit message
  92. git commit --amend -m "New commit message"
  93. concise, yet informative git history
  94. git log --oneline --decorate=full --graph
                    
  95. how to init and fetch data for git submodules
  96. git submodule init
    git submodule update
                    
    Apparently git submodule update --init --recursive is also an option. See for more: how to clone a repo including the submodules).
  97. how to get the hash of the current commit (and just that)
  98. git rev-parse --verify HEAD
                      

    - or simply -

    git rev-parse HEAD
                        
  99. how to restore a specific file to the branch's image:
  100. git checkout -f visualization "13 - COAST Caches/ccaches_protocol_types/src/org/coast/caches/network/types/CacheGetRequest.java"
    In the incantation above 'visualization' (i.e. the branch name) is a tree-ish object in git. The general signature of git checkout is therefore:
    git checkout  
                        
  101. overwrite local working copy modifications:
  102. git checkout .
  103. bullet-proof way to reset all the files in the local repository:
  104.                 $ git clean -d -x -f
                    $ git reset --hard
                        
    to just see which files will be deleted by git clean do a dry-run:
                    $ git clean -d -x -n
                        
  105. how to check differences between local and remote branches:
  106.                 $ git diff master origin/master
                        
  107. to avoid having to type:
  108.                 git add . -A
                    git commit -m " .. "
                        
    do a:
                    git config --global alias.ac '!git add . -A && git commit'
                        
  109. how to force git diff to always use color:
  110.                 git config --global color.diff auto
                        
  111. delete a commit that's also been pushed:
  112. source Assuming you are sitting on that commit, then this command will wack it...
        git reset --hard HEAD~1
                        
    The HEAD~1 means the commit before head. Or, you could look at the output of git log, find the commit id of the commit you want to back up to, and then do this:
        git reset --hard 
                        
    If you already pushed it, you will need to do a force push to get rid of it...
        git push origin HEAD --force
                        
    However, if others may have pulled it, then you would be better off starting a new branch. Because when they pull, it will just merge it into their work, and you will get it pushed back up again. If you already pushed, it may be better to use git revert, to create a "mirror image" commit that will undo the changes. However, both commits will both be in the log. FYI -- git reset --hard HEAD is great if you want to get rid of WORK IN PROGRESS. It will reset you back to the most recent commit, and erase all the changes in your working tree and index. Lastly, if you need to find a commit that you "deleted", it is typically present in git reflog unless you have garbage collected your repository. comment: HEAD~1 or just HEAD^. If you pushed, you should use git revert instead