git submodule update needed only initially? - git-submodules

I'm getting a hang of git submodule (wishful thinking?) and I'm coming up with more specific questions, which is a good sign...
I've tried to find the which revision of the submodule the superproject refers to, in .gitmodules and .git/config, but nothing is mentioned there...
The scenario is that I'm changing submodules in their root locations (from which they're imported), and then pulling them in where they're "submoduled"...
Beyond committing from the superproject to incorporate those changes into the superproject repo, do I also need to do "git update" to register the new pulled in submodule commits?
Basically the question is:
do I need to "git submodule update" only when I first clone the superproject, or after every pulling of the submodule (from its own repo)?
Thank you

As mentioned in my previous answer to git submodule update, that command checks out the specific version of the project, base on their .gitmodules file.
The GitPro page does insist:
This is an important point with submodules: you record them as the exact commit they’re at.
You can see which commit is referenced by running within the "super project" (the one referencing one or several submodules):
git submodule status (except if you did some commit directly within that submodule, in that case it will show a "+" in front of the SHA-1 of the HEAD of any submodule that has advanced from the SHA-1 stored in the superproject) or
git ls-files --stage looking for entry in mode "160000", a special entry in the Git index.
That means, each time you execute a git command in the "super project" which could modify that submodule commit SHA1, you need a "git submodule update".
do I need to "git submodule update" only when I first clone the superproject, or after every pulling of the submodule (from its own repo)?
Yes, you have to do this every time you pull down a submodule change in the main project.
That is because you are referencing the exact commit the submodule original repo is at (as said above), and when you pull that repo, you are effectively modifying that commit.

Related

Git submodule is ignored

When I try to add a submodule via
git submodule add git#domian:repo.git contact
I get the following message:
The following path is ignored by one of your .gitignore files:
contact
Use -f if you really want to add it.
Here is my .gitignore:
# Ignore everything
*
# But not these files:
!*.py
!*.md
!*.gitignore
!.gitmodules
!contact/
It is resolved by using the suggested -f option, but I am curious why the !contact/ entry in .gitignore does not alleviate the problem.
A submodule is composed of a gitlink (a special entry 160000 in the Git repository index), and a remote URL+path in the .gitmodules.
So excluding !contact/ would still ignore the gitlink "contact" (which is not a folder contact/, but a special "file")
This would work better, and allow the git submodule add to proceed:
!contact
And if any other cause would still block the git submodule add, the next Git 2.26 (Q1 2020) will provide a more helpful error message.
I don't hit that error in your particular case (I have git version 2.21.0.windows.1).
I do hit that error when trying to add a submodule outside the parent repository, though (which apparently isn't supported):
$ git submodule add https://github.com/user/repo ../repo
The following path is ignored by one of your .gitignore files:
../repo
Use -f if you really want to add it.
Best guess is it's a bug...so adding !contact/ to your .gitignore doesn't fix it because it's not actually the .gitignore causing the problem.
What git version do you have? You can download the source code for your particular version, search for the error message (e.g. here it is in v2.21), and trace through the code to figure out what actually goes wrong.

Git: checkout submodule files into a single directory

It's possible with git submodules to checkout multiple repositories as submodules into respective paths, e.g.:
% git submodule add git#.../repo1.git ./here/is/1
% git submodule add git#.../repo2.git ./here/is/2
But what if I need to checkout the contents of repo1 and repo2 both into a single path, ./here/is/3?
Basically I have a metric shit-ton of submodule repos I need to all be checked out into a very rigid directory hierarchy on the client side when the user does git clone --recursive ...
I want the contents of all submodules to be checked out into ./somepath. Can it be done?
One thing I considered was using symlinks, but that feels wrong.
EDIT:
I want the contents of 1 and 2 in the above to be placed in the same target directory on the client. I can do this by having the user manually run a script after cloning (it is not possible to have git track a single file), but it seems like there should be a cleaner way to do this -- manually creating a symlink for each submodule is a lot of work, and it seems like the submodule abstraction should be able to handle this.
Maybe my question is a dupe-in-disguise?
One way would be to create another parent repo, with the submodules declared directly in it:
newParentRepo/
1/
2/
3/
...
That parent repo could be cloned --recursive in ./somepath, and the submodules would be directly under ./somepath (in their respective root directories 1/, 2/, ...).
You would need to synchronize the SHA1 of the submodules as recorded by the first parent repo into the second parent repo, in order for said second repo to record the right list of submodules SHA1.

How do I change ignore-paths on an existing git-svn repo?

I have an already existing git-svn repo with an ignore paths in my .config file that looks like this:
ignore-paths = ^(?!(Path1/Proj1|Path1/Proj2|Path2/Proj3))
This works well.
Someone added a new project in svn that I now need in my git repo.
If I change ignore-paths to what's below and issue a fetch or a rebase, I never see Path2/Proj4
ignore-paths = ^(?!(Path1/Proj1|Path1/Proj2|Path2/Proj3|Path2/Proj4))
In the past, I've always given up and blasted away my git repo and recreated it. Is there a better way?
After editing the ignore-paths you need to
git svn reset -r <n> -p # where <n> is the SVN revision where the new path was added.
git svn fetch
git rebase # or reset
Reference git-svn(1):
reset
Undoes the effects of fetch back to the specified revision.
This allows you to re-fetch an SVN revision. Normally the
contents of an SVN revision should never change and reset
should not be necessary. However, if SVN permissions change,
or if you alter your --ignore-paths option, a fetch may fail
with "not found in commit" (file not previously visible) or
"checksum mismatch" (missed a modification). If the problem
file cannot be ignored forever (with --ignore-paths) the only
way to repair the repo is to use reset.
Only the rev_map and refs/remotes/git-svn are changed (see
$GIT_DIR/svn/*\*/.rev_map.* in the FILES section below for details).
Follow reset with a fetch and then git reset or git rebase to
move local branches onto the new tree.

Git merge with overwriting local changes [duplicate]

In Git, during a merge, is there a way that we can tell git to discard local changes in case of a conflict and apply the changes from the merged branch?
I mean if there is a way, then we can do merges like branch merges without conflicts.
Before trying to merge, you can discard the local changes yourself git reset --hard HEAD.
You can replace HEAD by whatever commit hash you want.
This will bring you the the clean state of the commit you're actually on, and you'd lose all your changes.
If you want to keep them, you can stash them before with git stash, or move them to another branch:
git checkout -b new_branch
git add .
git commit -m "My awesome commit"
git checkout - # will bring you back to the last branch you were in
If you want to ignore all local changes, and an additional merge commit you want to just move your branch to the remote HEAD.
git log --oneline origin/master
# assume the first sha is bbdfa17
git reset --hard bbdfa17
Now you are at the tip of the tree with no merge commits.
It sounds like you want to read about the merge strategies 'theirs' and 'ours'. When merging you can specify that either your current branch (ours) or the remote branch (theirs) is the correct one.

How to recover from an unwanted rename using git-svn: "Transaction is out of date"

I'm using git-svn. I've moved file 'A' to 'B' and I'm up to date with the svn HEAD (using git svn rebase). I can commit all other changes without problems. Now I've decided that I want to move 'B' back to 'A' and commit that change.
When I do the move and commit to my local master it works fine, but I get the following when doing a git svn dcommit:
Transaction is out of date: Out of date: 'A' in transaction '3652-1' at /opt/local/libexec/git-core/git-svn line 570
So I tried to copy and delete in a separate commit which resulted in:
Item already exists in filesystem: File already exists: filesystem '/usr/svn/db', transaction '3652-1', path 'A' at /opt/local/libexec/git-core/git-svn line 4735
I've recovered from this situation with plain svn by using the workarounds like the one described in the documentation, but I don't know how to recover with git-svn. What is going on and how do I fix it?
Removing .git/svn did not work for me. Instead, here's how I resolved:
Deleted the offending directories from the repository (But I'm not sure that this is necessary. In hindsight I think I could have skipped this step)
git svn rebase
During the rebase, there were some conflicts. For each conflict, I resolved the conflicts in text editor, then used git add <file-in-conflict> and then git rebase --continue
After rebase completed successfully, git svn dcommit ran successfully!
I can't claim to understand what's really going on under the hood in git-svn in this case (although the underlying SVN issue makes perfect sense). My usual strategy when git-svn gets confused somehow is to blow away the .git/svn metadata directory (as in this post). This almost always saves me from odd synchronization issues between the git and SVN repositories.
It happened with me when I interrupted the dcommit process.
Follow these steps to recover from error:
git svn rebase
You will get conflicts in files. Resolve the conflicts & then git add filename (in which conflict occurred) for each file.
Now do git svn dcommit. It will be pushed to remote successfully.