Git Functions
- git_functions.bsh
A few functions to make working with git and different versions of git easier
- log_unpushed_commits
List all unpushed commits to stdout
List all commits on branches/tags that have not been pushed to a remote. This is a set operation: it lists all the commits from a branch in the DAG except those reachable by a remote-tracking branch. It does not require an associated remote-tracking branch
- Arguments:
[
$1
] - A name of a remote to filter by; e.g., origin. If unset, then don’t filter[
$2...
] - A branch/tag to filter by (or multiple branches/tags); e.g., main. If unset, then don’t filter
- Output:
*stdout*
- Print all unpushed commits for tracking branches to stdout
See also
- git_tracking_branch
Get the corresponding remote-tracking branch for a local-tracking branch
- Arguments:
$1
- A local-tracking branch; e.g., main
- Output:
*stdout*
- The corresponding remote-tracking branch, or the empty string if there is no tracking branch
Note
A branch that you create locally and then push to a remote is not configured as a local-tracking branch by default. You must use the -u flag with
git push
orgit branch
.A branch cannot track multiple remotes.
- git_tracking_branches
Find all local- and corresponding remote-tracking branches
- Arguments:
[
$1...
] - The name of a remote to filter by (or multiple remotes); e.g., origin. If unset, then don’t filter
- Output:
vsi_git_tracking_branches
- An array of local-tracking branch namesvsi_git_remote_tracking_branches
- A corresponding array of remote-tracking branch names
Note
A branch that you create locally and then push to a remote is not configured as a local-tracking branch by default. You must use the -u flag with
git push
orgit branch
.A branch cannot track multiple remotes.
- log_outgoing_commits
List all unpushed commits for a tracking branch to stdout
- Arguments:
$1...
- A local-tracking branch (or multiple branches); e.g., main
- Output:
*stdout*
- Print all unpushed commits for the tracking branch to stdout
See also
- log_all_outgoing_commits
List all unpushed commits for tracking branches to stdout
- Arguments:
[
$1...
] - The name of a remote to filter by (or multiple remotes); e.g., origin. If unset, then don’t filter
- Output:
*stdout*
- Print all unpushed commits for tracking branches to stdout
See also
- convert_git_remote_http_to_git
Change the remote url of a git repo to use the git@ syntax instead of https
In a git repository (or submodule), if the (last) URL of the remote is specified using the the https://
protocol, convert it to the ssh transfer protocol (git@..) to make pushing changes to a private remote server easier. Assume a very basic url format: https://git-server.com/co/project.git
without port, query, or fragment sections. Warn if these exist. Do nothing if a pushurl is already configured
- Arguments:
[
$1
] - The name of a remote to convert. Default: origin
Note
This does not change a submodule’s tracked URL (i.e., the URL in the .gitmodules file) nor a submodule’s URL (i.e., .git/config:submodule), only the URL of the remote in .git/**/config (e.g., .git/modules/docker/recipes/config:remote)
- is_submodule
- Output:
Returns
0
if the PWD is in a submodule,1
for it is not
- git_project_root_dir
- Output:
*stdout*
- The absolute path to the root of the topmost superproject’s working tree.
Example
If the vsi_common repository is cloned (recursively) at /src
, and then git_project_root_dir
will output /src/vsi_common
. This is true regardless of where in the work-tree the function is run from, including from within submodules, sub-submodules, etc. Cf. git rev-parse –show-superproject-working-tree (available in git v2.13.7), which only outputs the absolute path to the working tree of the superproject of the current submodule.
- git_project_git_dir
- Output:
*stdout*
- The absolute path to the git directory of the topmost superproject.
If the vsi_common repository is cloned (recursively) at /src
, and then git_project_git_dir
will output /src/vsi_common/.git
. This is true regardless of where in the work-tree the function is run from, including from within submodules (e.g., docker/recipes), sub-submodules, etc. This function can also be run from within a bare repo (and from within a .git directory)
- git_submodule_summary_recursive
Recursively log the commits differing between each submodule’s tracked commit and its current working tree
See also
- git_submodule_summary
Log the commits differing between each submodule’s tracked commit and its current working tree
Using git diff --submodule=log
, compare the working tree of each submodule to the version committed to HEAD of the super project, and list any commits that are missing and/or now present in the submodule. For example, if an earlier commit in the submodule is checked out, there will be missing commits in the submodule according to the super project. Similarly, if a commit is made to the submodule, there will be new commits present in the submodule according to the super project. Of course, the commit graph could diverge in more complicated ways.
- Output:
*stdout*
- Each submodule’s differences in terms of commits
Note
This function iterates through each submodule in a depth-first traversal
See also
- git_submodule_displaypaths_recursive
Recursively get the displaypath to each submodule
See also
- git_submodule_displaypaths
Get the displaypath to each submodule
Get what git refers to as the displaypath of the submodule: the relative path from the current working directory to the root of the containing repository and then to each submodule. This path is defined by the git-specified environment variable, displaypath (or prefix in and before git v1.8.3).
- Output:
stdout - The displaypath to each submodule (recursively); e.g., docker/recipes
Note
Submodule paths are not the same thing as submodule names.
Note
This function iterates through each submodule in the same order as git_submodule_urls
, git_submodule_names
and git_submodule_toplevels
(i.e., a depth-first traversal)
Note
Because this function uses git submodule foreach
, it skips submodules that have been init’d but not updated.
See also
- git_submodule_urls_recursive
Recursively get all submodule URLs
See also
- git_submodule_urls
Get all submodule URLs
Get the (last) URL for each submodule (recursively) from its .git/**/config file (e.g., .git/modules/docker/recipes/config) for the specified remote (origin by default). Note: Since git v1.8, a remote can have multiple associated URLs (and pushurls) (see .git/config).
- Arguments:
[
$1
] - The name of a remote. Note: this same remote must exist in all submodules. Default: origin- Output:
stdout - The URL of each submodule (recursively); e.g., https://github.com/VisionSystemsInc/docker_recipes.git
Note
The ultimate source-of-truth of a submodule’s URL is in its .gitmodules file. If the URL is updated in this file, then the repository’s and submodule’s configurations will be out-of-date. git submodule sync
will update these configurations using the .gitmodules file and the default remote of the current branch, if set; otherwise origin. git_submodule_sync
will do the same but using the specified remote.
Note
This function iterates through each submodule in the same order as git_submodule_displaypaths
, git_submodule_names
and git_submodule_toplevels
(i.e., a depth-first traversal)
Note
Because this function uses git submodule foreach
, it skips submodules that have been init’d but not updated. Cf. git_mirror get_config_submodule_names
, which will (non-recursively) list submodules that have only been init’d. The associated URL can then be queried for a given submodule name with git config --get submodule.<name>.url
as git_mirror clone_submodules
does.
See also
- git_submodule_names_recursive
Recursively get the name of each submodule
See also
- git_submodule_names
Get the name of each submodule
Get the name of the submodule as defined in the .gitmodules file. This name is, by default, the same as the path to the submodule; however, this is not necessarily the case.
- Output:
stdout - The name of each submodule (recursively); e.g., docker/recipes
Note
Submodule names are not the same thing as submodule paths.
Note
This function iterates through each submodule in the same order as git_submodule_displaypaths
, git_submodule_urls
and git_submodule_toplevels
(i.e., a depth-first traversal)
Note
Because this function uses git submodule foreach
, it skips submodules that have been init’d but not updated. Cf. git_mirror get_config_submodule_names
(it queries the current repository’s submodule names from its configuration), which will list submodules that have been init’d but not updated, and just_git_functions.bsh submodule-helper-list
, which will list all submodules, even those not init’d (it queries the current repository’s submodule names and paths from the .gitmodules file). Although these functions are not recursive, they both are used to recurse manually through all the submodules (albeit, in a different order than this function).
See also
- git_submodule_toplevels_recursive
Recursively get the path to the top-level directory of each submodule
See also
- git_submodule_toplevels
Get the path to the top-level directory of each submodule
Get the path to what git refers to as the top-level directory of the submodule; i.e., the absolute path to the top-level of the immediate superproject. For example, the vsi_common repository has a submodule at docker/recipes
. If the repository is cloned in /src
, then the top-level directory for the submodule docker/recipes is /src/vsi_common
.
This function, along with git_submodule_names
, could be used to, for example, cd to the top-level of each immediate superproject and then query the repository’s submodule configuration using git config submodule.<name>.<key>
; e.g., git config submodule.docker/recipes.url
.
- Output:
stdout - The top-level directory of each submodule (recursively); e.g., /src/vsi_common
Note
This function iterates through each submodule in the same order as git_submodule_displaypaths
, git_submodule_urls
and git_submodule_names
(i.e., a depth-first traversal)
Note
Because this function uses git submodule foreach
, it skips submodules that have been init’d but not updated.
See also
- submodule-helper-relative-url
Essentially git submodule--helper relative-url
(if it existed)
Resolve a submodule’s relative URL based on the parent URL. This function works by creating a dummy git repository and submodule and then running git submodule init
(which runs a process similar to git submodule sync
), after which, the resolved URL can be queried with git config submodule.submod.url
. We do this to avoid modifying the existing repository’s git configuration (e.g., git config submodule.docker/recipes.url
).
- Arguments:
$1
- URL of the parent repository; e.g., https://github.com/VisionSystemsInc/vsi_common.git pergit config remote.origin.url
$2
- A relative submodule URL—typically from the .gitmodules file; e.g., ../../VisionSystemsInc/docker_recipes.git pergit config -f .gitmodules submodule.docker/recipes.url
[
$3
] - Up path: path from the submodule to the parent repository; e.g.,../../
. Must have a trailing slash. (Not strictly necessary if$1
is an absolute path)
- Output:
stdout - Resolved URL; e.g., https://github.com/VisionSystemsInc/docker_recipes.git
Note
This is essentially a bash port of the function relative_url() (called from resolve_relative_url(), aka git submodule--helper resolve-relative-url
, which itself is called from cmd_sync(), aka git submodule sync
. git submodule--helper resolve-relative-url
, which is available in git v2.9 and after, does not allow us to specify (directly) the remote URL from which to resolve a relative URL: it resolves relative URLs based on the remote URL, git config remote.${remote_name}.url
, where remote_name is the default remote of the current branch, if set; otherwise origin.
- git_submodule_sync_recursive
git submodule sync --recursive
but using a specific remote (just_upstream
by default)
See also
- git_submodule_sync
git submodule sync
but using a specific remote (just_upstream
by default)
Like git submodule sync
, synchronize the configured URL of each submodule in a repository (recursively) to the value specified in .gitmodules; however, instead of overwriting the default remote (origin), update the remote specified by JUST_GIT_UPSTREAM (just_upstream
by default).
- Arguments:
[
$1
] - The project-repository’s remote. Default: origin [$2...
] - The submodule path to sync (or multiple submodules). Default: all submodules of the current repository (non-recursively)- Parameters:
[
JUST_GIT_UPSTREAM
] - The submodules’ remote to sync. When updating the URL in the submodules’ configuration, use this remote. Default:just_upstream
Note
Because this function uses git submodule foreach
, it skips submodules that have been init’d but not updated.
Note
Creates the just_upstream remote just like, and using the same procedure as, just_git_functions.bsh safe_git_submodule_update
; however, importantly, it does not try to update the submodule to the expected SHA.
See also
- git_submodule_is_published_recursive
Ensure all submodules have pushed the necessary changes to their public repo
Check each submodule (recursively) to see if the SHA tracked by its parent repository has been pushed to the URL tracked by the parent repository (per its .gitmodules file). Must be run from the root of a repository.
- Arguments:
[
$1
] - The project-repository’s remote. Default: origin- Parameters:
[
JUST_GIT_UPSTREAM
] - The submodule’s remote to sync. When fetching, use this remote’s URL. Default:just_upstream
- Output:
Return 0 if, for each submodule (recursively), the changes tracked by the parent repository have been made public; otherwise, return 1
Note
Creates a JUST_GIT_UPSTREAM remote. See git_submodule_sync
.
Note
Cf. git push --recurse-submodules=check
(available since git v1.8.0) will check for unpushed commits in a submodule for its current committed state in the parent project. However, this only seems to work if it is used with a set of outgoing commits that contains a change to a submodule. And, despite its name, it does not seem to recurse into submodules.