1. how to submit multipled pull requests add as a submodule an existing, locally available git repo
  2. In February 2025 I followed the below procedure and it worked like a charm. My situation was that I wanted to submit a pull request to a github repo to which I was unable to push a branch. Therefore, as per the suggested procedure in these cases, I forked the original repo, created a branch, pushed it (to my forked repo) and issued the pull request from github.com. This all worked with no problem. The problem came on the next step.

    After the owner of the repo accepted my pull request into his master branch, I obviously wanted to fetch their updated master branch wherein my pull request had been merged — not just to see my changes but, more importantly, to be able to create a new pull request out of the latest revision of the master branch. At that point simply doing: git fetch origin failed to achieve this as the origin for my local cloned repo (on my development machine) was obviously set to point to my own forked repo. To address this, I had to define a new remote for the upstream repo that I cloned from, and followed the below procedure:

    $ git remote -v
    to see the existing remotes
    $ git remote add upstream https://github.com/kyp44/Topology.git
    to add a new remote for the original repo I had cloned
    $ git remote -v
    to confirm the new remotes
    $ git checkout master
    to checkout the master of my forked repo into my development, locally-cloned repo
    $ git fetch upstream
    to fetch the upstream main branch
    $ git merge upstream/master master
    to merge the upstream master branch into my local master branch
    $ git push origin
    to push my local current (master) branch, that was just merged with the upstream master into my forked repo's remote master branch

    Following the above procedure I was able to not only synchronize my cloned repo with the upstream master but was also able to quickly submit another pull request.

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

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

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

  13. how to undo a git commit --amend and on the difference between HEAD@{1} and HEAD^ (or HEAD~1)
  14. 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.

  15. how to cleanly solve conflicts during git stash pop without a commit
  16. 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
  17. sample ~/.gitconfig file
  18. 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
            

  19. how to merge a github pull request locally in order to test it before accepting it
  20. 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'.

  21. how to cleanly rebase contributions from a collaborator
  22. 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

  23. how to edit / view description on branches
  24. 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

  25. how to show all commits that have affected a particular file
  26. source
            git log --follow -- path/to/file
  27. how to resolve conflicts during rebase operations
  28. 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.

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

  35. how to stash untracked files without having to stage them
  36. git stash save -u
  37. examining file differences in commits
  38. workflow for rebase / merge
  39. 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.

  40. Show files changed in a branch
  41. 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 ...

  42. how to stash and apply unstaged changes in a new branch
  43. 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
  44. how to stash unstaged changes
  45. 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.

  46. various capablities of git diff
  47. 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.

  48. how to update all submodules
  49. 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.

  50. 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 
  51. How to publish a github project to GitPages
  52. 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

  53. How to remove a git submodule
  54. source
    git rm the_submodule
    rm -rf .git/modules/the_submodule
          
  55. how to add (clone) an external git repo as a submodule of my repo
  56. 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).
  57. how to configure git to save password in memory for sometime (when cloning via https)
  58. $ git config --global credential.helper 'cache --timeout=3600'
    # Set the cache to timeout after 1 hour (setting is in seconds)
          
    source
  59. console-based tool equivalent to gitk
  60. sudo apt-get install tig
    E.g. to view history on single file:
    tig [filename]
  61. undo commit before push
  62. The following has worked for me once:
    git reset --hard HEAD~1
          
    source.
  63. git list remote commits
  64. git delete pushed commits (SO)
  65. git workflow using 'rebase'
  66. original article hacker news discussion
  67. show files affected by a commit in SVN
  68. 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)
  69. procedure I used to create an SVN mirror of my git project
  70. (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
                    
  71. How to do SVN read-only mirroring from a git repo
  72. 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.
  73. reconnect a detached head
  74. $ 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]
                
  75. list tags
  76. git tag -l
  77. checkout remote tip
  78. git checkout origin/HEAD
  79. show remote tags
  80. git ls-remote --tags
  81. produce a git patch
  82. There are two ways: The git-format-patch method produces cleaner output.
  83. git add all files in a directory hierarchy except a particular one
  84. The following is the 'safe' version (echo):
    find . ! -type d  ! -iname nosecurity_mvn.zip -exec echo git add {} \;
  85. examine tree-ish objects (such as commits)
  86. git ls-tree

    or..

    git-ls-tree

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

  87. show git tags including messages of annotated tags
  88. git tag -l -n1
  89. useful git log alias (to show tags among others)
  90. git config --global alias.lgb "log --graph --oneline --color --decorate"
  91. move local changes to new branch
  92. 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"
                    
  93. change most recent git commit message
  94. git commit --amend -m "New commit message"
  95. concise, yet informative git history
  96. git log --oneline --decorate=full --graph
                    
  97. how to init and fetch data for git submodules
  98. 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).
  99. how to get the hash of the current commit (and just that)
  100. git rev-parse --verify HEAD
                      

    - or simply -

    git rev-parse HEAD
                        
  101. how to restore a specific file to the branch's image:
  102. 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  
                        
  103. overwrite local working copy modifications:
  104. git checkout .
  105. bullet-proof way to reset all the files in the local repository:
  106.                 $ 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
                        
  107. how to check differences between local and remote branches:
  108.                 $ git diff master origin/master
                        
  109. to avoid having to type:
  110.                 git add . -A
                    git commit -m " .. "
                        
    do a:
                    git config --global alias.ac '!git add . -A && git commit'
                        
  111. how to force git diff to always use color:
  112.                 git config --global color.diff auto
                        
  113. delete a commit that's also been pushed:
  114. 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