Git submodules checkout to branch if not exist then switch to another - bash

I would like to have something like:
git submodule foreach --recursive git checkout some_feature_branch || git checkout develop
so if some_feature_branch exists then I want to checkout it otherwise develop. Is it possible to implement that with built-in git or bash commands?

Remember that git submodule foreach passes its argument to a shell, so all you have to do is provide the right shell commands. But if you type a command into a shell (command line interpreter), the shell decides what you meant. The command:
foo some bars || raz a matazz
means, to the shell:
try to foo some bars
if that succeeds, stop; otherwise, try to raz a matazz
That's not what you want here. You want git submodule itself to try to git checkout and if that fails, you want git submodule—not your main shell—to go on to git checkout. That is, you don't want:
for all submodules, try a git checkout
if that succeeds, stop; otherwise try one git checkout
You want:
for all submodules:
try a git checkout
if that succeeds, go on to the next submodule; if it fails, try another git checkout, and then go on to the next submodule
So that's:
git submodule foreach "git checkout a || git checkout b"
The double quotes here (though single quotes would also work) protect the || so that the top level shell doesn't try to interpret this as:
(git submodule foreach git checkout a) || (git checkout b)
Instead, the top level shell passes the entire "git checkout a || git checkout b" part to the git submodule foreach command. That command—the git submodule foreach—then passes the git checkout a || git checkout b on to one command-line-interpreter run for one submodule. Then git submodule foreach goes on to the next submodule.
(Note that this has very little to do with Git itself: it's basic shell programming. The shell is an interpreter that runs shell programs, and you need to learn to write programs for it.)

Related

Git alias for checkout branch, pull and checkout back

We are using the Feature-Branch-Workflow, which means others merge theire changes to the dev-branch that I want to merge into my feature branch. As it happens a lot I would like to have a simple git alias which does:
Checkout the dev branch
Pull
Checkout the previous branch
I want to do the merge myself, as sometimes changes block the checkout or pulls can fail.
My current state is:
[alias]
pull-and-back = !git checkout $1 && git pull && git checkout #{-1}
which sadly gives the error error: pathspec 'dev' did not match any file(s) known to git.
What is going wrong? I assume as the exclamation mark causes the command to be interpreted as bash code the last part #{-1} is not evaluated by git but by bash instead.
You'd have to use an ad hoc bash function to pass your parameter :
git config alias.pab '!f() { git checkout $1 && git pull && git checkout -; }; f'
As a note, git checkout - is a handy shortcut for git checkout #{-1}, but both work.

How I cherry pick previous branch's latest commit by one command?

For example, I have branch "feature-A".
Then I execute one commond that can help me checkout to "feature-B" and cherry pick "feature-A"'s lastest's commit.
Does git have such a magical command? Or does anyone have a ready-made script? If so, this could save me a lot of time.
Thanks!
You can concatenate 2 git commands: first to move to your desired branch (in this case feature-B) and then cherry pick the last commit on the top of your other branch (in this case feature-A)
You can do it by running git checkout feature-B && git cherry-pick feature-A
Remember you can specify -n after cherry-pick if you don't want to commit (so you can check it before committing), or on the other hand you can concatenate && git push in case you don't need to check but you want directly to push everything in the same command after the cherry pick.
Below bash/zsh script might help if you want to cherry-pick only the latest commit from feature-A
git checkout feature-A
commitId=$(git log -n 1 --pretty=format:"%h")
git checkout feature-B
git cherry-pick $commitId
git diff --stat --cached origin/feature-B
Then to push the changes, run below command
git push origin feature-B

How to use a line of hyphen to separate git command results within git alias in git-bash

I've already created a alias called info to display status, branch and log in git-bash. However, all the information was bunched up and somewhat annoying to read, so i wanted to make it easier on myself when reading it by adding a line of hyphens with new line above and below it. After trying many times, I can't get it to work. Therefore i'm seeking help here.
Here's what I tried before, trying to get one to work before copying it in between git branch and git log.
$ git config --global alias.info '!git status && echo && !printf -- '-%.0s' {1..80}; echo "" && echo && git branch && git log'
Below is what the result should look like.
git status result
-----------------------
git branch result
-----------------------
git log result
If the ! syntax doe not give the expected result, try and embed your commands in a shell function within your Git alias:
alias.info !f() { echo begin arg=$1/$2/end; }; f
Or even in a separate script:
git config --global alias.info '!sh info.sh'
The point is: if you can make it work in a regular shell script, you will be able to call it from an alias.
Or you can even name your script git-info (executable, no extension), and simply type:
git info
No alias needed there: any git-xxx script can be called as git xxx (if git-xxx is in your PATH)

Always prompt for a stash message in git

I tend to stash changes without remembering why I stash them.
I do make it a point to git stash push -m most of the time, but if there's a fire drill or something else that knocks me out of flow, I may forget and lose time trying to recover.
Is there a way to imitate the behavior of git commit (minus the -m) for git stash where vim pops up and abandons the operation if the message is empty?
AFAIK there's no config option for this. You'll have to write an alias in your .gitconfig and train yourself to use it.
For example, I have two stash aliases git pop and git save. (You can see I didn't get the memo about git stash save being deprecated). These are both for convenience, and to change the default behavior to something I find more useful.
save = stash save -k -u
pop = stash pop
Unfortunately git stash push -m doesn't bring up an editor, if you need to write more than a few words to describe what you were doing consider a branch instead. We can fix this by writing a little shell function and passing the argument to -m using "$#" to ensure messages with spaces are a single argument.
savem = "!f() { git save -m \"$#\"; }; f"
Now you can write git savem 'remember to remember what this was'.
$ git savem 'remember to remember what this was'
Saved working directory and index state On issue/45: remember to remember what this was
And if you forget, you'll get the normal git-stash usage message. You can snazz up the alias to provide a custom usage message if you like.
$ git savem
usage: git stash list [<options>]
or: git stash show [<stash>]
...
To me it makes sense to consider using a branch for this. It seems like you want to keep the changes. Branches can be named so it’s easier to recall what was being worked on. These can be local or pushed to remote in case it wasn’t a drill.
$ git branch topic/wip
If you want continue work on master yo can do a
$ git checkout master
Not pretty but could be achieved using bash + vipe in moreutils
msg="$(< /dev/null vipe)";
[[ -z "$msg" ]] || git stash -m "$msg"

Git checkout by date gives error on Windows

I want to checkout from git and using commands from this SO-link. I am not sure what I am doing wrong here.
I have tried following commands.
git checkout `git rev-list -n 1 --before="2015-3-3 13:37:00" master`
git checkout `git rev-list 1 --before="2015-3-3 13:37:00" master`
git checkout `git rev-list -1 --before="2015-3-3 13:37:00" master`
and get the following error.
C:\Users\junaid\Documents\GitHub\bucardo [master]> git checkout `git rev-list -n 1 --before="2015-3-3 13:37:00" master`
error: unknown switch `n'
usage: git checkout [options] <branch>
or: git checkout [options] [<branch>] -- <file>...
-q, --quiet suppress progress reporting
-b <branch> create and checkout a new branch
-B <branch> create/reset and checkout a branch
-l create reflog for new branch
--detach detach the HEAD at named commit
-t, --track set upstream info for new branch
--orphan <new branch>
new unparented branch
-2, --ours checkout our version for unmerged files
-3, --theirs checkout their version for unmerged files
-f, --force force checkout (throw away local modifications)
-m, --merge perform a 3-way merge with the new branch
--overwrite-ignore update ignored files (default)
--conflict <style> conflict style (merge or diff3)
-p, --patch select hunks interactively
--ignore-skip-worktree-bits
do not limit pathspecs to sparse entries only
But following command works but I think, it can go back to 90 days only.
C:\Users\junaid\Documents\GitHub\bucardo [master]> git checkout 'master#{2015-3-27 18:30:00}'
warning: Log for 'master' only goes back to Thu, 17 Mar 2015 18:08:03 -0500.
Note: checking out 'master#{2015-07-27 18:30:00}'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:
git checkout -b new_branch_name
HEAD is now at cb4f95a... Start the cleanup of delete_rows()
C:\Users\junaid\Documents\GitHub\bucardo [(cb4f95a...)]>
In Bash (and many other Unixy shells) backticks are used for command substitution, e.g. see this description from The Linux Documentation Project:
Command substitution allows the output of a command to replace the command itself. Command substitution occurs when a command is enclosed like this:
$(command)
or like this using backticks:
`command`
Bash performs the expansion by executing COMMAND and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting.
franky ~> echo `date`
Thu Feb 6 10:06:20 CET 2003
I don't think that cmd.exe supports real command substitution at all. It certainly doesn't treat backticks this way.
There are some workarounds that you can try, e.g. using for /f or temporary files, but these are awkward to use.
Depending on how you installed Git you might have access to a Bash shell on Windows that should work the way you want.
If you have access to PowerShell it looks like the $(...) syntax should work, which is also supported on Bash. posh-git has a good reputation as an environment for Git on PowerShell, though I've never used it personally.

Resources